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