Annotation of embedaddon/strongswan/src/libstrongswan/threading/thread.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2009-2012 Tobias Brunner
        !             3:  * HSR Hochschule fuer Technik Rapperswil
        !             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: #define _GNU_SOURCE
        !            17: #include <pthread.h>
        !            18: #include <signal.h>
        !            19: 
        !            20: #ifdef HAVE_GETTID
        !            21: #include <sys/types.h>
        !            22: #include <unistd.h>
        !            23: #endif
        !            24: 
        !            25: #ifdef HAVE_SYS_GETTID
        !            26: #include <sys/syscall.h>
        !            27: static inline pid_t gettid()
        !            28: {
        !            29:        return syscall(SYS_gettid);
        !            30: }
        !            31: #endif
        !            32: 
        !            33: #include <library.h>
        !            34: #include <utils/debug.h>
        !            35: 
        !            36: #include <threading/thread_value.h>
        !            37: #include <threading/mutex.h>
        !            38: #include <collections/linked_list.h>
        !            39: 
        !            40: #include "thread.h"
        !            41: 
        !            42: typedef struct private_thread_t private_thread_t;
        !            43: 
        !            44: struct private_thread_t {
        !            45:        /**
        !            46:         * Public interface.
        !            47:         */
        !            48:        thread_t public;
        !            49: 
        !            50:        /**
        !            51:         * Identifier of this thread (human-readable/thread ID).
        !            52:         */
        !            53:        u_int id;
        !            54: 
        !            55:        /**
        !            56:         * ID of the underlying thread.
        !            57:         */
        !            58:        pthread_t thread_id;
        !            59: 
        !            60:        /**
        !            61:         * Main function of this thread (NULL for the main thread).
        !            62:         */
        !            63:        thread_main_t main;
        !            64: 
        !            65:        /**
        !            66:         * Argument for the main function.
        !            67:         */
        !            68:        void *arg;
        !            69: 
        !            70:        /**
        !            71:         * Stack of cleanup handlers.
        !            72:         */
        !            73:        linked_list_t *cleanup_handlers;
        !            74: 
        !            75:        /**
        !            76:         * Mutex to make modifying thread properties safe.
        !            77:         */
        !            78:        mutex_t *mutex;
        !            79: 
        !            80:        /**
        !            81:         * TRUE if this thread has been detached or joined, i.e. can be cleaned
        !            82:         * up after terminating.
        !            83:         */
        !            84:        bool detached_or_joined;
        !            85: 
        !            86:        /**
        !            87:         * TRUE if the threads has terminated (cancelled, via thread_exit or
        !            88:         * returned from the main function)
        !            89:         */
        !            90:        bool terminated;
        !            91: 
        !            92: };
        !            93: 
        !            94: typedef struct {
        !            95:        /**
        !            96:         * Cleanup callback function.
        !            97:         */
        !            98:        thread_cleanup_t cleanup;
        !            99: 
        !           100:        /**
        !           101:         * Argument provided to the cleanup function.
        !           102:         */
        !           103:        void *arg;
        !           104: 
        !           105: } cleanup_handler_t;
        !           106: 
        !           107: 
        !           108: /**
        !           109:  * Next thread ID.
        !           110:  */
        !           111: static u_int next_id;
        !           112: 
        !           113: /**
        !           114:  * Mutex to safely access the next thread ID.
        !           115:  */
        !           116: static mutex_t *id_mutex;
        !           117: 
        !           118: /**
        !           119:  * Store the thread object in a thread-specific value.
        !           120:  */
        !           121: static thread_value_t *current_thread;
        !           122: 
        !           123: 
        !           124: #ifndef HAVE_PTHREAD_CANCEL
        !           125: /* if pthread_cancel is not available, we emulate it using a signal */
        !           126: #ifdef ANDROID
        !           127: #define SIG_CANCEL SIGUSR2
        !           128: #else
        !           129: #define SIG_CANCEL (SIGRTMIN+7)
        !           130: #endif
        !           131: 
        !           132: /* the signal handler for SIG_CANCEL uses pthread_exit to terminate the
        !           133:  * "cancelled" thread */
        !           134: static void cancel_signal_handler(int sig)
        !           135: {
        !           136:        pthread_exit(NULL);
        !           137: }
        !           138: #endif
        !           139: 
        !           140: 
        !           141: /**
        !           142:  * Destroy an internal thread object.
        !           143:  *
        !           144:  * @note The mutex of this thread object has to be locked, it gets unlocked
        !           145:  * automatically.
        !           146:  */
        !           147: static void thread_destroy(private_thread_t *this)
        !           148: {
        !           149:        if (!this->terminated || !this->detached_or_joined)
        !           150:        {
        !           151:                this->mutex->unlock(this->mutex);
        !           152:                return;
        !           153:        }
        !           154:        this->cleanup_handlers->destroy(this->cleanup_handlers);
        !           155:        this->mutex->unlock(this->mutex);
        !           156:        this->mutex->destroy(this->mutex);
        !           157:        free(this);
        !           158: }
        !           159: 
        !           160: /**
        !           161:  * Determine the ID of the current thread
        !           162:  */
        !           163: static u_int get_thread_id()
        !           164: {
        !           165:        u_int id;
        !           166: 
        !           167: #if defined(USE_THREAD_IDS) && defined(HAVE_GETTID)
        !           168:        id = gettid();
        !           169: #else
        !           170:        id_mutex->lock(id_mutex);
        !           171:        id = next_id++;
        !           172:        id_mutex->unlock(id_mutex);
        !           173: #endif
        !           174:        return id;
        !           175: }
        !           176: 
        !           177: METHOD(thread_t, cancel, void,
        !           178:        private_thread_t *this)
        !           179: {
        !           180:        this->mutex->lock(this->mutex);
        !           181:        if (pthread_equal(this->thread_id, pthread_self()))
        !           182:        {
        !           183:                this->mutex->unlock(this->mutex);
        !           184:                DBG1(DBG_LIB, "!!! CANNOT CANCEL CURRENT THREAD !!!");
        !           185:                return;
        !           186:        }
        !           187: #ifdef HAVE_PTHREAD_CANCEL
        !           188:        pthread_cancel(this->thread_id);
        !           189: #else
        !           190:        pthread_kill(this->thread_id, SIG_CANCEL);
        !           191: #endif /* HAVE_PTHREAD_CANCEL */
        !           192:        this->mutex->unlock(this->mutex);
        !           193: }
        !           194: 
        !           195: METHOD(thread_t, kill_, void,
        !           196:        private_thread_t *this, int sig)
        !           197: {
        !           198:        this->mutex->lock(this->mutex);
        !           199:        if (pthread_equal(this->thread_id, pthread_self()))
        !           200:        {
        !           201:                /* it might actually be possible to send a signal to pthread_self (there
        !           202:                 * is an example in raise(3) describing that), the problem is though,
        !           203:                 * that the thread only returns here after the signal handler has
        !           204:                 * returned, so depending on the signal, the lock might not get
        !           205:                 * unlocked. */
        !           206:                this->mutex->unlock(this->mutex);
        !           207:                DBG1(DBG_LIB, "!!! CANNOT SEND SIGNAL TO CURRENT THREAD !!!");
        !           208:                return;
        !           209:        }
        !           210:        pthread_kill(this->thread_id, sig);
        !           211:        this->mutex->unlock(this->mutex);
        !           212: }
        !           213: 
        !           214: METHOD(thread_t, detach, void,
        !           215:        private_thread_t *this)
        !           216: {
        !           217:        this->mutex->lock(this->mutex);
        !           218:        pthread_detach(this->thread_id);
        !           219:        this->detached_or_joined = TRUE;
        !           220:        thread_destroy(this);
        !           221: }
        !           222: 
        !           223: METHOD(thread_t, join, void*,
        !           224:        private_thread_t *this)
        !           225: {
        !           226:        pthread_t thread_id;
        !           227:        void *val;
        !           228: 
        !           229:        this->mutex->lock(this->mutex);
        !           230:        if (pthread_equal(this->thread_id, pthread_self()))
        !           231:        {
        !           232:                this->mutex->unlock(this->mutex);
        !           233:                DBG1(DBG_LIB, "!!! CANNOT JOIN CURRENT THREAD !!!");
        !           234:                return NULL;
        !           235:        }
        !           236:        if (this->detached_or_joined)
        !           237:        {
        !           238:                this->mutex->unlock(this->mutex);
        !           239:                DBG1(DBG_LIB, "!!! CANNOT JOIN DETACHED THREAD !!!");
        !           240:                return NULL;
        !           241:        }
        !           242:        thread_id = this->thread_id;
        !           243:        this->detached_or_joined = TRUE;
        !           244:        if (this->terminated)
        !           245:        {
        !           246:                /* thread has terminated before the call to join */
        !           247:                thread_destroy(this);
        !           248:        }
        !           249:        else
        !           250:        {
        !           251:                /* thread_destroy is called when the thread terminates normally */
        !           252:                this->mutex->unlock(this->mutex);
        !           253:        }
        !           254:        pthread_join(thread_id, &val);
        !           255: 
        !           256:        return val;
        !           257: }
        !           258: 
        !           259: /**
        !           260:  * Create an internal thread object.
        !           261:  */
        !           262: static private_thread_t *thread_create_internal()
        !           263: {
        !           264:        private_thread_t *this;
        !           265: 
        !           266:        INIT(this,
        !           267:                .public = {
        !           268:                        .cancel = _cancel,
        !           269:                        .kill = _kill_,
        !           270:                        .detach = _detach,
        !           271:                        .join = _join,
        !           272:                },
        !           273:                .cleanup_handlers = linked_list_create(),
        !           274:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
        !           275:        );
        !           276: 
        !           277:        return this;
        !           278: }
        !           279: 
        !           280: /**
        !           281:  * Remove and run all cleanup handlers in reverse order.
        !           282:  */
        !           283: static void thread_cleanup_popall_internal(private_thread_t *this)
        !           284: {
        !           285:        cleanup_handler_t *handler;
        !           286: 
        !           287:        while (this->cleanup_handlers->remove_last(this->cleanup_handlers,
        !           288:                                                                                          (void**)&handler) == SUCCESS)
        !           289:        {
        !           290:                handler->cleanup(handler->arg);
        !           291:                free(handler);
        !           292:        }
        !           293: }
        !           294: 
        !           295: /**
        !           296:  * Main cleanup function for threads.
        !           297:  */
        !           298: static void thread_cleanup(private_thread_t *this)
        !           299: {
        !           300:        thread_cleanup_popall_internal(this);
        !           301:        this->mutex->lock(this->mutex);
        !           302:        this->terminated = TRUE;
        !           303:        thread_destroy(this);
        !           304: }
        !           305: 
        !           306: /**
        !           307:  * Main function wrapper for threads.
        !           308:  */
        !           309: static void *thread_main(private_thread_t *this)
        !           310: {
        !           311:        void *res;
        !           312: 
        !           313:        this->id = get_thread_id();
        !           314: 
        !           315:        current_thread->set(current_thread, this);
        !           316:        pthread_cleanup_push((thread_cleanup_t)thread_cleanup, this);
        !           317: 
        !           318:        /* TODO: this is not 100% portable as pthread_t is an opaque type (i.e.
        !           319:         * could be of any size, or even a struct) */
        !           320: #ifdef HAVE_GETTID
        !           321:        DBG2(DBG_LIB, "created thread %.2d [%u]",
        !           322:                 this->id, gettid());
        !           323: #elif defined(WIN32)
        !           324:        DBG2(DBG_LIB, "created thread %.2d [%p]",
        !           325:                 this->id, this->thread_id.p);
        !           326: #else
        !           327:        DBG2(DBG_LIB, "created thread %.2d [%lx]",
        !           328:                 this->id, (u_long)this->thread_id);
        !           329: #endif
        !           330: 
        !           331:        res = this->main(this->arg);
        !           332:        pthread_cleanup_pop(TRUE);
        !           333: 
        !           334:        return res;
        !           335: }
        !           336: 
        !           337: /**
        !           338:  * Described in header.
        !           339:  */
        !           340: thread_t *thread_create(thread_main_t main, void *arg)
        !           341: {
        !           342:        private_thread_t *this = thread_create_internal();
        !           343: 
        !           344:        this->main = main;
        !           345:        this->arg = arg;
        !           346: 
        !           347:        if (pthread_create(&this->thread_id, NULL, (void*)thread_main, this) != 0)
        !           348:        {
        !           349:                DBG1(DBG_LIB, "failed to create thread!");
        !           350:                this->mutex->lock(this->mutex);
        !           351:                this->terminated = TRUE;
        !           352:                this->detached_or_joined = TRUE;
        !           353:                thread_destroy(this);
        !           354:                return NULL;
        !           355:        }
        !           356: 
        !           357:        return &this->public;
        !           358: }
        !           359: 
        !           360: /**
        !           361:  * Described in header.
        !           362:  */
        !           363: thread_t *thread_current()
        !           364: {
        !           365:        private_thread_t *this;
        !           366: 
        !           367:        this = (private_thread_t*)current_thread->get(current_thread);
        !           368:        if (!this)
        !           369:        {
        !           370:                this = thread_create_internal();
        !           371:                this->id = get_thread_id();
        !           372:                current_thread->set(current_thread, (void*)this);
        !           373:        }
        !           374:        return &this->public;
        !           375: }
        !           376: 
        !           377: /**
        !           378:  * Described in header.
        !           379:  */
        !           380: u_int thread_current_id()
        !           381: {
        !           382:        private_thread_t *this = (private_thread_t*)thread_current();
        !           383: 
        !           384:        return this ? this->id : 0;
        !           385: }
        !           386: 
        !           387: /**
        !           388:  * Described in header.
        !           389:  */
        !           390: void thread_cleanup_push(thread_cleanup_t cleanup, void *arg)
        !           391: {
        !           392:        private_thread_t *this = (private_thread_t*)thread_current();
        !           393:        cleanup_handler_t *handler;
        !           394: 
        !           395:        INIT(handler,
        !           396:                .cleanup = cleanup,
        !           397:                .arg = arg,
        !           398:        );
        !           399: 
        !           400:        this->cleanup_handlers->insert_last(this->cleanup_handlers, handler);
        !           401: }
        !           402: 
        !           403: /**
        !           404:  * Described in header.
        !           405:  */
        !           406: void thread_cleanup_pop(bool execute)
        !           407: {
        !           408:        private_thread_t *this = (private_thread_t*)thread_current();
        !           409:        cleanup_handler_t *handler;
        !           410: 
        !           411:        if (this->cleanup_handlers->remove_last(this->cleanup_handlers,
        !           412:                                                                                        (void**)&handler) != SUCCESS)
        !           413:        {
        !           414:                DBG1(DBG_LIB, "!!! THREAD CLEANUP ERROR !!!");
        !           415:                return;
        !           416:        }
        !           417: 
        !           418:        if (execute)
        !           419:        {
        !           420:                handler->cleanup(handler->arg);
        !           421:        }
        !           422:        free(handler);
        !           423: }
        !           424: 
        !           425: /**
        !           426:  * Described in header.
        !           427:  */
        !           428: void thread_cleanup_popall()
        !           429: {
        !           430:        private_thread_t *this = (private_thread_t*)thread_current();
        !           431: 
        !           432:        thread_cleanup_popall_internal(this);
        !           433: }
        !           434: 
        !           435: /**
        !           436:  * Described in header.
        !           437:  */
        !           438: bool thread_cancelability(bool enable)
        !           439: {
        !           440: #ifdef HAVE_PTHREAD_CANCEL
        !           441:        int old;
        !           442: 
        !           443:        pthread_setcancelstate(enable ? PTHREAD_CANCEL_ENABLE
        !           444:                                                                  : PTHREAD_CANCEL_DISABLE, &old);
        !           445: 
        !           446:        return old == PTHREAD_CANCEL_ENABLE;
        !           447: #else
        !           448:        sigset_t new, old;
        !           449: 
        !           450:        sigemptyset(&new);
        !           451:        sigaddset(&new, SIG_CANCEL);
        !           452:        pthread_sigmask(enable ? SIG_UNBLOCK : SIG_BLOCK, &new, &old);
        !           453: 
        !           454:        return sigismember(&old, SIG_CANCEL) == 0;
        !           455: #endif /* HAVE_PTHREAD_CANCEL */
        !           456: }
        !           457: 
        !           458: /**
        !           459:  * Described in header.
        !           460:  */
        !           461: void thread_cancellation_point()
        !           462: {
        !           463:        bool old = thread_cancelability(TRUE);
        !           464: 
        !           465: #ifdef HAVE_PTHREAD_CANCEL
        !           466:        pthread_testcancel();
        !           467: #endif /* HAVE_PTHREAD_CANCEL */
        !           468:        thread_cancelability(old);
        !           469: }
        !           470: 
        !           471: /**
        !           472:  * Described in header.
        !           473:  */
        !           474: void thread_exit(void *val)
        !           475: {
        !           476:        pthread_exit(val);
        !           477: }
        !           478: 
        !           479: /**
        !           480:  * A dummy thread value that reserved pthread_key_t value "0". A buggy PKCS#11
        !           481:  * library mangles this key, without owning it, so we allocate it for them.
        !           482:  */
        !           483: static thread_value_t *dummy1;
        !           484: 
        !           485: /**
        !           486:  * Described in header.
        !           487:  */
        !           488: void threads_init()
        !           489: {
        !           490:        private_thread_t *main_thread = thread_create_internal();
        !           491: 
        !           492:        dummy1 = thread_value_create(NULL);
        !           493: 
        !           494:        next_id = 0;
        !           495:        main_thread->thread_id = pthread_self();
        !           496:        current_thread = thread_value_create(NULL);
        !           497:        current_thread->set(current_thread, (void*)main_thread);
        !           498:        id_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
        !           499:        main_thread->id = get_thread_id();
        !           500: 
        !           501: #ifndef HAVE_PTHREAD_CANCEL
        !           502:        {       /* install a signal handler for our custom SIG_CANCEL */
        !           503:                struct sigaction action = {
        !           504:                        .sa_handler = cancel_signal_handler
        !           505:                };
        !           506:                sigaction(SIG_CANCEL, &action, NULL);
        !           507:        }
        !           508: #endif /* HAVE_PTHREAD_CANCEL */
        !           509: }
        !           510: 
        !           511: /**
        !           512:  * Described in header.
        !           513:  */
        !           514: void threads_deinit()
        !           515: {
        !           516:        private_thread_t *main_thread = (private_thread_t*)thread_current();
        !           517: 
        !           518:        dummy1->destroy(dummy1);
        !           519: 
        !           520:        main_thread->mutex->lock(main_thread->mutex);
        !           521:        main_thread->terminated = TRUE;
        !           522:        main_thread->detached_or_joined = TRUE;
        !           523:        thread_destroy(main_thread);
        !           524:        current_thread->destroy(current_thread);
        !           525:        id_mutex->destroy(id_mutex);
        !           526: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>