Return to thread.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libstrongswan / threading / windows |
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: }