D-Bus
1.10.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-sysdeps-pthread.c Implements threads using pthreads (internal to libdbus) 00003 * 00004 * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 #ifdef HAVE_MONOTONIC_CLOCK 00040 /* Whether we have a "monotonic" clock; i.e. a clock not affected by 00041 * changes in system time. 00042 * This is initialized once in check_monotonic_clock below. 00043 * https://bugs.freedesktop.org/show_bug.cgi?id=18121 00044 */ 00045 static dbus_bool_t have_monotonic_clock = 0; 00046 #endif 00047 00048 struct DBusRMutex { 00049 pthread_mutex_t lock; 00050 }; 00051 00052 struct DBusCMutex { 00053 pthread_mutex_t lock; 00054 }; 00055 00056 struct DBusCondVar { 00057 pthread_cond_t cond; 00058 }; 00059 00060 #define DBUS_MUTEX(m) ((DBusMutex*) m) 00061 #define DBUS_MUTEX_PTHREAD(m) ((DBusMutexPThread*) m) 00062 00063 #define DBUS_COND_VAR(c) ((DBusCondVar*) c) 00064 #define DBUS_COND_VAR_PTHREAD(c) ((DBusCondVarPThread*) c) 00065 00066 00067 #ifdef DBUS_DISABLE_ASSERT 00068 /* (tmp != 0) is a no-op usage to silence compiler */ 00069 #define PTHREAD_CHECK(func_name, result_or_call) \ 00070 do { int tmp = (result_or_call); if (tmp != 0) {;} } while (0) 00071 #else 00072 #define PTHREAD_CHECK(func_name, result_or_call) do { \ 00073 int tmp = (result_or_call); \ 00074 if (tmp != 0) { \ 00075 _dbus_warn_check_failed ("pthread function %s failed with %d %s in %s\n", \ 00076 func_name, tmp, strerror(tmp), _DBUS_FUNCTION_NAME); \ 00077 } \ 00078 } while (0) 00079 #endif /* !DBUS_DISABLE_ASSERT */ 00080 00081 DBusCMutex * 00082 _dbus_platform_cmutex_new (void) 00083 { 00084 DBusCMutex *pmutex; 00085 int result; 00086 00087 pmutex = dbus_new (DBusCMutex, 1); 00088 if (pmutex == NULL) 00089 return NULL; 00090 00091 result = pthread_mutex_init (&pmutex->lock, NULL); 00092 00093 if (result == ENOMEM || result == EAGAIN) 00094 { 00095 dbus_free (pmutex); 00096 return NULL; 00097 } 00098 else 00099 { 00100 PTHREAD_CHECK ("pthread_mutex_init", result); 00101 } 00102 00103 return pmutex; 00104 } 00105 00106 DBusRMutex * 00107 _dbus_platform_rmutex_new (void) 00108 { 00109 DBusRMutex *pmutex; 00110 pthread_mutexattr_t mutexattr; 00111 int result; 00112 00113 pmutex = dbus_new (DBusRMutex, 1); 00114 if (pmutex == NULL) 00115 return NULL; 00116 00117 pthread_mutexattr_init (&mutexattr); 00118 pthread_mutexattr_settype (&mutexattr, PTHREAD_MUTEX_RECURSIVE); 00119 result = pthread_mutex_init (&pmutex->lock, &mutexattr); 00120 pthread_mutexattr_destroy (&mutexattr); 00121 00122 if (result == ENOMEM || result == EAGAIN) 00123 { 00124 dbus_free (pmutex); 00125 return NULL; 00126 } 00127 else 00128 { 00129 PTHREAD_CHECK ("pthread_mutex_init", result); 00130 } 00131 00132 return pmutex; 00133 } 00134 00135 void 00136 _dbus_platform_cmutex_free (DBusCMutex *mutex) 00137 { 00138 PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&mutex->lock)); 00139 dbus_free (mutex); 00140 } 00141 00142 void 00143 _dbus_platform_rmutex_free (DBusRMutex *mutex) 00144 { 00145 PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&mutex->lock)); 00146 dbus_free (mutex); 00147 } 00148 00149 void 00150 _dbus_platform_cmutex_lock (DBusCMutex *mutex) 00151 { 00152 PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&mutex->lock)); 00153 } 00154 00155 void 00156 _dbus_platform_rmutex_lock (DBusRMutex *mutex) 00157 { 00158 PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&mutex->lock)); 00159 } 00160 00161 void 00162 _dbus_platform_cmutex_unlock (DBusCMutex *mutex) 00163 { 00164 PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&mutex->lock)); 00165 } 00166 00167 void 00168 _dbus_platform_rmutex_unlock (DBusRMutex *mutex) 00169 { 00170 PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&mutex->lock)); 00171 } 00172 00173 DBusCondVar * 00174 _dbus_platform_condvar_new (void) 00175 { 00176 DBusCondVar *pcond; 00177 pthread_condattr_t attr; 00178 int result; 00179 00180 pcond = dbus_new (DBusCondVar, 1); 00181 if (pcond == NULL) 00182 return NULL; 00183 00184 pthread_condattr_init (&attr); 00185 #ifdef HAVE_MONOTONIC_CLOCK 00186 if (have_monotonic_clock) 00187 pthread_condattr_setclock (&attr, CLOCK_MONOTONIC); 00188 #endif 00189 00190 result = pthread_cond_init (&pcond->cond, &attr); 00191 pthread_condattr_destroy (&attr); 00192 00193 if (result == EAGAIN || result == ENOMEM) 00194 { 00195 dbus_free (pcond); 00196 return NULL; 00197 } 00198 else 00199 { 00200 PTHREAD_CHECK ("pthread_cond_init", result); 00201 } 00202 00203 return pcond; 00204 } 00205 00206 void 00207 _dbus_platform_condvar_free (DBusCondVar *cond) 00208 { 00209 PTHREAD_CHECK ("pthread_cond_destroy", pthread_cond_destroy (&cond->cond)); 00210 dbus_free (cond); 00211 } 00212 00213 void 00214 _dbus_platform_condvar_wait (DBusCondVar *cond, 00215 DBusCMutex *mutex) 00216 { 00217 PTHREAD_CHECK ("pthread_cond_wait", pthread_cond_wait (&cond->cond, &mutex->lock)); 00218 } 00219 00220 dbus_bool_t 00221 _dbus_platform_condvar_wait_timeout (DBusCondVar *cond, 00222 DBusCMutex *mutex, 00223 int timeout_milliseconds) 00224 { 00225 struct timeval time_now; 00226 struct timespec end_time; 00227 int result; 00228 00229 #ifdef HAVE_MONOTONIC_CLOCK 00230 if (have_monotonic_clock) 00231 { 00232 struct timespec monotonic_timer; 00233 clock_gettime (CLOCK_MONOTONIC,&monotonic_timer); 00234 time_now.tv_sec = monotonic_timer.tv_sec; 00235 time_now.tv_usec = monotonic_timer.tv_nsec / 1000; 00236 } 00237 else 00238 /* This else falls through to gettimeofday */ 00239 #endif 00240 gettimeofday (&time_now, NULL); 00241 00242 end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000; 00243 end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000; 00244 if (end_time.tv_nsec > 1000*1000*1000) 00245 { 00246 end_time.tv_sec += 1; 00247 end_time.tv_nsec -= 1000*1000*1000; 00248 } 00249 00250 result = pthread_cond_timedwait (&cond->cond, &mutex->lock, &end_time); 00251 00252 if (result != ETIMEDOUT) 00253 { 00254 PTHREAD_CHECK ("pthread_cond_timedwait", result); 00255 } 00256 00257 /* return true if we did not time out */ 00258 return result != ETIMEDOUT; 00259 } 00260 00261 void 00262 _dbus_platform_condvar_wake_one (DBusCondVar *cond) 00263 { 00264 PTHREAD_CHECK ("pthread_cond_signal", pthread_cond_signal (&cond->cond)); 00265 } 00266 00267 static void 00268 check_monotonic_clock (void) 00269 { 00270 #ifdef HAVE_MONOTONIC_CLOCK 00271 struct timespec dummy; 00272 if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0) 00273 have_monotonic_clock = TRUE; 00274 #endif 00275 } 00276 00277 dbus_bool_t 00278 _dbus_threads_init_platform_specific (void) 00279 { 00280 /* These have static variables, and we need to handle both the case 00281 * where dbus_threads_init() has been called and when it hasn't; 00282 * so initialize them before any threads are allowed to enter. 00283 */ 00284 check_monotonic_clock (); 00285 (void) _dbus_check_setuid (); 00286 00287 return TRUE; 00288 } 00289 00290 static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER; 00291 00292 void 00293 _dbus_threads_lock_platform_specific (void) 00294 { 00295 pthread_mutex_lock (&init_mutex); 00296 } 00297 00298 void 00299 _dbus_threads_unlock_platform_specific (void) 00300 { 00301 pthread_mutex_unlock (&init_mutex); 00302 }