Annotation of embedaddon/strongswan/src/libstrongswan/threading/windows/thread.c, revision 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>