Adding atomic bitwise operations api and rwlocks support

remotes/origin/master-1.1.x
Pablo Rincon 15 years ago committed by Victor Julien
parent b8a709cbe7
commit 14a12f5fb7

@ -49,7 +49,7 @@ int ThreadMacrosTest01Mutex(void) {
}
/**
* \brief Test Spin Macros
* \brief Test Spinlock Macros
*
* Valgrind's DRD tool (valgrind-3.5.0-Debian) reports:
*
@ -59,7 +59,7 @@ int ThreadMacrosTest01Mutex(void) {
* ==31156== by 0x532E8A: UtRunTests (util-unittest.c:182)
* ==31156== by 0x4065C3: main (suricata.c:789)
*
* To me this is a false possitve, as the whole point of "trylock" is to see
* To me this is a false positve, as the whole point of "trylock" is to see
* if a spinlock is actually locked.
*
*/
@ -75,6 +75,51 @@ int ThreadMacrosTest02Spinlocks(void) {
return (r == 0)? 1 : 0;
}
/**
* \brief Test RWLock macros
*/
int ThreadMacrosTest03RWLocks(void) {
SCRWLock rwl_write;
int r = 0;
r |= SCRWLockInit(&rwl_write, NULL);
r |= SCRWLockWRLock(&rwl_write);
r |= (SCRWLockTryWRLock(&rwl_write) == EBUSY)? 0 : 1;
r |= SCRWLockUnlock(&rwl_write);
r |= SCRWLockDestroy(&rwl_write);
return (r == 0)? 1 : 0;
}
/**
* \brief Test RWLock macros
*/
int ThreadMacrosTest04RWLocks(void) {
SCRWLock rwl_read;
int r = 0;
r |= SCRWLockInit(&rwl_read, NULL);
r |= SCRWLockRDLock(&rwl_read);
r |= (SCRWLockTryWRLock(&rwl_read) == EBUSY)? 0 : 1;
r |= SCRWLockUnlock(&rwl_read);
r |= SCRWLockDestroy(&rwl_read);
return (r == 0)? 1 : 0;
}
/**
* \brief Test RWLock macros
*/
int ThreadMacrosTest05RWLocks(void) {
SCRWLock rwl_read;
int r = 0;
r |= SCRWLockInit(&rwl_read, NULL);
r |= SCRWLockWRLock(&rwl_read);
r |= (SCRWLockTryRDLock(&rwl_read) == EBUSY)? 0 : 1;
r |= SCRWLockUnlock(&rwl_read);
r |= SCRWLockDestroy(&rwl_read);
return (r == 0)? 1 : 0;
}
#endif /* UNIT TESTS */
/**
@ -84,6 +129,8 @@ void ThreadMacrosRegisterTests(void)
{
#ifdef UNITTESTS /* UNIT TESTS */
UtRegisterTest("ThreadMacrosTest01Mutex", ThreadMacrosTest01Mutex, 1);
UtRegisterTest("ThreadMacrossTest02Spinlocks", ThreadMacrosTest02Spinlocks, 1);
UtRegisterTest("ThreadMacrosTest02Spinlocks", ThreadMacrosTest02Spinlocks, 1);
UtRegisterTest("ThreadMacrosTest03RWLocks", ThreadMacrosTest03RWLocks, 1);
UtRegisterTest("ThreadMacrosTest04RWLocks", ThreadMacrosTest04RWLocks, 1);
#endif /* UNIT TESTS */
}

@ -79,6 +79,10 @@
#define SCMutexAttr pthread_mutexattr_t
#define SCMutexDestroy pthread_mutex_destroy
/** Suricata RWLocks */
#define SCRWLock pthread_rwlock_t
#define SCRWLockDestroy pthread_rwlock_destroy
/** Get the Current Thread Id */
#ifdef OS_FREEBSD
#define SCGetThreadIdLong(...) ({ \
@ -374,6 +378,146 @@
})
#endif
/** RWLock Functions */
#ifdef DBG_THREADS
/** When dbg threads is defined, if a rwlock fail to lock, it's
* initialized, logged, and does a second try; This is to prevent the system to freeze;
* If you see a rwlock, spinlock or condiion not initialized, report it please!
*/
#define SCRWLockRDLock_dbg(rwl) ({ \
printf("%16s(%s:%d): (thread:%"PRIuMAX") locking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \
int retl = pthread_rwlock_rdlock(rwl); \
printf("%16s(%s:%d): (thread:%"PRIuMAX") locked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retl); \
if (retl != 0) { \
switch (retl) { \
case EINVAL: \
printf("The value specified by attr is invalid\n"); \
retl = pthread_rwlock_init(rwl, NULL); \
if (retl != 0) \
exit(EXIT_FAILURE); \
retl = pthread_rwlock_rdlock(rwl); \
break; \
case EDEADLK: \
printf("A deadlock would occur if the thread blocked waiting for rwlock\n"); \
break; \
} \
} \
retl; \
})
#define SCRWLockWRLock_dbg(rwl) ({ \
printf("%16s(%s:%d): (thread:%"PRIuMAX") locking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \
int retl = pthread_rwlock_wrlock(rwl); \
printf("%16s(%s:%d): (thread:%"PRIuMAX") locked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retl); \
if (retl != 0) { \
switch (retl) { \
case EINVAL: \
printf("The value specified by attr is invalid\n"); \
retl = pthread_rwlock_init(rwl, NULL); \
if (retl != 0) \
exit(EXIT_FAILURE); \
retl = pthread_rwlock_wrlock(rwl); \
break; \
case EDEADLK: \
printf("A deadlock would occur if the thread blocked waiting for rwlock\n"); \
break; \
} \
} \
retl; \
})
#define SCRWLockTryWRLock_dbg(rwl) ({ \
printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \
int rett = pthread_rwlock_trywrlock(rwl); \
printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, rett); \
if (rett != 0) { \
switch (rett) { \
case EINVAL: \
printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \
break; \
case EBUSY: \
printf("RWLock is already locked\n"); \
break; \
} \
} \
rett; \
})
#define SCRWLockTryRDLock_dbg(rwl) ({ \
printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \
int rett = pthread_rwlock_tryrdlock(rwl); \
printf("%16s(%s:%d): (thread:%"PRIuMAX") trylocked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, rett); \
if (rett != 0) { \
switch (rett) { \
case EINVAL: \
printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \
break; \
case EBUSY: \
printf("RWLock is already locked\n"); \
break; \
} \
} \
rett; \
})
#define SCRWLockInit_dbg(rwl, rwlattr) ({ \
int ret; \
ret = pthread_rwlock_init(rwl, rwlattr); \
if (ret != 0) { \
switch (ret) { \
case EINVAL: \
printf("The value specified by attr is invalid\n"); \
printf("%16s(%s:%d): (thread:%"PRIuMAX") rwlock %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, ret); \
break; \
case EAGAIN: \
printf("The system temporarily lacks the resources to create another rwlock\n"); \
printf("%16s(%s:%d): (thread:%"PRIuMAX") rwlock %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, ret); \
break; \
case ENOMEM: \
printf("The process cannot allocate enough memory to create another rwlock\n"); \
printf("%16s(%s:%d): (thread:%"PRIuMAX") rwlock %p initialization returned %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, ret); \
break; \
} \
} \
ret; \
})
#define SCRWLockUnlock_dbg(rwl) ({ \
printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocking rwlock %p\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl); \
int retu = pthread_rwlock_unlock(rwl); \
printf("%16s(%s:%d): (thread:%"PRIuMAX") unlocked rwlock %p ret %" PRId32 "\n", __FUNCTION__, __FILE__, __LINE__, (uintmax_t)pthread_self(), rwl, retu); \
if (retu != 0) { \
switch (retu) { \
case EINVAL: \
printf("%16s(%s:%d): The value specified by attr is invalid\n", __FUNCTION__, __FILE__, __LINE__); \
break; \
case EPERM: \
printf("The current thread does not hold a lock on rwlock\n"); \
break; \
} \
} \
retu; \
})
#define SCRWLockInit(rwl, rwlattrs) SCRWLockInit_dbg(rwl, rwlattrs)
#define SCRWLockRDLock(rwl) SCRWLockRDLock_dbg(rwl)
#define SCRWLockWRLock(rwl) SCRWLockWRLock_dbg(rwl)
#define SCRWLockTryWRLock(rwl) SCRWLockTryWRLock_dbg(rwl)
#define SCRWLockTryRDLock(rwl) SCRWLockTryRDLock_dbg(rwl)
#define SCRWLockUnlock(rwl) SCRWLockUnlock_dbg(rwl)
#else
#define SCRWLockInit(rwl, rwlattr ) pthread_rwlock_init(rwl, rwlattr)
#define SCRWLockWRLock(rwl) pthread_rwlock_wrlock(rwl)
#define SCRWLockRDLock(rwl) pthread_rwlock_rdlock(rwl)
#define SCRWLockTryWRLock(rwl) pthread_rwlock_trywrlock(rwl)
#define SCRWLockTryRDLock(rwl) pthread_rwlock_tryrdlock(rwl)
#define SCRWLockUnlock(rwl) pthread_rwlock_unlock(rwl)
#endif
/** End of RWLock functions */
void ThreadMacrosRegisterTests(void);
#endif /* __THREADS_H__ */

@ -19,6 +19,7 @@
* \file
*
* \author Victor Julien <victor@inliniac.net>
* \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
*
* API for atomic operations. Uses atomic instructions (GCC only at this time)
* where available, falls back to (spin)locked* operations otherwise.
@ -121,6 +122,58 @@
SCSpinUnlock(&(name ## _sc_lock__)); \
} while(0)
/**
* \brief Bitwise AND a value from our atomic variable
*
* \param name the atomic variable
* \param val the value to sub from the variable
*/
#define SC_ATOMIC_AND(name, val) \
do { \
SCSpinLock(&(name ## _sc_lock__)); \
(name ## _sc_atomic__) &= (val); \
SCSpinUnlock(&(name ## _sc_lock__)); \
} while(0)
/**
* \brief Bitwise OR a value from our atomic variable
*
* \param name the atomic variable
* \param val the value to sub from the variable
*/
#define SC_ATOMIC_OR(name, val) \
do { \
SCSpinLock(&(name ## _sc_lock__)); \
(name ## _sc_atomic__) |= (val); \
SCSpinUnlock(&(name ## _sc_lock__)); \
} while(0)
/**
* \brief Bitwise NAND a value from our atomic variable
*
* \param name the atomic variable
* \param val the value to sub from the variable
*/
#define SC_ATOMIC_NAND(name, val) \
do { \
SCSpinLock(&(name ## _sc_lock__)); \
(name ## _sc_atomic__) = ~(name ## _sc_atomic__) & (val); \
SCSpinUnlock(&(name ## _sc_lock__)); \
} while(0)
/**
* \brief Bitwise XOR a value from our atomic variable
*
* \param name the atomic variable
* \param val the value to sub from the variable
*/
#define SC_ATOMIC_XOR(name, val) \
do { \
SCSpinLock(&(name ## _sc_lock__)); \
(name ## _sc_atomic__) ^= (val); \
SCSpinUnlock(&(name ## _sc_lock__)); \
} while(0)
/**
* \brief Get the value from the atomic variable.
*
@ -190,6 +243,47 @@
#define SCAtomicFetchAndSub(addr, value) \
__sync_fetch_and_sub((addr), (value))
/**
* \brief wrapper for OS/compiler specific atomic fetch and "AND"
* function.
*
* \param addr Address of the variable to AND to
* \param value Value to add to the variable at addr
*/
#define SCAtomicFetchAndAnd(addr, value) \
__sync_fetch_and_and((addr), (value))
/**
* \brief wrapper for OS/compiler specific atomic fetch and "NAND"
* function.
*
* \param addr Address of the variable to NAND to
* \param value Value to add to the variable at addr
*/
#define SCAtomicFetchAndNand(addr, value) \
__sync_fetch_and_nand((addr), (value))
/**
* \brief wrapper for OS/compiler specific atomic fetch and "XOR"
* function.
*
* \param addr Address of the variable to XOR to
* \param value Value to add to the variable at addr
*/
#define SCAtomicFetchAndXor(addr, value) \
__sync_fetch_and_xor((addr), (value))
/**
* \brief wrapper for OS/compiler specific atomic fetch and or
* function.
*
* \param addr Address of the variable to or to
* \param value Value to add to the variable at addr
*/
#define SCAtomicFetchAndOr(addr, value) \
__sync_fetch_and_or((addr), (value))
/**
* \brief wrapper for declaring atomic variables.
*
@ -264,6 +358,42 @@
#define SC_ATOMIC_SUB(name, val) \
SCAtomicFetchAndSub(&(name ## _sc_atomic__), (val))
/**
* \brief Bitwise OR a value to our atomic variable
*
* \param name the atomic variable
* \param val the value to OR to the variable
*/
#define SC_ATOMIC_OR(name, val) \
SCAtomicFetchAndOr(&(name ## _sc_atomic__), (val))
/**
* \brief Bitwise AND a value to our atomic variable
*
* \param name the atomic variable
* \param val the value to AND to the variable
*/
#define SC_ATOMIC_AND(name, val) \
SCAtomicFetchAndAnd(&(name ## _sc_atomic__), (val))
/**
* \brief Bitwise NAND a value to our atomic variable
*
* \param name the atomic variable
* \param val the value to NAND to the variable
*/
#define SC_ATOMIC_NAND(name, val) \
SCAtomicFetchAndNand(&(name ## _sc_atomic__), (val))
/**
* \brief Bitwise XOR a value to our atomic variable
*
* \param name the atomic variable
* \param val the value to XOR to the variable
*/
#define SC_ATOMIC_XOR(name, val) \
SCAtomicFetchAndXor(&(name ## _sc_atomic__), (val))
/**
* \brief atomic Compare and Switch
*

Loading…
Cancel
Save