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>