From 592d48aab727142cb2521468e5ed9d85f2408783 Mon Sep 17 00:00:00 2001 From: Ken Steele Date: Fri, 27 Sep 2013 16:27:13 -0400 Subject: [PATCH] Use Spin locks on Tile On Tile, replace pthread_mutex_locks with queued spin locks (ticket locks) for dataplane processing code. This is safe when running on dataplane cores with one thread per core. The condition variables are no-ops when the thread is spinning anyway. For control plane threads, unix-manager, stats-logs, thread startup, use pthread_mutex_locks. For these locks replaced SCMutex with SCCtrlMutex and SCCond with SCCtrlCond. --- src/counters.c | 14 +++--- src/flow-manager.c | 13 +++--- src/flow-manager.h | 8 ++-- src/threads.h | 108 +++++++++++++++++++++++++++++++++++++++++++-- src/threadvars.h | 4 +- src/tm-threads.c | 14 +++--- src/tmqh-flow.c | 4 +- src/tmqh-simple.c | 6 +-- src/unix-manager.c | 7 +-- src/unix-manager.h | 4 +- 10 files changed, 142 insertions(+), 40 deletions(-) diff --git a/src/counters.c b/src/counters.c index f574f742a9..711e2710c8 100644 --- a/src/counters.c +++ b/src/counters.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -474,9 +474,9 @@ static void *SCPerfMgmtThread(void *arg) cond_time.tv_sec = time(NULL) + sc_counter_tts; cond_time.tv_nsec = 0; - SCMutexLock(tv_local->m); - SCCondTimedwait(tv_local->cond, tv_local->m, &cond_time); - SCMutexUnlock(tv_local->m); + SCCtrlMutexLock(tv_local->ctrl_mutex); + SCCtrlCondTimedwait(tv_local->ctrl_cond, tv_local->ctrl_mutex, &cond_time); + SCCtrlMutexUnlock(tv_local->ctrl_mutex); SCPerfOutputCounters(); @@ -542,9 +542,9 @@ static void *SCPerfWakeupThread(void *arg) cond_time.tv_sec = time(NULL) + SC_PERF_WUT_TTS; cond_time.tv_nsec = 0; - SCMutexLock(tv_local->m); - SCCondTimedwait(tv_local->cond, tv_local->m, &cond_time); - SCMutexUnlock(tv_local->m); + SCCtrlMutexLock(tv_local->ctrl_mutex); + SCCtrlCondTimedwait(tv_local->ctrl_cond, tv_local->ctrl_mutex, &cond_time); + SCCtrlMutexUnlock(tv_local->ctrl_mutex); tv = tv_root[TVT_PPT]; while (tv != NULL) { diff --git a/src/flow-manager.c b/src/flow-manager.c index 1f2828f12c..b3a49cd0ce 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -94,7 +94,7 @@ void FlowKillFlowManagerThread(void) ThreadVars *tv = NULL; int cnt = 0; - SCCondSignal(&flow_manager_cond); + SCCtrlCondSignal(&flow_manager_ctrl_cond); SCMutexLock(&tv_root_lock); @@ -538,9 +538,10 @@ void *FlowManagerThread(void *td) cond_time.tv_sec = time(NULL) + flow_update_delay_sec; cond_time.tv_nsec = flow_update_delay_nsec; - SCMutexLock(&flow_manager_mutex); - SCCondTimedwait(&flow_manager_cond, &flow_manager_mutex, &cond_time); - SCMutexUnlock(&flow_manager_mutex); + SCCtrlMutexLock(&flow_manager_ctrl_mutex); + SCCtrlCondTimedwait(&flow_manager_ctrl_cond, &flow_manager_ctrl_mutex, + &cond_time); + SCCtrlMutexUnlock(&flow_manager_ctrl_mutex); SCLogDebug("woke up... %s", SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY ? "emergency":""); @@ -566,8 +567,8 @@ void FlowManagerThreadSpawn() { ThreadVars *tv_flowmgr = NULL; - SCCondInit(&flow_manager_cond, NULL); - SCMutexInit(&flow_manager_mutex, NULL); + SCCtrlCondInit(&flow_manager_ctrl_cond, NULL); + SCCtrlMutexInit(&flow_manager_ctrl_mutex, NULL); tv_flowmgr = TmThreadCreateMgmtThread("FlowManagerThread", FlowManagerThread, 0); diff --git a/src/flow-manager.h b/src/flow-manager.h index 6bb64b8771..090e74fbc3 100644 --- a/src/flow-manager.h +++ b/src/flow-manager.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -25,9 +25,9 @@ #define __FLOW_MANAGER_H__ /** flow manager scheduling condition */ -SCCondT flow_manager_cond; -SCMutex flow_manager_mutex; -#define FlowWakeupFlowManagerThread() SCCondSignal(&flow_manager_cond) +SCCtrlCondT flow_manager_ctrl_cond; +SCCtrlMutex flow_manager_ctrl_mutex; +#define FlowWakeupFlowManagerThread() SCCtrlCondSignal(&flow_manager_ctrl_cond) void FlowManagerThreadSpawn(void); void FlowKillFlowManagerThread(void); diff --git a/src/threads.h b/src/threads.h index b07457dd87..68855e17b3 100644 --- a/src/threads.h +++ b/src/threads.h @@ -27,6 +27,11 @@ #ifndef __THREADS_H__ #define __THREADS_H__ +#ifdef __tile__ +#include +#include +#endif + #if HAVE_CONFIG_H #include #endif @@ -101,14 +106,34 @@ enum { //#define DBG_THREADS /** Suricata Mutex */ +#ifdef __tile__ +#define SCMutex tmc_spin_queued_mutex_t +#define SCMutexAttr +#define SCMutexDestroy(x) ({ (void)(x); 0; }) +#define SCMUTEX_INITIALIZER TMC_SPIN_QUEUED_MUTEX_INIT +#else #define SCMutex pthread_mutex_t #define SCMutexAttr pthread_mutexattr_t #define SCMutexDestroy pthread_mutex_destroy #define SCMUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +#endif + +/* NOTE: On Tilera datapath threads use the tmc library for mutexes + * while the control threads use pthread mutexes. So the pthread + * mutex types are split out so they their use can be differentiated. + */ +#define SCCtrlMutex pthread_mutex_t +#define SCCtrlMutexAttr pthread_mutexattr_t +#define SCCtrlMutexDestroy pthread_mutex_destroy /** Suricata RWLocks */ +#ifdef __tile__ +#define SCRWLock tmc_spin_rwlock_t +#define SCRWLockDestroy(x) ({ (void)(x); 0; }) +#else #define SCRWLock pthread_rwlock_t #define SCRWLockDestroy pthread_rwlock_destroy +#endif /** Get the Current Thread Id */ #ifdef OS_FREEBSD @@ -291,20 +316,60 @@ extern __thread uint64_t mutex_lock_cnt; #define SCMutexLock(mut) SCMutexLock_profile(mut) #define SCMutexTrylock(mut) pthread_mutex_trylock(mut) -#else +#else /* Not Debug and Not Profile */ +#ifdef __tile__ +#define SCMutexInit(mut, mutattr) ({ \ + int ret = 0; \ + tmc_spin_queued_mutex_init(mut); \ + ret; \ +}) +#define SCMutexLock(mut) ({ \ + int ret = 0; \ + tmc_spin_queued_mutex_lock(mut); \ + ret; \ +}) +#define SCMutexTrylock(mut) ({ \ + int ret = (tmc_spin_queued_mutex_trylock(mut) == 0) ? 0 : EBUSY; \ + ret; \ +}) +#define SCMutexUnlock(mut) ({ \ + int ret = 0; \ + tmc_spin_queued_mutex_unlock(mut); \ + ret; \ +}) +#else /* !__tile__ and ! DEBUG*/ #define SCMutexInit(mut, mutattr ) pthread_mutex_init(mut, mutattr) #define SCMutexLock(mut) pthread_mutex_lock(mut) #define SCMutexTrylock(mut) pthread_mutex_trylock(mut) #define SCMutexUnlock(mut) pthread_mutex_unlock(mut) -#endif +#endif /* __tile__ */ +/* Control threads locks. Not Debug. */ +#define SCCtrlMutexInit(mut, mutattr ) pthread_mutex_init(mut, mutattr) +#define SCCtrlMutexLock(mut) pthread_mutex_lock(mut) +#define SCCtrlMutexTrylock(mut) pthread_mutex_trylock(mut) +#define SCCtrlMutexUnlock(mut) pthread_mutex_unlock(mut) +#endif /* DBG_THREADS */ /** Conditions/Signals */ -/* Here we don't need to do nothing atm */ +/* Here we don't need to do anything at the moment */ +#ifdef __tile__ +/* Ignore signals when using spin locks */ +#define SCCondT uint8_t +#define SCCondInit(x,y) ({ 0; }) +#define SCCondSignal(x) +#define SCCondDestroy(x) +#else /* !__tile__ */ #define SCCondT pthread_cond_t #define SCCondInit pthread_cond_init #define SCCondSignal pthread_cond_signal -#define SCCondTimedwait pthread_cond_timedwait #define SCCondDestroy pthread_cond_destroy +#endif /* __tile__ */ + +#define SCCtrlCondT pthread_cond_t +#define SCCtrlCondInit pthread_cond_init +#define SCCtrlCondSignal pthread_cond_signal +#define SCCtrlCondTimedwait pthread_cond_timedwait +#define SCCtrlCondDestroy pthread_cond_destroy #ifdef DBG_THREAD #define SCCondWait_dbg(cond, mut) ({ \ @@ -319,10 +384,27 @@ extern __thread uint64_t mutex_lock_cnt; }) #define SCCondWait SCondWait_dbg #else +#ifdef __tile__ +static inline void cycle_sleep(int cycles) +{ + uint64_t end = get_cycle_count() + cycles; + while (get_cycle_count() < end) + ; +} +#define SCCondWait(x,y) cycle_sleep(300) +#else #define SCCondWait(cond, mut) pthread_cond_wait(cond, mut) +#endif /* __tile__ */ #endif /** Spinlocks */ +#if 0 +#ifdef __tile__ +#define SCSpinlock tmc_spin_queued_mutex_t +#else +#define SCSpinlock pthread_spinlock_t +#endif +#endif /** If posix spin not supported, use mutex */ #if ((_POSIX_SPIN_LOCKS - 200112L) < 0L) || defined HELGRIND @@ -472,12 +554,21 @@ extern __thread uint64_t spin_lock_cnt; #else /* if no dbg threads defined... */ +#ifdef __tile__ +#define SCSpinlock tmc_spin_queued_mutex_t +#define SCSpinLock(spin) ({ tmc_spin_queued_mutex_lock(spin); 0; }) +#define SCSpinTrylock(spin) (tmc_spin_queued_mutex_trylock(spin) ? EBUSY : 0) +#define SCSpinUnlock(spin) ({ tmc_spin_queued_mutex_unlock(spin); 0; }) +#define SCSpinInit(spin, spin_attr) ({ tmc_spin_queued_mutex_init(spin); 0; }) +#define SCSpinDestroy(spin) ({ (void)(spin); 0; }) +#else #define SCSpinlock pthread_spinlock_t #define SCSpinLock(spin) pthread_spin_lock(spin) #define SCSpinTrylock(spin) pthread_spin_trylock(spin) #define SCSpinUnlock(spin) pthread_spin_unlock(spin) #define SCSpinInit(spin, spin_attr) pthread_spin_init(spin, spin_attr) #define SCSpinDestroy(spin) pthread_spin_destroy(spin) +#endif /* __tile__ */ #endif /* DBG_THREADS */ @@ -719,6 +810,14 @@ extern __thread uint64_t rwr_lock_cnt; #define SCRWLockTryWRLock(rwl) pthread_rwlock_trywrlock(rwl) #define SCRWLockTryRDLock(rwl) pthread_rwlock_tryrdlock(rwl) #else +#ifdef __tile__ +#define SCRWLockInit(rwl, rwlattr ) ({ tmc_spin_rwlock_init(rwl); 0; }) +#define SCRWLockWRLock(rwl) ({ tmc_spin_rwlock_wrlock(rwl); 0; }) +#define SCRWLockRDLock(rwl) ({ tmc_spin_rwlock_rdlock(rwl); 0; }) +#define SCRWLockTryWRLock(rwl) (tmc_spin_rwlock_trywrlock(rwl) ? EBUSY : 0) +#define SCRWLockTryRDLock(rwl) (tmc_spin_rwlock_tryrdlock(rwl) ? EBUSY : 0) +#define SCRWLockUnlock(rwl) ({ tmc_spin_rwlock_unlock(rwl); 0; }) +#else #define SCRWLockInit(rwl, rwlattr ) pthread_rwlock_init(rwl, rwlattr) #define SCRWLockWRLock(rwl) pthread_rwlock_wrlock(rwl) #define SCRWLockRDLock(rwl) pthread_rwlock_rdlock(rwl) @@ -726,6 +825,7 @@ extern __thread uint64_t rwr_lock_cnt; #define SCRWLockTryRDLock(rwl) pthread_rwlock_tryrdlock(rwl) #define SCRWLockUnlock(rwl) pthread_rwlock_unlock(rwl) #endif +#endif /** End of RWLock functions */ diff --git a/src/threadvars.h b/src/threadvars.h index 58581a0f79..6502072b90 100644 --- a/src/threadvars.h +++ b/src/threadvars.h @@ -99,8 +99,8 @@ typedef struct ThreadVars_ { SCPerfContext sc_perf_pctx; SCPerfCounterArray *sc_perf_pca; - SCMutex *m; - SCCondT *cond; + SCCtrlMutex *ctrl_mutex; + SCCtrlCondT *ctrl_cond; uint8_t cap_flags; /**< Flags to indicate the capabilities of all the TmModules resgitered under this thread */ diff --git a/src/tm-threads.c b/src/tm-threads.c index 0bc8fe4f52..e15e218597 100644 --- a/src/tm-threads.c +++ b/src/tm-threads.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -1678,8 +1678,8 @@ void TmThreadKillThread(ThreadVars *tv) SCLogDebug("signalled tv->inq->id %" PRIu32 "", tv->inq->id); } - if (tv->cond != NULL ) { - pthread_cond_broadcast(tv->cond); + if (tv->ctrl_cond != NULL ) { + pthread_cond_broadcast(tv->ctrl_cond); } usleep(100); @@ -1952,24 +1952,24 @@ void TmThreadSetAOF(ThreadVars *tv, uint8_t aof) */ void TmThreadInitMC(ThreadVars *tv) { - if ( (tv->m = SCMalloc(sizeof(SCMutex))) == NULL) { + if ( (tv->ctrl_mutex = SCMalloc(sizeof(*tv->ctrl_mutex))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in TmThreadInitMC. " "Exiting..."); exit(EXIT_FAILURE); } - if (SCMutexInit(tv->m, NULL) != 0) { + if (SCCtrlMutexInit(tv->ctrl_mutex, NULL) != 0) { printf("Error initializing the tv->m mutex\n"); exit(0); } - if ( (tv->cond = SCMalloc(sizeof(SCCondT))) == NULL) { + if ( (tv->ctrl_cond = SCMalloc(sizeof(*tv->ctrl_cond))) == NULL) { SCLogError(SC_ERR_FATAL, "Fatal error encountered in TmThreadInitMC. " "Exiting..."); exit(0); } - if (SCCondInit(tv->cond, NULL) != 0) { + if (SCCtrlCondInit(tv->ctrl_cond, NULL) != 0) { SCLogError(SC_ERR_FATAL, "Error initializing the tv->cond condition " "variable"); exit(0); diff --git a/src/tmqh-flow.c b/src/tmqh-flow.c index 207ddc71ab..d25fab619e 100644 --- a/src/tmqh-flow.c +++ b/src/tmqh-flow.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -88,7 +88,7 @@ Packet *TmqhInputFlow(ThreadVars *tv) SCPerfSyncCountersIfSignalled(tv, 0); SCMutexLock(&q->mutex_q); - if (q->len == 0) { + while (q->len == 0) { /* if we have no packets in queue, wait... */ SCCondWait(&q->cond_q, &q->mutex_q); } diff --git a/src/tmqh-simple.c b/src/tmqh-simple.c index 3a1feafbaa..cc5b69c068 100644 --- a/src/tmqh-simple.c +++ b/src/tmqh-simple.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -50,7 +50,7 @@ Packet *TmqhInputSimple(ThreadVars *t) SCMutexLock(&q->mutex_q); - if (q->len == 0) { + while (q->len == 0) { /* if we have no packets in queue, wait... */ SCCondWait(&q->cond_q, &q->mutex_q); } @@ -111,7 +111,7 @@ void TmqhOutputSimple(ThreadVars *t, Packet *p) SCDQGenericQData *TmqhInputSimpleOnQ(SCDQDataQueue *q) { SCMutexLock(&q->mutex_q); - if (q->len == 0) { + while (q->len == 0) { /* if we have no packets in queue, wait... */ SCCondWait(&q->cond_q, &q->mutex_q); } diff --git a/src/unix-manager.c b/src/unix-manager.c index 6bf01ef878..45540e1069 100644 --- a/src/unix-manager.c +++ b/src/unix-manager.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Open Information Security Foundation +/* Copyright (C) 2013 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -549,7 +549,7 @@ void UnixKillUnixManagerThread(void) ThreadVars *tv = NULL; int cnt = 0; - SCCondSignal(&unix_manager_cond); + SCCtrlCondSignal(&unix_manager_ctrl_cond); SCMutexLock(&tv_root_lock); @@ -899,7 +899,8 @@ void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode) { ThreadVars *tv_unixmgr = NULL; - SCCondInit(&unix_manager_cond, NULL); + SCCtrlCondInit(&unix_manager_ctrl_cond, NULL); + SCCtrlMutexInit(&unix_manager_ctrl_mutex, NULL); tv_unixmgr = TmThreadCreateCmdThread("UnixManagerThread", UnixManagerThread, 0); diff --git a/src/unix-manager.h b/src/unix-manager.h index 97145a59bf..937737ef11 100644 --- a/src/unix-manager.h +++ b/src/unix-manager.h @@ -30,8 +30,8 @@ #define UNIX_CMD_TAKE_ARGS 1 -SCCondT unix_manager_cond; -SCMutex unix_manager_mutex; +SCCtrlCondT unix_manager_ctrl_cond; +SCCtrlMutex unix_manager_ctrl_mutex; void UnixManagerThreadSpawn(DetectEngineCtx *de_ctx, int mode); void UnixSocketKillSocketThread(void);