Main Page | Modules | Namespace List | Class Hierarchy | Data Structures | Directories | File List | Namespace Members | Data Fields | Related Pages

dbus-threads.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-threads.h  D-BUS threads handling
00003  *
00004  * Copyright (C) 2002, 2003 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 #include "dbus-threads.h"
00024 #include "dbus-internals.h"
00025 #include "dbus-threads-internal.h"
00026 
00027 static DBusThreadFunctions thread_functions =
00028 {
00029   0,
00030   NULL, NULL, NULL, NULL,
00031   NULL, NULL, NULL, NULL, NULL,
00032 
00033   NULL, NULL, NULL, NULL,
00034   NULL, NULL, NULL, NULL
00035 };
00036 static int thread_init_generation = 0;
00037 
00039 #define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
00040 
00042 #define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
00043 
00062 DBusMutex*
00063 _dbus_mutex_new (void)
00064 {
00065   if (thread_functions.mutex_new)
00066     return (* thread_functions.mutex_new) ();
00067   else
00068     return _DBUS_DUMMY_MUTEX;
00069 }
00070 
00075 void
00076 _dbus_mutex_free (DBusMutex *mutex)
00077 {
00078   if (mutex && thread_functions.mutex_free)
00079     (* thread_functions.mutex_free) (mutex);
00080 }
00081 
00088 dbus_bool_t
00089 _dbus_mutex_lock (DBusMutex *mutex)
00090 {
00091   if (mutex && thread_functions.mutex_lock)
00092     return (* thread_functions.mutex_lock) (mutex);
00093   else
00094     return TRUE;
00095 }
00096 
00102 dbus_bool_t
00103 _dbus_mutex_unlock (DBusMutex *mutex)
00104 {
00105   if (mutex && thread_functions.mutex_unlock)
00106     return (* thread_functions.mutex_unlock) (mutex);
00107   else
00108     return TRUE;
00109 }
00110 
00119 DBusCondVar *
00120 _dbus_condvar_new (void)
00121 {
00122   if (thread_functions.condvar_new)
00123     return (* thread_functions.condvar_new) ();
00124   else
00125     return _DBUS_DUMMY_CONDVAR;
00126 }
00127 
00132 void
00133 _dbus_condvar_free (DBusCondVar *cond)
00134 {
00135   if (cond && thread_functions.condvar_free)
00136     (* thread_functions.condvar_free) (cond);
00137 }
00138 
00145 void
00146 _dbus_condvar_wait (DBusCondVar *cond,
00147                     DBusMutex   *mutex)
00148 {
00149   if (cond && mutex && thread_functions.condvar_wait)
00150     (* thread_functions.condvar_wait) (cond, mutex);
00151 }
00152 
00165 dbus_bool_t
00166 _dbus_condvar_wait_timeout (DBusCondVar               *cond,
00167                             DBusMutex                 *mutex,
00168                             int                        timeout_milliseconds)
00169 {
00170   if (cond && mutex && thread_functions.condvar_wait)
00171     return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
00172   else
00173     return TRUE;
00174 }
00175 
00181 void
00182 _dbus_condvar_wake_one (DBusCondVar *cond)
00183 {
00184   if (cond && thread_functions.condvar_wake_one)
00185     (* thread_functions.condvar_wake_one) (cond);
00186 }
00187 
00193 void
00194 _dbus_condvar_wake_all (DBusCondVar *cond)
00195 {
00196   if (cond && thread_functions.condvar_wake_all)
00197     (* thread_functions.condvar_wake_all) (cond);
00198 }
00199 
00200 static void
00201 shutdown_global_locks (void *data)
00202 {
00203   DBusMutex ***locks = data;
00204   int i;
00205 
00206   i = 0;
00207   while (i < _DBUS_N_GLOBAL_LOCKS)
00208     {
00209       _dbus_mutex_free (*(locks[i]));
00210       *(locks[i]) = NULL;
00211       ++i;
00212     }
00213   
00214   dbus_free (locks);
00215 }
00216 
00217 static dbus_bool_t
00218 init_global_locks (void)
00219 {
00220   int i;
00221   DBusMutex ***dynamic_global_locks;
00222   
00223   DBusMutex **global_locks[] = {
00224 #define LOCK_ADDR(name) (& _dbus_lock_##name)
00225     LOCK_ADDR (list),
00226     LOCK_ADDR (connection_slots),
00227     LOCK_ADDR (pending_call_slots),
00228     LOCK_ADDR (server_slots),
00229     LOCK_ADDR (message_slots),
00230     LOCK_ADDR (atomic),
00231     LOCK_ADDR (bus),
00232     LOCK_ADDR (shutdown_funcs),
00233     LOCK_ADDR (system_users),
00234     LOCK_ADDR (message_cache),
00235     LOCK_ADDR (shared_connections)
00236 #undef LOCK_ADDR
00237   };
00238 
00239   _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
00240                 _DBUS_N_GLOBAL_LOCKS);
00241 
00242   i = 0;
00243   
00244   dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
00245   if (dynamic_global_locks == NULL)
00246     goto failed;
00247   
00248   while (i < _DBUS_N_ELEMENTS (global_locks))
00249     {
00250       *global_locks[i] = _dbus_mutex_new ();
00251       
00252       if (*global_locks[i] == NULL)
00253         goto failed;
00254 
00255       dynamic_global_locks[i] = global_locks[i];
00256 
00257       ++i;
00258     }
00259   
00260   if (!_dbus_register_shutdown_func (shutdown_global_locks,
00261                                      dynamic_global_locks))
00262     goto failed;
00263   
00264   return TRUE;
00265 
00266  failed:
00267   dbus_free (dynamic_global_locks);
00268                                      
00269   for (i = i - 1; i >= 0; i--)
00270     {
00271       _dbus_mutex_free (*global_locks[i]);
00272       *global_locks[i] = NULL;
00273     }
00274   return FALSE;
00275 }
00276  /* end of internals */
00278 
00305 dbus_bool_t
00306 dbus_threads_init (const DBusThreadFunctions *functions)
00307 {
00308   _dbus_assert (functions != NULL);
00309 
00310   /* these base functions are required. Future additions to
00311    * DBusThreadFunctions may be optional.
00312    */
00313   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK);
00314   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK);
00315   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK);
00316   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK);
00317   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
00318   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
00319   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
00320   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
00321   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
00322   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
00323   _dbus_assert (functions->mutex_new != NULL);
00324   _dbus_assert (functions->mutex_free != NULL);
00325   _dbus_assert (functions->mutex_lock != NULL);
00326   _dbus_assert (functions->mutex_unlock != NULL);
00327   _dbus_assert (functions->condvar_new != NULL);
00328   _dbus_assert (functions->condvar_free != NULL);
00329   _dbus_assert (functions->condvar_wait != NULL);
00330   _dbus_assert (functions->condvar_wait_timeout != NULL);
00331   _dbus_assert (functions->condvar_wake_one != NULL);
00332   _dbus_assert (functions->condvar_wake_all != NULL);
00333 
00334   /* Check that all bits in the mask actually are valid mask bits.
00335    * ensures people won't write code that breaks when we add
00336    * new bits.
00337    */
00338   _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
00339 
00340   if (thread_init_generation != _dbus_current_generation)
00341     thread_functions.mask = 0; /* allow re-init in new generation */
00342   
00343   if (thread_functions.mask != 0)
00344     {
00345       /* Silently allow multiple init if the functions are the same ones.
00346        * Well, we only bother checking two of them, just out of laziness.
00347        */
00348       if (thread_functions.mask == functions->mask &&
00349           thread_functions.mutex_new == functions->mutex_new &&
00350           thread_functions.condvar_new == functions->condvar_new)
00351         {
00352           return TRUE;
00353         }
00354       else
00355         {
00356           _dbus_warn ("dbus_threads_init() called twice with two different sets of functions\n");
00357           return FALSE;
00358         }
00359     }
00360   
00361   thread_functions.mutex_new = functions->mutex_new;
00362   thread_functions.mutex_free = functions->mutex_free;
00363   thread_functions.mutex_lock = functions->mutex_lock;
00364   thread_functions.mutex_unlock = functions->mutex_unlock;
00365   
00366   thread_functions.condvar_new = functions->condvar_new;
00367   thread_functions.condvar_free = functions->condvar_free;
00368   thread_functions.condvar_wait = functions->condvar_wait;
00369   thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
00370   thread_functions.condvar_wake_one = functions->condvar_wake_one;
00371   thread_functions.condvar_wake_all = functions->condvar_wake_all;
00372   
00373   thread_functions.mask = functions->mask;
00374 
00375   if (!init_global_locks ())
00376     return FALSE;
00377 
00378   thread_init_generation = _dbus_current_generation;
00379   
00380   return TRUE;
00381 }
00382 
00385 #ifdef DBUS_BUILD_TESTS
00386 
00387 typedef struct DBusFakeMutex DBusFakeMutex;
00389 struct DBusFakeMutex
00390 {
00391   dbus_bool_t locked; 
00392 };      
00393 
00394 static DBusMutex *  dbus_fake_mutex_new            (void);
00395 static void         dbus_fake_mutex_free           (DBusMutex   *mutex);
00396 static dbus_bool_t  dbus_fake_mutex_lock           (DBusMutex   *mutex);
00397 static dbus_bool_t  dbus_fake_mutex_unlock         (DBusMutex   *mutex);
00398 static DBusCondVar* dbus_fake_condvar_new          (void);
00399 static void         dbus_fake_condvar_free         (DBusCondVar *cond);
00400 static void         dbus_fake_condvar_wait         (DBusCondVar *cond,
00401                                                     DBusMutex   *mutex);
00402 static dbus_bool_t  dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
00403                                                     DBusMutex   *mutex,
00404                                                     int          timeout_msec);
00405 static void         dbus_fake_condvar_wake_one     (DBusCondVar *cond);
00406 static void         dbus_fake_condvar_wake_all     (DBusCondVar *cond);
00407 
00408 
00409 static const DBusThreadFunctions fake_functions =
00410 {
00411   DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
00412   DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
00413   DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
00414   DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
00415   DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
00416   DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
00417   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
00418   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
00419   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
00420   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
00421   dbus_fake_mutex_new,
00422   dbus_fake_mutex_free,
00423   dbus_fake_mutex_lock,
00424   dbus_fake_mutex_unlock,
00425   dbus_fake_condvar_new,
00426   dbus_fake_condvar_free,
00427   dbus_fake_condvar_wait,
00428   dbus_fake_condvar_wait_timeout,
00429   dbus_fake_condvar_wake_one,
00430   dbus_fake_condvar_wake_all
00431 };
00432 
00433 static DBusMutex *
00434 dbus_fake_mutex_new (void)
00435 {
00436   DBusFakeMutex *mutex;
00437 
00438   mutex = dbus_new0 (DBusFakeMutex, 1);
00439 
00440   return (DBusMutex *)mutex;
00441 }
00442 
00443 static void
00444 dbus_fake_mutex_free (DBusMutex *mutex)
00445 {
00446   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
00447 
00448   _dbus_assert (!fake->locked);
00449   
00450   dbus_free (fake);
00451 }
00452 
00453 static dbus_bool_t
00454 dbus_fake_mutex_lock (DBusMutex *mutex)
00455 {
00456   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
00457 
00458   _dbus_assert (!fake->locked);
00459 
00460   fake->locked = TRUE;
00461   
00462   return TRUE;
00463 }
00464 
00465 static dbus_bool_t
00466 dbus_fake_mutex_unlock (DBusMutex *mutex)
00467 {
00468   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
00469 
00470   _dbus_assert (fake->locked);
00471 
00472   fake->locked = FALSE;
00473   
00474   return TRUE;
00475 }
00476 
00477 static DBusCondVar*
00478 dbus_fake_condvar_new (void)
00479 {
00480   return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
00481 }
00482 
00483 static void
00484 dbus_fake_condvar_free (DBusCondVar *cond)
00485 {
00486   dbus_free (cond);
00487 }
00488 
00489 static void
00490 dbus_fake_condvar_wait (DBusCondVar *cond,
00491                         DBusMutex   *mutex)
00492 {
00493   
00494 }
00495 
00496 static dbus_bool_t
00497 dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
00498                                 DBusMutex   *mutex,
00499                                 int         timeout_msec)
00500 {
00501   return TRUE;
00502 }
00503 
00504 static void
00505 dbus_fake_condvar_wake_one (DBusCondVar *cond)
00506 {
00507 
00508 }
00509 
00510 static void
00511 dbus_fake_condvar_wake_all (DBusCondVar *cond)
00512 {
00513 
00514 }
00515 
00516 dbus_bool_t
00517 _dbus_threads_init_debug (void)
00518 {
00519   return dbus_threads_init (&fake_functions);
00520 }
00521 
00522 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Sep 13 01:28:07 2005 for D-BUS by  doxygen 1.4.4