windows: Use WINAPI call convention for Windows API callbacks
[strongswan.git] / src / libstrongswan / threading / windows / thread.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
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 #include "thread.h"
17
18 #include <utils/debug.h>
19 #include <threading/spinlock.h>
20 #include <threading/thread.h>
21 #include <collections/hashtable.h>
22 #include <collections/array.h>
23
24
25 typedef struct private_thread_t private_thread_t;
26
27 struct private_thread_t {
28
29 /**
30 * Public interface.
31 */
32 thread_t public;
33
34 /**
35 * GetCurrentThreadId() of thread
36 */
37 DWORD id;
38
39 /**
40 * Printable thread id returned by thread_current_id()
41 */
42 u_int tid;
43
44 /**
45 * Windows thread handle
46 */
47 HANDLE handle;
48
49 /**
50 * Main function of this thread (NULL for the main thread).
51 */
52 thread_main_t main;
53
54 /**
55 * Argument for the main function.
56 */
57 void *arg;
58
59 /**
60 * Thread return value
61 */
62 void *ret;
63
64 /**
65 * Stack of cleanup handlers, as cleanup_t
66 */
67 array_t *cleanup;
68
69 /**
70 * Thread specific values for this thread
71 */
72 hashtable_t *tls;
73
74 /**
75 * Thread terminated?
76 */
77 bool terminated;
78
79 /**
80 * Thread detached?
81 */
82 bool detached;
83
84 /**
85 * Is thread in cancellable state
86 */
87 bool cancelability;
88
89 /**
90 * Has the thread been cancelled by thread->cancel()?
91 */
92 bool canceled;
93
94 /**
95 * Did we schedule an APC to docancel()?
96 */
97 bool cancel_pending;
98
99 /**
100 * Active condition variable thread is waiting in, if any
101 */
102 CONDITION_VARIABLE *condvar;
103 };
104
105 /**
106 * Global list of threads, GetCurrentThreadId() => private_thread_t
107 */
108 static hashtable_t *threads;
109
110 /**
111 * Lock for threads table
112 */
113 static spinlock_t *threads_lock;
114
115 /**
116 * Counter to assign printable thread IDs
117 */
118 static u_int threads_ids = 0;
119
120 /**
121 * Forward declaration
122 */
123 static private_thread_t *create_internal(DWORD id);
124
125 /**
126 * Set leak detective state
127 */
128 static inline bool set_leak_detective(bool state)
129 {
130 #ifdef LEAK_DETECTIVE
131 if (lib && lib->leak_detective)
132 {
133 return lib->leak_detective->set_state(lib->leak_detective, state);
134 }
135 #endif
136 return FALSE;
137 }
138
139 /**
140 * Store thread in index
141 */
142 static void put_thread(private_thread_t *this)
143 {
144 bool old;
145
146 old = set_leak_detective(FALSE);
147 threads_lock->lock(threads_lock);
148
149 this = threads->put(threads, (void*)(uintptr_t)this->id, this);
150
151 threads_lock->unlock(threads_lock);
152 set_leak_detective(old);
153 }
154
155 /**
156 * Remove thread from index
157 */
158 static void remove_thread(private_thread_t *this)
159 {
160 bool old;
161
162 old = set_leak_detective(FALSE);
163 threads_lock->lock(threads_lock);
164
165 threads->remove(threads, (void*)(uintptr_t)this->id);
166
167 threads_lock->unlock(threads_lock);
168 set_leak_detective(old);
169 }
170
171 /**
172 * Get thread data for calling thread
173 */
174 static private_thread_t *get_current_thread()
175 {
176 private_thread_t *this;
177
178 threads_lock->lock(threads_lock);
179
180 this = threads->get(threads, (void*)(uintptr_t)GetCurrentThreadId());
181
182 threads_lock->unlock(threads_lock);
183
184 if (!this)
185 {
186 this = create_internal(GetCurrentThreadId());
187 put_thread(this);
188 }
189
190 return this;
191 }
192
193 /**
194 * See header.
195 */
196 void* thread_tls_put(void *key, void *value)
197 {
198 private_thread_t *thread;
199 bool old;
200
201 thread = get_current_thread();
202
203 old = set_leak_detective(FALSE);
204 value = thread->tls->put(thread->tls, key, value);
205 set_leak_detective(old);
206
207 return value;
208 }
209
210 /**
211 * See header.
212 */
213 void* thread_tls_get(void *key)
214 {
215 private_thread_t *thread;
216 void *value;
217 bool old;
218
219 thread = get_current_thread();
220
221 old = set_leak_detective(FALSE);
222 value = thread->tls->get(thread->tls, key);
223 set_leak_detective(old);
224
225 return value;
226 }
227
228 /**
229 * See header.
230 */
231 void* thread_tls_remove(void *key)
232 {
233 private_thread_t *thread;
234 void *value;
235 bool old;
236
237 thread = get_current_thread();
238
239 old = set_leak_detective(FALSE);
240 threads_lock->lock(threads_lock);
241 value = thread->tls->remove(thread->tls, key);
242 threads_lock->unlock(threads_lock);
243 set_leak_detective(old);
244
245 return value;
246 }
247
248 /**
249 * See header.
250 */
251 void thread_tls_remove_all(void *key)
252 {
253 private_thread_t *thread;
254 enumerator_t *enumerator;
255 void *value;
256 bool old;
257
258 old = set_leak_detective(FALSE);
259 threads_lock->lock(threads_lock);
260
261 enumerator = threads->create_enumerator(threads);
262 while (enumerator->enumerate(enumerator, NULL, &thread))
263 {
264 value = thread->tls->remove(thread->tls, key);
265 if (value)
266 {
267 set_leak_detective(old);
268 thread_tls_cleanup(value);
269 set_leak_detective(FALSE);
270 }
271 }
272 enumerator->destroy(enumerator);
273
274 threads_lock->unlock(threads_lock);
275 set_leak_detective(old);
276 }
277
278 /**
279 * Thread cleanup data
280 */
281 typedef struct {
282 /** Cleanup callback function */
283 thread_cleanup_t cb;
284 /** Argument provided to the cleanup function */
285 void *arg;
286 } cleanup_t;
287
288 /**
289 * Invoke pushed/tls cleanup handlers
290 */
291 static void docleanup(private_thread_t *this)
292 {
293 enumerator_t *enumerator;
294 cleanup_t cleanup, *tls;
295 bool old;
296
297 old = set_leak_detective(FALSE);
298
299 while (array_remove(this->cleanup, -1, &cleanup))
300 {
301 set_leak_detective(old);
302 cleanup.cb(cleanup.arg);
303 set_leak_detective(FALSE);
304 }
305
306 threads_lock->lock(threads_lock);
307 enumerator = this->tls->create_enumerator(this->tls);
308 while (enumerator->enumerate(enumerator, NULL, &tls))
309 {
310 this->tls->remove_at(this->tls, enumerator);
311
312 set_leak_detective(old);
313 thread_tls_cleanup(tls);
314 set_leak_detective(FALSE);
315 }
316 enumerator->destroy(enumerator);
317 threads_lock->unlock(threads_lock);
318
319 set_leak_detective(old);
320 }
321
322 /**
323 * Clean up and destroy a thread
324 */
325 static void destroy(private_thread_t *this)
326 {
327 bool old;
328
329 docleanup(this);
330
331 old = set_leak_detective(FALSE);
332
333 array_destroy(this->cleanup);
334 this->tls->destroy(this->tls);
335 if (this->handle)
336 {
337 CloseHandle(this->handle);
338 }
339 free(this);
340
341 set_leak_detective(old);
342 }
343
344 /**
345 * End a thread, destroy when detached
346 */
347 static void end_thread(private_thread_t *this)
348 {
349 if (this->detached)
350 {
351 remove_thread(this);
352 destroy(this);
353 }
354 else
355 {
356 this->terminated = TRUE;
357 docleanup(this);
358 }
359 }
360
361 /**
362 * See header.
363 */
364 void thread_set_active_condvar(CONDITION_VARIABLE *condvar)
365 {
366 private_thread_t *thread;
367
368 thread = get_current_thread();
369
370 threads_lock->lock(threads_lock);
371 thread->condvar = condvar;
372 threads_lock->unlock(threads_lock);
373
374 /* this is a cancellation point, as condvar wait is one */
375 SleepEx(0, TRUE);
376 }
377
378 /**
379 * APC to cancel a thread
380 */
381 static void WINAPI docancel(ULONG_PTR dwParam)
382 {
383 private_thread_t *this = (private_thread_t*)dwParam;
384
385 /* make sure cancel() does not access this anymore */
386 threads_lock->lock(threads_lock);
387 threads_lock->unlock(threads_lock);
388
389 end_thread(this);
390 ExitThread(0);
391 }
392
393 METHOD(thread_t, cancel, void,
394 private_thread_t *this)
395 {
396 this->canceled = TRUE;
397 if (this->cancelability)
398 {
399 threads_lock->lock(threads_lock);
400 if (!this->cancel_pending)
401 {
402 this->cancel_pending = TRUE;
403 QueueUserAPC(docancel, this->handle, (uintptr_t)this);
404 if (this->condvar)
405 {
406 WakeAllConditionVariable(this->condvar);
407 }
408 }
409 threads_lock->unlock(threads_lock);
410 }
411 }
412
413 METHOD(thread_t, kill_, void,
414 private_thread_t *this, int sig)
415 {
416 }
417
418 METHOD(thread_t, detach, void,
419 private_thread_t *this)
420 {
421 this->detached = TRUE;
422 }
423
424 METHOD(thread_t, join, void*,
425 private_thread_t *this)
426 {
427 void *ret;
428
429 if (this->detached)
430 {
431 return NULL;
432 }
433
434 while (!this->terminated)
435 {
436 /* join is a cancellation point, use alertable wait */
437 WaitForSingleObjectEx(this->handle, INFINITE, TRUE);
438 }
439
440 ret = this->ret;
441
442 remove_thread(this);
443 destroy(this);
444
445 return ret;
446 }
447
448 /**
449 * Main function wrapper for threads
450 */
451 static DWORD thread_cb(private_thread_t *this)
452 {
453 /* Enable cancelability once the thread starts. We must check for any
454 * pending cancellation request an queue the APC that gets executed
455 * at the first cancellation point. */
456 this->cancelability = TRUE;
457 if (this->canceled)
458 {
459 cancel(this);
460 }
461
462 this->ret = this->main(this->arg);
463
464 end_thread(this);
465
466 return 0;
467 }
468
469 /**
470 * Create an internal thread object.
471 */
472 static private_thread_t *create_internal(DWORD id)
473 {
474 private_thread_t *this;
475 bool old;
476
477 old = set_leak_detective(FALSE);
478
479 INIT(this,
480 .public = {
481 .cancel = _cancel,
482 .kill = _kill_,
483 .detach = _detach,
484 .join = _join,
485 },
486 .cleanup = array_create(sizeof(cleanup_t), 0),
487 .tls = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4),
488 .id = id,
489 .cancelability = TRUE,
490 );
491
492 set_leak_detective(old);
493
494 threads_lock->lock(threads_lock);
495 this->tid = threads_ids++;
496 threads_lock->unlock(threads_lock);
497
498 if (id)
499 {
500 this->handle = OpenThread(THREAD_ALL_ACCESS, FALSE, id);
501 }
502 return this;
503 }
504
505 /**
506 * Described in header.
507 */
508 thread_t *thread_create(thread_main_t main, void *arg)
509 {
510 private_thread_t *this;
511
512 this = create_internal(0);
513
514 this->main = main;
515 this->arg = arg;
516 /* not cancellable until started */
517 this->cancelability = FALSE;
518
519 this->handle = CreateThread(NULL, 0, (void*)thread_cb, this,
520 CREATE_SUSPENDED, &this->id);
521 if (!this->handle)
522 {
523 destroy(this);
524 return NULL;
525 }
526
527 put_thread(this);
528
529 DBG2(DBG_LIB, "created thread %u", this->id);
530
531 ResumeThread(this->handle);
532
533 return &this->public;
534 }
535
536 /**
537 * Described in header.
538 */
539 thread_t *thread_current()
540 {
541 return &get_current_thread()->public;
542 }
543
544 /**
545 * Described in header.
546 */
547 u_int thread_current_id()
548 {
549 return get_current_thread()->tid;
550 }
551
552 /**
553 * Described in header.
554 */
555 void thread_cleanup_push(thread_cleanup_t cb, void *arg)
556 {
557 private_thread_t *this;
558 cleanup_t cleanup = {
559 .cb = cb,
560 .arg = arg,
561 };
562 bool old;
563
564 this = get_current_thread();
565
566 old = set_leak_detective(FALSE);
567 array_insert(this->cleanup, -1, &cleanup);
568 set_leak_detective(old);
569 }
570
571 /**
572 * Described in header
573 */
574 void thread_cleanup_pop(bool execute)
575 {
576 private_thread_t *this;
577 cleanup_t cleanup = {};
578 bool old;
579
580 this = get_current_thread();
581
582 old = set_leak_detective(FALSE);
583 array_remove(this->cleanup, -1, &cleanup);
584 set_leak_detective(old);
585
586 if (execute)
587 {
588 cleanup.cb(cleanup.arg);
589 }
590 }
591
592 /**
593 * Described in header.
594 */
595 bool thread_cancelability(bool enable)
596 {
597 private_thread_t *this;
598 bool old;
599
600 this = get_current_thread();
601 old = this->cancelability;
602 this->cancelability = enable;
603
604 if (enable && !old && this->canceled)
605 {
606 cancel(this);
607 }
608 return old;
609 }
610
611 /**
612 * Described in header.
613 */
614 void thread_cancellation_point()
615 {
616 bool old;
617
618 old = thread_cancelability(TRUE);
619 SleepEx(0, TRUE);
620 thread_cancelability(old);
621 }
622
623 /**
624 * Described in header.
625 */
626 void thread_exit(void *val)
627 {
628 private_thread_t *this;
629
630 this = get_current_thread();
631 this->ret = val;
632
633 end_thread(this);
634 ExitThread(0);
635 }
636
637 /*
638 * Described in header.
639 */
640 void threads_init()
641 {
642 threads_lock = spinlock_create();
643 threads = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4);
644
645 /* reset counter should we initialize more than once */
646 threads_ids = 0;
647
648 put_thread(create_internal(GetCurrentThreadId()));
649 }
650
651 /**
652 * Described in header.
653 */
654 void threads_deinit()
655 {
656 private_thread_t *this;
657
658 this = threads->remove(threads, (void*)(uintptr_t)GetCurrentThreadId());
659 destroy(this);
660
661 threads_lock->destroy(threads_lock);
662 threads->destroy(threads);
663 }