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