1 #ifndef THREADS_H_ 2 #define THREADS_H_ 3 4 #include <config.h> 5 6 #include <pthread.h> 7 #include <stdint.h> 8 9 #include <semaphore.h> 10 #if !HAVE_SEM_TIMEDWAIT 11 # include <time.h> 12 int sem_timedwait(sem_t* sem, const struct timespec* abs_timeout); 13 #endif 14 15 int sem_timedwait_rel(sem_t* sem, double rel_timeout); 16 int pthread_cond_timedwait_rel(pthread_cond_t* cond, pthread_mutex_t* mutex, double rel_timeout); 17 18 enum { 19 INVALID_TID = -1, 20 TRX_TID, QRZ_TID, RIGCTL_TID, NORIGCTL_TID, 21 #if USE_XMLRPC 22 XMLRPC_TID, 23 #endif 24 ARQ_TID, ARQSOCKET_TID, 25 FLMAIN_TID, 26 NUM_THREADS, NUM_QRUNNER_THREADS = NUM_THREADS - 1 27 }; 28 29 #ifdef __linux__ 30 void linux_log_tid(void); 31 # define LOG_THREAD_ID() linux_log_tid() 32 #else 33 # define LOG_THREAD_ID() /* nothing */ 34 #endif 35 36 #if USE_TLS 37 # define THREAD_ID_TYPE __thread intptr_t 38 # define CREATE_THREAD_ID() thread_id_ = INVALID_TID 39 # define SET_THREAD_ID(x) do { thread_id_ = (x); LOG_THREAD_ID(); } while (0) 40 # define GET_THREAD_ID() thread_id_ 41 #else 42 # define THREAD_ID_TYPE pthread_key_t 43 # define CREATE_THREAD_ID() pthread_key_create(&thread_id_, NULL) 44 # define SET_THREAD_ID(x) do { pthread_setspecific(thread_id_, (const void *)(x + 1)); LOG_THREAD_ID(); } while (0) 45 # define GET_THREAD_ID() ((intptr_t)pthread_getspecific(thread_id_) - 1) 46 #endif // USE_TLS 47 extern THREAD_ID_TYPE thread_id_; 48 49 50 #ifndef NDEBUG 51 # include "debug.h" 52 bool thread_in_list(int id, const int* list); 53 # define ENSURE_THREAD(...) \ 54 do { \ 55 int id_ = GET_THREAD_ID(); \ 56 int t_[] = { __VA_ARGS__, INVALID_TID }; \ 57 if (!thread_in_list(id_, t_)) \ 58 LOG_ERROR("bad thread context: %d", id_); \ 59 } while (0) 60 # define ENSURE_NOT_THREAD(...) \ 61 do { \ 62 int id_ = GET_THREAD_ID(); \ 63 int t_[] = { __VA_ARGS__, INVALID_TID }; \ 64 if (thread_in_list(id_, t_)) \ 65 LOG_ERROR("bad thread context: %d", id_); \ 66 } while (0) 67 #else 68 # define ENSURE_THREAD(...) ((void)0) 69 # define ENSURE_NOT_THREAD(...) ((void)0) 70 #endif // ! NDEBUG 71 72 73 // On POSIX systems we cancel threads by sending them SIGUSR2, 74 // which will also interrupt blocking calls. On woe32 we use 75 // pthread_cancel and there is no good/sane way to interrupt. 76 #ifndef __WOE32__ 77 # define SET_THREAD_CANCEL() \ 78 do { \ 79 sigset_t usr2; \ 80 sigemptyset(&usr2); \ 81 sigaddset(&usr2, SIGUSR2); \ 82 pthread_sigmask(SIG_UNBLOCK, &usr2, NULL); \ 83 } while (0) 84 # define TEST_THREAD_CANCEL() /* nothing */ 85 # define CANCEL_THREAD(t__) pthread_kill(t__, SIGUSR2) 86 #else 87 // threads have PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DEFERRED when created 88 # define SET_THREAD_CANCEL() /* nothing */ 89 # define TEST_THREAD_CANCEL() pthread_testcancel() 90 # define CANCEL_THREAD(t__) pthread_cancel(t__); 91 #endif 92 93 #include "fl_lock.h" 94 95 /// This ensures that a mutex is always unlocked when leaving a function or block. 96 class guard_lock 97 { 98 public: 99 guard_lock(pthread_mutex_t* m); 100 ~guard_lock(void); 101 private: 102 pthread_mutex_t* mutex; 103 }; 104 105 #endif // !THREADS_H_ 106