00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "dbus-internals.h"
00025 #include "dbus-sysdeps.h"
00026 #include "dbus-threads.h"
00027
00028 #include <sys/time.h>
00029 #include <pthread.h>
00030 #include <string.h>
00031
00032 #ifdef HAVE_ERRNO_H
00033 #include <errno.h>
00034 #endif
00035
00036 #include <config.h>
00037
00038
00039
00040
00041
00042
00043 static dbus_bool_t have_monotonic_clock = 0;
00044
00045 typedef struct {
00046 pthread_mutex_t lock;
00047 volatile int count;
00048 volatile pthread_t holder;
00052 } DBusMutexPThread;
00053
00054 typedef struct {
00055 pthread_cond_t cond;
00056 } DBusCondVarPThread;
00057
00058 #define DBUS_MUTEX(m) ((DBusMutex*) m)
00059 #define DBUS_MUTEX_PTHREAD(m) ((DBusMutexPThread*) m)
00060
00061 #define DBUS_COND_VAR(c) ((DBusCondVar*) c)
00062 #define DBUS_COND_VAR_PTHREAD(c) ((DBusCondVarPThread*) c)
00063
00064
00065 #ifdef DBUS_DISABLE_ASSERT
00066
00067 #define PTHREAD_CHECK(func_name, result_or_call) \
00068 do { int tmp = (result_or_call); if (tmp != 0) {;} } while (0)
00069 #else
00070 #define PTHREAD_CHECK(func_name, result_or_call) do { \
00071 int tmp = (result_or_call); \
00072 if (tmp != 0) { \
00073 _dbus_warn_check_failed ("pthread function %s failed with %d %s in %s\n", \
00074 func_name, tmp, strerror(tmp), _DBUS_FUNCTION_NAME); \
00075 } \
00076 } while (0)
00077 #endif
00078
00079 static DBusMutex*
00080 _dbus_pthread_mutex_new (void)
00081 {
00082 DBusMutexPThread *pmutex;
00083 int result;
00084
00085 pmutex = dbus_new (DBusMutexPThread, 1);
00086 if (pmutex == NULL)
00087 return NULL;
00088
00089 result = pthread_mutex_init (&pmutex->lock, NULL);
00090
00091 if (result == ENOMEM || result == EAGAIN)
00092 {
00093 dbus_free (pmutex);
00094 return NULL;
00095 }
00096 else
00097 {
00098 PTHREAD_CHECK ("pthread_mutex_init", result);
00099 }
00100
00101
00102 pmutex->count = 0;
00103
00104
00105
00106
00107
00108
00109 return DBUS_MUTEX (pmutex);
00110 }
00111
00112 static void
00113 _dbus_pthread_mutex_free (DBusMutex *mutex)
00114 {
00115 DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
00116
00117 _dbus_assert (pmutex->count == 0);
00118
00119 PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&pmutex->lock));
00120
00121 dbus_free (pmutex);
00122 }
00123
00124 static void
00125 _dbus_pthread_mutex_lock (DBusMutex *mutex)
00126 {
00127 DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
00128 pthread_t self = pthread_self ();
00129
00130
00131
00132
00133
00134
00135
00136
00137 if (pmutex->count == 0)
00138 {
00139
00140
00141 PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&pmutex->lock));
00142
00143
00144
00145
00146
00147 _dbus_assert (pmutex->count == 0);
00148
00149 pmutex->holder = self;
00150 pmutex->count = 1;
00151 }
00152 else
00153 {
00154
00155
00156
00157
00158
00159
00160 if (pthread_equal (pmutex->holder, self))
00161 {
00162
00163 _dbus_assert (pmutex->count > 0);
00164 }
00165 else
00166 {
00167
00168 PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&pmutex->lock));
00169 pmutex->holder = self;
00170 _dbus_assert (pmutex->count == 0);
00171 }
00172
00173 pmutex->count += 1;
00174 }
00175 }
00176
00177 static void
00178 _dbus_pthread_mutex_unlock (DBusMutex *mutex)
00179 {
00180 DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
00181
00182 _dbus_assert (pmutex->count > 0);
00183
00184 pmutex->count -= 1;
00185
00186 if (pmutex->count == 0)
00187 PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&pmutex->lock));
00188
00189
00190 }
00191
00192 static DBusCondVar *
00193 _dbus_pthread_condvar_new (void)
00194 {
00195 DBusCondVarPThread *pcond;
00196 pthread_condattr_t attr;
00197 int result;
00198
00199 pcond = dbus_new (DBusCondVarPThread, 1);
00200 if (pcond == NULL)
00201 return NULL;
00202
00203 pthread_condattr_init (&attr);
00204 #ifdef HAVE_MONOTONIC_CLOCK
00205 if (have_monotonic_clock)
00206 pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
00207 #endif
00208
00209 result = pthread_cond_init (&pcond->cond, &attr);
00210 pthread_condattr_destroy (&attr);
00211
00212 if (result == EAGAIN || result == ENOMEM)
00213 {
00214 dbus_free (pcond);
00215 return NULL;
00216 }
00217 else
00218 {
00219 PTHREAD_CHECK ("pthread_cond_init", result);
00220 }
00221
00222 return DBUS_COND_VAR (pcond);
00223 }
00224
00225 static void
00226 _dbus_pthread_condvar_free (DBusCondVar *cond)
00227 {
00228 DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
00229
00230 PTHREAD_CHECK ("pthread_cond_destroy", pthread_cond_destroy (&pcond->cond));
00231
00232 dbus_free (pcond);
00233 }
00234
00235 static void
00236 _dbus_pthread_condvar_wait (DBusCondVar *cond,
00237 DBusMutex *mutex)
00238 {
00239 DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
00240 DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
00241 int old_count;
00242
00243 _dbus_assert (pmutex->count > 0);
00244 _dbus_assert (pthread_equal (pmutex->holder, pthread_self ()));
00245
00246 old_count = pmutex->count;
00247 pmutex->count = 0;
00248 PTHREAD_CHECK ("pthread_cond_wait", pthread_cond_wait (&pcond->cond, &pmutex->lock));
00249 _dbus_assert (pmutex->count == 0);
00250 pmutex->count = old_count;
00251 pmutex->holder = pthread_self();
00252 }
00253
00254 static dbus_bool_t
00255 _dbus_pthread_condvar_wait_timeout (DBusCondVar *cond,
00256 DBusMutex *mutex,
00257 int timeout_milliseconds)
00258 {
00259 DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
00260 DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
00261 struct timeval time_now;
00262 struct timespec end_time;
00263 int result;
00264 int old_count;
00265
00266 _dbus_assert (pmutex->count > 0);
00267 _dbus_assert (pthread_equal (pmutex->holder, pthread_self ()));
00268
00269 #ifdef HAVE_MONOTONIC_CLOCK
00270 if (have_monotonic_clock)
00271 {
00272 struct timespec monotonic_timer;
00273 clock_gettime (CLOCK_MONOTONIC,&monotonic_timer);
00274 time_now.tv_sec = monotonic_timer.tv_sec;
00275 time_now.tv_usec = monotonic_timer.tv_nsec / 1000;
00276 }
00277 else
00278
00279 #endif
00280 gettimeofday (&time_now, NULL);
00281
00282 end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000;
00283 end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000;
00284 if (end_time.tv_nsec > 1000*1000*1000)
00285 {
00286 end_time.tv_sec += 1;
00287 end_time.tv_nsec -= 1000*1000*1000;
00288 }
00289
00290 old_count = pmutex->count;
00291 pmutex->count = 0;
00292 result = pthread_cond_timedwait (&pcond->cond, &pmutex->lock, &end_time);
00293
00294 if (result != ETIMEDOUT)
00295 {
00296 PTHREAD_CHECK ("pthread_cond_timedwait", result);
00297 }
00298
00299 _dbus_assert (pmutex->count == 0);
00300 pmutex->count = old_count;
00301 pmutex->holder = pthread_self();
00302
00303
00304 return result != ETIMEDOUT;
00305 }
00306
00307 static void
00308 _dbus_pthread_condvar_wake_one (DBusCondVar *cond)
00309 {
00310 DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
00311
00312 PTHREAD_CHECK ("pthread_cond_signal", pthread_cond_signal (&pcond->cond));
00313 }
00314
00315 static void
00316 _dbus_pthread_condvar_wake_all (DBusCondVar *cond)
00317 {
00318 DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
00319
00320 PTHREAD_CHECK ("pthread_cond_broadcast", pthread_cond_broadcast (&pcond->cond));
00321 }
00322
00323 static const DBusThreadFunctions pthread_functions =
00324 {
00325 DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK |
00326 DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK |
00327 DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK |
00328 DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK |
00329 DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
00330 DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
00331 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
00332 DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
00333 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
00334 DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
00335 NULL, NULL, NULL, NULL,
00336 _dbus_pthread_condvar_new,
00337 _dbus_pthread_condvar_free,
00338 _dbus_pthread_condvar_wait,
00339 _dbus_pthread_condvar_wait_timeout,
00340 _dbus_pthread_condvar_wake_one,
00341 _dbus_pthread_condvar_wake_all,
00342 _dbus_pthread_mutex_new,
00343 _dbus_pthread_mutex_free,
00344 _dbus_pthread_mutex_lock,
00345 _dbus_pthread_mutex_unlock
00346 };
00347
00348 static void
00349 check_monotonic_clock (void)
00350 {
00351 #ifdef HAVE_MONOTONIC_CLOCK
00352 struct timespec dummy;
00353 if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0)
00354 have_monotonic_clock = TRUE;
00355 #endif
00356 }
00357
00358 dbus_bool_t
00359 _dbus_threads_init_platform_specific (void)
00360 {
00361 check_monotonic_clock ();
00362 return dbus_threads_init (&pthread_functions);
00363 }