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