00001 /* Part of the culibs project, <http://www.eideticdew.org/culibs/>. 00002 * Copyright (C) 2004--2009 Petter Urkedal <urkedal@nbi.dk> 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #ifndef CU_THREAD_H 00019 #define CU_THREAD_H 00020 00021 #include <pthread.h> 00022 #include <cu/fwd.h> 00023 #include <cu/conf.h> 00024 #include <cu/diag.h> 00025 #include <cu/hash.h> 00026 #include <string.h> 00027 #include <errno.h> 00028 00029 CU_BEGIN_DECLARATIONS 00030 /** \defgroup cu_thread_h cu/thread.h: Multi-Threading (Extensions to pthreads) 00031 ** @{ \ingroup cu_base_mod 00032 ** 00033 ** These are mostly light wrappers around the pthread functions or from the 00034 ** corresponding GC wrappers. You may as well use the underlying functions if 00035 ** you prefer. 00036 ** 00037 ** The mutex functions defined here will, when debugging is enabled, check the 00038 ** error codes from the pthread library, and abort on errors which should not 00039 ** occur in a correct program. These are \c EINVAL, \c EDEADLK and \c EPERM, 00040 ** whereas \c EBUSY is reported *by cu_pthread_trylock as a \c cu_false 00041 ** return. */ 00042 00043 /** \name Thread Creation and Initialisation 00044 ** @{ */ 00045 00046 #ifndef CU_IN_DOXYGEN 00047 int GC_pthread_create(pthread_t *, pthread_attr_t const *, 00048 void *(*)(void *), void *); 00049 int GC_pthread_join(pthread_t thread, void **retval); 00050 int GC_pthread_detach(pthread_t thread); 00051 #endif 00052 00053 /** A wrapper around GC_pthread_create (and thus pthread_create), which also 00054 ** runs thread-specific initialisation code registered with \ref 00055 ** cu_register_thread_init or \ref CU_THREADLOCAL_INIT. */ 00056 int cu_pthread_create(pthread_t *thread_out, pthread_attr_t const *attrs, 00057 void *(*cf)(void *), void *cd); 00058 00059 /** Alias for the GC wrapper for pthread_join. */ 00060 #define cu_pthread_join GC_pthread_join 00061 00062 /** Alias for the GC wrapper for pthread_detach. */ 00063 #define cu_pthread_detach GC_pthread_detach 00064 00065 /** If you don't have the chance to use \a cu_pthread_create, call this 00066 ** function as a fall-back to perform thread-local initialisation before using 00067 ** functions which rely on it. This function is idempotent, and it will also 00068 ** arrange for the associated cleaup functions to be called before thread 00069 ** exit. */ 00070 void cu_thread_init(void); 00071 00072 /** Checks to make sure the thread initialisation have been run. */ 00073 void cu_assert_thread_init(void); 00074 00075 /** Calls \a on_entry and arranges for \a on_entry to be called in each newly 00076 ** started thread before other code, and \a on_exit to be called before the 00077 ** thread exits. The \a on_entry callbacks are called in order of 00078 ** registration, and \a on_exit are called in reverse order of registration. 00079 ** Either one may be \ref cu_clop_null if it's not needed. These callbacks 00080 ** only take effect in the main thread and threads which are created with \a 00081 ** cu_pthread_create. */ 00082 void cu_register_thread_init(cu_clop0(on_entry, void), cu_clop0(on_exit, void)); 00083 00084 /** Register \a cleanup to be run at exit or cancellation of the current 00085 ** thread, and before previously registered cleanup functions. */ 00086 void cu_thread_atexit(cu_clop0(cleanup, void)); 00087 00088 /** An error-checking wrapper for pthread_key_create. */ 00089 void cu_pthread_key_create(pthread_key_t *key_out, void (*destructor)(void *)); 00090 00091 /** An error-checking wrapper for pthread_setspecific. */ 00092 void cu_pthread_setspecific(pthread_key_t key, void *data); 00093 00094 /** @} */ 00095 /** \name Mutices 00096 ** @{ */ 00097 00098 typedef pthread_mutex_t cu_mutex_t; 00099 00100 /* CU_MUTEX_INITIALISER is set to error-checking type iff (1) the library 00101 * is configured to enable debugging (2) error-checking mutices are available, 00102 * and (3) the client has defined _GNU_SOURCE. The latter condition is to 00103 * avoild opening other library features which the client does not request, 00104 * and it does not apply to explicitely constructed mutices. */ 00105 #if defined(CUCONF_ERRORCHECK_MUTEX_INITIALIZER) && defined(_GNU_SOURCE) 00106 # define CU_MUTEX_INITIALISER CUCONF_ERRORCHECK_MUTEX_INITIALIZER 00107 #else 00108 # define CU_MUTEX_INITIALISER PTHREAD_MUTEX_INITIALIZER 00109 #endif 00110 #if defined(CUCONF_MUTEX_ERRORCHECK) 00111 # define cu_mutex_init(m) pthread_mutex_init(m, &cuP_mutexattr) 00112 extern pthread_mutexattr_t cuP_mutexattr; 00113 #else 00114 # define cu_mutex_init(m) pthread_mutex_init(m, NULL) 00115 #endif 00116 00117 /** Lock \a m. Aborts on bad usage if debugging is enabled. */ 00118 CU_SINLINE void 00119 cu_mutex_lock(pthread_mutex_t *m) 00120 { 00121 #ifndef CU_NDEBUG 00122 int st = pthread_mutex_lock(m); 00123 if (st != 0) 00124 cu_bugf("Could not lock mutex: %s", strerror(st)); 00125 #else 00126 pthread_mutex_lock(m); 00127 #endif 00128 } 00129 00130 /** Tries to lock \a m without blocking, and return true iff successful. 00131 ** Aborts on bad usage if debugging is enabled. */ 00132 CU_SINLINE cu_bool_t 00133 cu_mutex_trylock(pthread_mutex_t *m) 00134 { 00135 #ifndef CU_NDEBUG 00136 int st = pthread_mutex_trylock(m); 00137 if (st == 0) 00138 return cu_true; 00139 else if (st == EBUSY || st == EDEADLK) 00140 return cu_false; 00141 else 00142 cu_bugf("Could not lock mutex: %s", strerror(st)); 00143 #else 00144 return pthread_mutex_trylock(m) == 0; 00145 #endif 00146 } 00147 00148 /** Unlock \a m. Aborts on bad usage if debugging is enabled. */ 00149 CU_SINLINE void 00150 cu_mutex_unlock(pthread_mutex_t *m) 00151 { 00152 #ifndef CU_NDEBUG 00153 int st = pthread_mutex_unlock(m); 00154 if (st) 00155 cu_bugf("Could not unlock mutex: %s", strerror(st)); 00156 #else 00157 pthread_mutex_unlock(m); 00158 #endif 00159 } 00160 00161 /** @} */ 00162 /** \name Per-Pointer Mutices 00163 ** @{ */ 00164 00165 #ifndef CU_IN_DOXYGEN 00166 #define cuP_PMUTEX_CNT 512 00167 extern cu_mutex_t cuP_pmutex_arr[cuP_PMUTEX_CNT]; 00168 #endif 00169 00170 CU_SINLINE cu_mutex_t *cu_pmutex_mutex(void *ptr) 00171 { return &cuP_pmutex_arr[cu_hash_mix((cu_hash_t)ptr) % cuP_PMUTEX_CNT]; } 00172 00173 /** Lock a mutex indexed by a hash mix of <tt>(cu_hash_t)\a ptr</tt>. These 00174 ** per-pointer mutices must not be used recursively, since several object 00175 ** pointers may have the same mutex. */ 00176 void cu_pmutex_lock(void *ptr); 00177 00178 /** Attempt to lock a mutex indexed by a hash mix of <tt>(cu_hash_t)\a 00179 ** ptr</tt>. See also \ref cu_pmutex_lock. */ 00180 cu_bool_t cu_pmutex_trylock(void *ptr); 00181 00182 /** Unlock a mutex indexed by a hash mix of <tt>(cu_hash_t)\a ptr</tt>. */ 00183 void cu_pmutex_unlock(void *ptr); 00184 00185 /** @} */ 00186 /** @} */ 00187 CU_END_DECLARATIONS 00188 00189 #define cu_thread_create cu_pthread_create 00190 #define cu_thread_join cu_pthread_join 00191 #define cu_thread_detach cu_pthread_detatch 00192 00193 /*!\deprecated Use cu_mutex_init. */ 00194 #define cu_mutex_cct cu_mutex_init 00195 00196 #endif