Annotation of embedaddon/strongswan/src/libstrongswan/threading/windows/thread.c, revision 1.1.1.1
1.1 misho 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: 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: * Thread cleanup data
250: */
251: typedef struct {
252: /** Cleanup callback function */
253: thread_cleanup_t cb;
254: /** Argument provided to the cleanup function */
255: void *arg;
256: } cleanup_t;
257:
258: /**
259: * Invoke pushed/tls cleanup handlers
260: */
261: static void docleanup(private_thread_t *this)
262: {
263: enumerator_t *enumerator;
264: cleanup_t cleanup, *tls;
265: bool old;
266:
267: old = set_leak_detective(FALSE);
268:
269: while (array_remove(this->cleanup, -1, &cleanup))
270: {
271: set_leak_detective(old);
272: cleanup.cb(cleanup.arg);
273: set_leak_detective(FALSE);
274: }
275:
276: threads_lock->lock(threads_lock);
277: enumerator = this->tls->create_enumerator(this->tls);
278: while (enumerator->enumerate(enumerator, NULL, &tls))
279: {
280: this->tls->remove_at(this->tls, enumerator);
281:
282: set_leak_detective(old);
283: thread_tls_cleanup(tls);
284: set_leak_detective(FALSE);
285: }
286: enumerator->destroy(enumerator);
287: threads_lock->unlock(threads_lock);
288:
289: set_leak_detective(old);
290: }
291:
292: /**
293: * Clean up and destroy a thread
294: */
295: static void destroy(private_thread_t *this)
296: {
297: bool old;
298:
299: docleanup(this);
300:
301: old = set_leak_detective(FALSE);
302:
303: array_destroy(this->cleanup);
304: this->tls->destroy(this->tls);
305: if (this->handle)
306: {
307: CloseHandle(this->handle);
308: }
309: free(this);
310:
311: set_leak_detective(old);
312: }
313:
314: /**
315: * End a thread, destroy when detached
316: */
317: static void end_thread(private_thread_t *this)
318: {
319: if (this->detached)
320: {
321: remove_thread(this);
322: destroy(this);
323: }
324: else
325: {
326: this->terminated = TRUE;
327: docleanup(this);
328: }
329: }
330:
331: /**
332: * See header.
333: */
334: void thread_set_active_condvar(CONDITION_VARIABLE *condvar)
335: {
336: private_thread_t *thread;
337:
338: thread = get_current_thread();
339:
340: threads_lock->lock(threads_lock);
341: thread->condvar = condvar;
342: threads_lock->unlock(threads_lock);
343:
344: /* this is a cancellation point, as condvar wait is one */
345: SleepEx(0, TRUE);
346: }
347:
348: /**
349: * APC to cancel a thread
350: */
351: static void WINAPI docancel(ULONG_PTR dwParam)
352: {
353: private_thread_t *this = (private_thread_t*)dwParam;
354:
355: /* make sure cancel() does not access this anymore */
356: threads_lock->lock(threads_lock);
357: threads_lock->unlock(threads_lock);
358:
359: end_thread(this);
360: ExitThread(0);
361: }
362:
363: METHOD(thread_t, cancel, void,
364: private_thread_t *this)
365: {
366: this->canceled = TRUE;
367: if (this->cancelability)
368: {
369: threads_lock->lock(threads_lock);
370: if (!this->cancel_pending)
371: {
372: this->cancel_pending = TRUE;
373: QueueUserAPC(docancel, this->handle, (uintptr_t)this);
374: if (this->condvar)
375: {
376: WakeAllConditionVariable(this->condvar);
377: }
378: }
379: threads_lock->unlock(threads_lock);
380: }
381: }
382:
383: METHOD(thread_t, kill_, void,
384: private_thread_t *this, int sig)
385: {
386: }
387:
388: METHOD(thread_t, detach, void,
389: private_thread_t *this)
390: {
391: this->detached = TRUE;
392: }
393:
394: METHOD(thread_t, join, void*,
395: private_thread_t *this)
396: {
397: void *ret;
398:
399: if (this->detached)
400: {
401: return NULL;
402: }
403:
404: while (!this->terminated)
405: {
406: /* join is a cancellation point, use alertable wait */
407: WaitForSingleObjectEx(this->handle, INFINITE, TRUE);
408: }
409:
410: ret = this->ret;
411:
412: remove_thread(this);
413: destroy(this);
414:
415: return ret;
416: }
417:
418: /**
419: * Main function wrapper for threads
420: */
421: static DWORD thread_cb(private_thread_t *this)
422: {
423: /* Enable cancelability once the thread starts. We must check for any
424: * pending cancellation request an queue the APC that gets executed
425: * at the first cancellation point. */
426: this->cancelability = TRUE;
427: if (this->canceled)
428: {
429: cancel(this);
430: }
431:
432: this->ret = this->main(this->arg);
433:
434: end_thread(this);
435:
436: return 0;
437: }
438:
439: /**
440: * Create an internal thread object.
441: */
442: static private_thread_t *create_internal(DWORD id)
443: {
444: private_thread_t *this;
445: bool old;
446:
447: old = set_leak_detective(FALSE);
448:
449: INIT(this,
450: .public = {
451: .cancel = _cancel,
452: .kill = _kill_,
453: .detach = _detach,
454: .join = _join,
455: },
456: .cleanup = array_create(sizeof(cleanup_t), 0),
457: .tls = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4),
458: .id = id,
459: .cancelability = TRUE,
460: );
461:
462: set_leak_detective(old);
463:
464: threads_lock->lock(threads_lock);
465: this->tid = threads_ids++;
466: threads_lock->unlock(threads_lock);
467:
468: if (id)
469: {
470: this->handle = OpenThread(THREAD_ALL_ACCESS, FALSE, id);
471: }
472: return this;
473: }
474:
475: /**
476: * Described in header.
477: */
478: thread_t *thread_create(thread_main_t main, void *arg)
479: {
480: private_thread_t *this;
481:
482: this = create_internal(0);
483:
484: this->main = main;
485: this->arg = arg;
486: /* not cancellable until started */
487: this->cancelability = FALSE;
488:
489: this->handle = CreateThread(NULL, 0, (void*)thread_cb, this,
490: CREATE_SUSPENDED, &this->id);
491: if (!this->handle)
492: {
493: destroy(this);
494: return NULL;
495: }
496:
497: put_thread(this);
498:
499: DBG2(DBG_LIB, "created thread %u", this->id);
500:
501: ResumeThread(this->handle);
502:
503: return &this->public;
504: }
505:
506: /**
507: * Described in header.
508: */
509: thread_t *thread_current()
510: {
511: return &get_current_thread()->public;
512: }
513:
514: /**
515: * Described in header.
516: */
517: u_int thread_current_id()
518: {
519: #ifdef USE_THREAD_IDS
520: return get_current_thread()->id;
521: #else
522: return get_current_thread()->tid;
523: #endif
524: }
525:
526: /**
527: * Described in header.
528: */
529: void thread_cleanup_push(thread_cleanup_t cb, void *arg)
530: {
531: private_thread_t *this;
532: cleanup_t cleanup = {
533: .cb = cb,
534: .arg = arg,
535: };
536: bool old;
537:
538: this = get_current_thread();
539:
540: old = set_leak_detective(FALSE);
541: array_insert(this->cleanup, -1, &cleanup);
542: set_leak_detective(old);
543: }
544:
545: /**
546: * Described in header
547: */
548: void thread_cleanup_pop(bool execute)
549: {
550: private_thread_t *this;
551: cleanup_t cleanup = {};
552: bool old;
553:
554: this = get_current_thread();
555:
556: old = set_leak_detective(FALSE);
557: array_remove(this->cleanup, -1, &cleanup);
558: set_leak_detective(old);
559:
560: if (execute)
561: {
562: cleanup.cb(cleanup.arg);
563: }
564: }
565:
566: /**
567: * Described in header.
568: */
569: void thread_cleanup_popall()
570: {
571: private_thread_t *this;
572: cleanup_t cleanup = {};
573: bool old;
574:
575: this = get_current_thread();
576: while (array_count(this->cleanup))
577: {
578: old = set_leak_detective(FALSE);
579: array_remove(this->cleanup, -1, &cleanup);
580: set_leak_detective(old);
581:
582: cleanup.cb(cleanup.arg);
583: }
584: }
585:
586: /**
587: * Described in header.
588: */
589: bool thread_cancelability(bool enable)
590: {
591: private_thread_t *this;
592: bool old;
593:
594: this = get_current_thread();
595: old = this->cancelability;
596: this->cancelability = enable;
597:
598: if (enable && !old && this->canceled)
599: {
600: cancel(this);
601: }
602: return old;
603: }
604:
605: /**
606: * Described in header.
607: */
608: void thread_cancellation_point()
609: {
610: bool old;
611:
612: old = thread_cancelability(TRUE);
613: SleepEx(0, TRUE);
614: thread_cancelability(old);
615: }
616:
617: /**
618: * Described in header.
619: */
620: void thread_exit(void *val)
621: {
622: private_thread_t *this;
623:
624: this = get_current_thread();
625: this->ret = val;
626:
627: end_thread(this);
628: ExitThread(0);
629: }
630:
631: /**
632: * Clean up thread data while it detaches
633: */
634: static void cleanup_tls()
635: {
636: private_thread_t *this;
637: bool old;
638:
639: old = set_leak_detective(FALSE);
640: threads_lock->lock(threads_lock);
641:
642: this = threads->remove(threads, (void*)(uintptr_t)GetCurrentThreadId());
643:
644: threads_lock->unlock(threads_lock);
645: set_leak_detective(old);
646:
647: if (this)
648: {
649: /* If the thread exited, but has not been joined, it is in terminated
650: * state. We must not mangle it, as we target externally spawned
651: * threads only. */
652: if (!this->terminated && !this->detached)
653: {
654: destroy(this);
655: }
656: }
657: }
658:
659: /**
660: * DllMain called for dll events
661: */
662: BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
663: {
664: switch (fdwReason)
665: {
666: case DLL_THREAD_DETACH:
667: cleanup_tls();
668: break;
669: default:
670: break;
671: }
672: return TRUE;
673: }
674:
675: /*
676: * Described in header.
677: */
678: void threads_init()
679: {
680: threads_lock = spinlock_create();
681: threads = hashtable_create(hashtable_hash_ptr, hashtable_equals_ptr, 4);
682:
683: /* reset counter should we initialize more than once */
684: threads_ids = 0;
685:
686: put_thread(create_internal(GetCurrentThreadId()));
687: }
688:
689: /**
690: * Described in header.
691: */
692: void threads_deinit()
693: {
694: private_thread_t *this;
695:
696: this = threads->remove(threads, (void*)(uintptr_t)GetCurrentThreadId());
697: destroy(this);
698:
699: threads_lock->destroy(threads_lock);
700: threads->destroy(threads);
701: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>