thread: Test for pending cancellation requests before poll()ing on OS X
[strongswan.git] / src / libstrongswan / threading / thread.h
1 /*
2 * Copyright (C) 2009 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 /**
17 * @defgroup thread thread
18 * @{ @ingroup threading
19 */
20
21 #ifndef THREADING_THREAD_H_
22 #define THREADING_THREAD_H_
23
24 typedef struct thread_t thread_t;
25
26 #ifdef __APPLE__
27 /* thread_create is a syscall used to create Mach kernel threads and although
28 * there are no errors or warnings during compilation or linkage the dynamic
29 * linker does not use our implementation, therefore we rename it here
30 */
31 #define thread_create(main, arg) strongswan_thread_create(main, arg)
32
33 /* on Mac OS X 10.5 several system calls we use are no cancellation points.
34 * fortunately, select isn't one of them, so we wrap some of the others with
35 * calls to select(2).
36 */
37 #include <sys/socket.h>
38 #include <sys/select.h>
39
40 #define WRAP_WITH_SELECT(func, socket, ...)\
41 fd_set rfds; FD_ZERO(&rfds); FD_SET(socket, &rfds);\
42 if (select(socket + 1, &rfds, NULL, NULL, NULL) <= 0) { return -1; }\
43 return func(socket, __VA_ARGS__)
44
45 static inline int cancellable_accept(int socket, struct sockaddr *address,
46 socklen_t *address_len)
47 {
48 WRAP_WITH_SELECT(accept, socket, address, address_len);
49 }
50 #define accept cancellable_accept
51 static inline int cancellable_recvfrom(int socket, void *buffer, size_t length,
52 int flags, struct sockaddr *address, socklen_t *address_len)
53 {
54 WRAP_WITH_SELECT(recvfrom, socket, buffer, length, flags, address, address_len);
55 }
56 #define recvfrom cancellable_recvfrom
57 #endif /* __APPLE__ */
58
59 /**
60 * Main function of a thread.
61 *
62 * @param arg argument provided to constructor
63 * @return value provided to threads joining the terminating thread
64 */
65 typedef void *(*thread_main_t)(void *arg);
66
67 /**
68 * Cleanup callback function for a thread.
69 *
70 * @param arg argument provided to thread_cleanup_push
71 */
72 typedef void (*thread_cleanup_t)(void *arg);
73
74 /**
75 * Thread wrapper implements simple, portable and advanced thread functions.
76 *
77 * @note All threads other than the main thread need either to be joined or
78 * detached by calling the corresponding method.
79 */
80 struct thread_t {
81
82 /**
83 * Cancel this thread.
84 */
85 void (*cancel)(thread_t *this);
86
87 /**
88 * Send a signal to this thread.
89 *
90 * @param sig the signal to be sent to this thread
91 */
92 void (*kill)(thread_t *this, int sig);
93
94 /**
95 * Detach this thread, this automatically destroys the thread object after
96 * the thread returned from its main function.
97 *
98 * @note Calling detach is like calling destroy on other objects.
99 */
100 void (*detach)(thread_t *this);
101
102 /**
103 * Join this thread, this automatically destroys the thread object
104 * afterwards.
105 *
106 * @note Calling join is like calling destroy on other objects.
107 *
108 * @return the value returned from the thread's main function or
109 * a call to exit.
110 */
111 void *(*join)(thread_t *this);
112 };
113
114 /**
115 * Create a new thread instance.
116 *
117 * @param main thread main function
118 * @param arg argument provided to the main function
119 * @return thread instance
120 */
121 thread_t *thread_create(thread_main_t main, void *arg);
122
123 /**
124 * Get a thread object for the current thread.
125 *
126 * @return thread instance
127 */
128 thread_t *thread_current();
129
130 /**
131 * Get the human-readable ID of the current thread.
132 *
133 * The IDs are assigned incrementally starting from 1.
134 *
135 * @return human-readable ID
136 */
137 u_int thread_current_id();
138
139 /**
140 * Push a function onto the current thread's cleanup handler stack.
141 * The callback function is called whenever the thread is cancelled, exits or
142 * thread_cleanup_pop is called with TRUE as execute argument.
143 *
144 * @param cleanup function called on thread exit
145 * @param arg argument provided to the callback
146 */
147 void thread_cleanup_push(thread_cleanup_t cleanup, void *arg);
148
149 /**
150 * Remove the top function from the current thread's cleanup handler stack
151 * and optionally execute it.
152 *
153 * @param execute TRUE to execute the function
154 */
155 void thread_cleanup_pop(bool execute);
156
157 /**
158 * Enable or disable the cancelability of the current thread. The current
159 * value is returned.
160 *
161 * @param enable TRUE to enable cancelability
162 * @return the current state of the cancelability
163 */
164 bool thread_cancelability(bool enable);
165
166 /**
167 * Force creation of a cancellation point in the calling thread.
168 *
169 * This temporarily enables thread cancelability, tests for a pending
170 * cancellation request and then disables cancelability again if it was
171 * disabled before the call to thread_cancellation_point().
172 */
173 void thread_cancellation_point();
174
175 /**
176 * Exit the current thread.
177 *
178 * @param val value provided to threads joining the current thread
179 */
180 void thread_exit(void *val);
181
182 /**
183 * Called by the main thread to initialize the thread management.
184 */
185 void threads_init();
186
187 /**
188 * Called by the main thread to deinitialize the thread management.
189 */
190 void threads_deinit();
191
192
193 #ifdef __APPLE__
194
195 /*
196 * While select() is a cancellation point, it seems that OS X does not honor
197 * pending cancellation points when entering the function. We manually test for
198 * and honor pending cancellation requests, but this obviously can't prevent
199 * some race conditions where the the cancellation happens after the check,
200 * but before the select.
201 */
202 static inline int precancellable_select(int nfds, fd_set *restrict readfds,
203 fd_set *restrict writefds, fd_set *restrict errorfds,
204 struct timeval *restrict timeout)
205 {
206 if (thread_cancelability(TRUE))
207 {
208 thread_cancellation_point();
209 }
210 else
211 {
212 thread_cancelability(FALSE);
213 }
214 return select(nfds, readfds, writefds, errorfds, timeout);
215 }
216 #define select precancellable_select
217
218 #include <poll.h>
219
220 /*
221 * The same as to select(2) applies to poll(2)
222 */
223 static inline int precancellable_poll(struct pollfd fds[], nfds_t nfds,
224 int timeout)
225 {
226 if (thread_cancelability(TRUE))
227 {
228 thread_cancellation_point();
229 }
230 else
231 {
232 thread_cancelability(FALSE);
233 }
234 return poll(fds, nfds, timeout);
235 }
236 #define poll precancellable_poll
237
238 #endif /* __APPLE__ */
239
240 #endif /** THREADING_THREAD_H_ @} */