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>