D-Bus
1.6.8
|
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 /* Whether we have a "monotonic" clock; i.e. a clock not affected by 00040 * changes in system time. 00041 * This is initialized once in check_monotonic_clock below. 00042 * https://bugs.freedesktop.org/show_bug.cgi?id=18121 00043 */ 00044 static dbus_bool_t have_monotonic_clock = 0; 00045 00046 struct DBusRMutex { 00047 pthread_mutex_t lock; 00048 }; 00049 00050 struct DBusCMutex { 00051 pthread_mutex_t lock; 00052 }; 00053 00054 struct DBusCondVar { 00055 pthread_cond_t cond; 00056 }; 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 /* (tmp != 0) is a no-op usage to silence compiler */ 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 /* !DBUS_DISABLE_ASSERT */ 00078 00079 DBusCMutex * 00080 _dbus_platform_cmutex_new (void) 00081 { 00082 DBusCMutex *pmutex; 00083 int result; 00084 00085 pmutex = dbus_new (DBusCMutex, 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 return pmutex; 00102 } 00103 00104 DBusRMutex * 00105 _dbus_platform_rmutex_new (void) 00106 { 00107 DBusRMutex *pmutex; 00108 pthread_mutexattr_t mutexattr; 00109 int result; 00110 00111 pmutex = dbus_new (DBusRMutex, 1); 00112 if (pmutex == NULL) 00113 return NULL; 00114 00115 pthread_mutexattr_init (&mutexattr); 00116 pthread_mutexattr_settype (&mutexattr, PTHREAD_MUTEX_RECURSIVE); 00117 result = pthread_mutex_init (&pmutex->lock, &mutexattr); 00118 pthread_mutexattr_destroy (&mutexattr); 00119 00120 if (result == ENOMEM || result == EAGAIN) 00121 { 00122 dbus_free (pmutex); 00123 return NULL; 00124 } 00125 else 00126 { 00127 PTHREAD_CHECK ("pthread_mutex_init", result); 00128 } 00129 00130 return pmutex; 00131 } 00132 00133 void 00134 _dbus_platform_cmutex_free (DBusCMutex *mutex) 00135 { 00136 PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&mutex->lock)); 00137 dbus_free (mutex); 00138 } 00139 00140 void 00141 _dbus_platform_rmutex_free (DBusRMutex *mutex) 00142 { 00143 PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&mutex->lock)); 00144 dbus_free (mutex); 00145 } 00146 00147 void 00148 _dbus_platform_cmutex_lock (DBusCMutex *mutex) 00149 { 00150 PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&mutex->lock)); 00151 } 00152 00153 void 00154 _dbus_platform_rmutex_lock (DBusRMutex *mutex) 00155 { 00156 PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&mutex->lock)); 00157 } 00158 00159 void 00160 _dbus_platform_cmutex_unlock (DBusCMutex *mutex) 00161 { 00162 PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&mutex->lock)); 00163 } 00164 00165 void 00166 _dbus_platform_rmutex_unlock (DBusRMutex *mutex) 00167 { 00168 PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&mutex->lock)); 00169 } 00170 00171 DBusCondVar * 00172 _dbus_platform_condvar_new (void) 00173 { 00174 DBusCondVar *pcond; 00175 pthread_condattr_t attr; 00176 int result; 00177 00178 pcond = dbus_new (DBusCondVar, 1); 00179 if (pcond == NULL) 00180 return NULL; 00181 00182 pthread_condattr_init (&attr); 00183 #ifdef HAVE_MONOTONIC_CLOCK 00184 if (have_monotonic_clock) 00185 pthread_condattr_setclock (&attr, CLOCK_MONOTONIC); 00186 #endif 00187 00188 result = pthread_cond_init (&pcond->cond, &attr); 00189 pthread_condattr_destroy (&attr); 00190 00191 if (result == EAGAIN || result == ENOMEM) 00192 { 00193 dbus_free (pcond); 00194 return NULL; 00195 } 00196 else 00197 { 00198 PTHREAD_CHECK ("pthread_cond_init", result); 00199 } 00200 00201 return pcond; 00202 } 00203 00204 void 00205 _dbus_platform_condvar_free (DBusCondVar *cond) 00206 { 00207 PTHREAD_CHECK ("pthread_cond_destroy", pthread_cond_destroy (&cond->cond)); 00208 dbus_free (cond); 00209 } 00210 00211 void 00212 _dbus_platform_condvar_wait (DBusCondVar *cond, 00213 DBusCMutex *mutex) 00214 { 00215 PTHREAD_CHECK ("pthread_cond_wait", pthread_cond_wait (&cond->cond, &mutex->lock)); 00216 } 00217 00218 dbus_bool_t 00219 _dbus_platform_condvar_wait_timeout (DBusCondVar *cond, 00220 DBusCMutex *mutex, 00221 int timeout_milliseconds) 00222 { 00223 struct timeval time_now; 00224 struct timespec end_time; 00225 int result; 00226 00227 #ifdef HAVE_MONOTONIC_CLOCK 00228 if (have_monotonic_clock) 00229 { 00230 struct timespec monotonic_timer; 00231 clock_gettime (CLOCK_MONOTONIC,&monotonic_timer); 00232 time_now.tv_sec = monotonic_timer.tv_sec; 00233 time_now.tv_usec = monotonic_timer.tv_nsec / 1000; 00234 } 00235 else 00236 /* This else falls through to gettimeofday */ 00237 #endif 00238 gettimeofday (&time_now, NULL); 00239 00240 end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000; 00241 end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000; 00242 if (end_time.tv_nsec > 1000*1000*1000) 00243 { 00244 end_time.tv_sec += 1; 00245 end_time.tv_nsec -= 1000*1000*1000; 00246 } 00247 00248 result = pthread_cond_timedwait (&cond->cond, &mutex->lock, &end_time); 00249 00250 if (result != ETIMEDOUT) 00251 { 00252 PTHREAD_CHECK ("pthread_cond_timedwait", result); 00253 } 00254 00255 /* return true if we did not time out */ 00256 return result != ETIMEDOUT; 00257 } 00258 00259 void 00260 _dbus_platform_condvar_wake_one (DBusCondVar *cond) 00261 { 00262 PTHREAD_CHECK ("pthread_cond_signal", pthread_cond_signal (&cond->cond)); 00263 } 00264 00265 static void 00266 check_monotonic_clock (void) 00267 { 00268 #ifdef HAVE_MONOTONIC_CLOCK 00269 struct timespec dummy; 00270 if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0) 00271 have_monotonic_clock = TRUE; 00272 #endif 00273 } 00274 00275 dbus_bool_t 00276 _dbus_threads_init_platform_specific (void) 00277 { 00278 /* These have static variables, and we need to handle both the case 00279 * where dbus_threads_init() has been called and when it hasn't; 00280 * so initialize them before any threads are allowed to enter. 00281 */ 00282 check_monotonic_clock (); 00283 (void) _dbus_check_setuid (); 00284 return dbus_threads_init (NULL); 00285 }