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>