D-Bus 1.4.6

dbus-threads.c

00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-threads.h  D-Bus threads handling
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 #include <config.h>
00024 #include "dbus-threads.h"
00025 #include "dbus-internals.h"
00026 #include "dbus-threads-internal.h"
00027 #include "dbus-list.h"
00028 
00029 static DBusThreadFunctions thread_functions =
00030 {
00031   0,
00032   NULL, NULL, NULL, NULL, NULL,
00033   NULL, NULL, NULL, NULL, NULL,
00034   NULL, NULL, NULL, NULL,
00035   
00036   NULL, NULL, NULL, NULL
00037 };
00038 
00039 static int thread_init_generation = 0;
00040  
00041 static DBusList *uninitialized_mutex_list = NULL;
00042 static DBusList *uninitialized_condvar_list = NULL;
00043 
00045 #define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
00046 
00048 #define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
00049 
00068 DBusMutex*
00069 _dbus_mutex_new (void)
00070 {
00071   if (thread_functions.recursive_mutex_new)
00072     return (* thread_functions.recursive_mutex_new) ();
00073   else if (thread_functions.mutex_new)
00074     return (* thread_functions.mutex_new) ();
00075   else
00076     return _DBUS_DUMMY_MUTEX;
00077 }
00078 
00088 void
00089 _dbus_mutex_new_at_location (DBusMutex **location_p)
00090 {
00091   _dbus_assert (location_p != NULL);
00092 
00093   *location_p = _dbus_mutex_new();
00094 
00095   if (thread_init_generation != _dbus_current_generation && *location_p)
00096     {
00097       if (!_dbus_list_append (&uninitialized_mutex_list, location_p))
00098         {
00099           _dbus_mutex_free (*location_p);
00100           *location_p = NULL;
00101         }
00102     }
00103 }
00104 
00109 void
00110 _dbus_mutex_free (DBusMutex *mutex)
00111 {
00112   if (mutex)
00113     {
00114       if (mutex && thread_functions.recursive_mutex_free)
00115         (* thread_functions.recursive_mutex_free) (mutex);
00116       else if (mutex && thread_functions.mutex_free)
00117         (* thread_functions.mutex_free) (mutex);
00118     }
00119 }
00120 
00126 void
00127 _dbus_mutex_free_at_location (DBusMutex **location_p)
00128 {
00129   if (location_p)
00130     {
00131       if (thread_init_generation != _dbus_current_generation)
00132         _dbus_list_remove (&uninitialized_mutex_list, location_p);
00133 
00134       _dbus_mutex_free (*location_p);
00135     }
00136 }
00137 
00143 void
00144 _dbus_mutex_lock (DBusMutex *mutex)
00145 {
00146   if (mutex) 
00147     {
00148       if (thread_functions.recursive_mutex_lock)
00149         (* thread_functions.recursive_mutex_lock) (mutex);
00150       else if (thread_functions.mutex_lock)
00151         (* thread_functions.mutex_lock) (mutex);
00152     }
00153 }
00154 
00160 void
00161 _dbus_mutex_unlock (DBusMutex *mutex)
00162 {
00163   if (mutex)
00164     {
00165       if (thread_functions.recursive_mutex_unlock)
00166         (* thread_functions.recursive_mutex_unlock) (mutex);
00167       else if (thread_functions.mutex_unlock)
00168         (* thread_functions.mutex_unlock) (mutex);
00169     }
00170 }
00171 
00180 DBusCondVar *
00181 _dbus_condvar_new (void)
00182 {
00183   if (thread_functions.condvar_new)
00184     return (* thread_functions.condvar_new) ();
00185   else
00186     return _DBUS_DUMMY_CONDVAR;
00187 }
00188 
00189 
00200 void 
00201 _dbus_condvar_new_at_location (DBusCondVar **location_p)
00202 {
00203   *location_p = _dbus_condvar_new();
00204 
00205   if (thread_init_generation != _dbus_current_generation && *location_p)
00206     {
00207       if (!_dbus_list_append (&uninitialized_condvar_list, location_p))
00208         {
00209           _dbus_condvar_free (*location_p);
00210           *location_p = NULL;
00211         }
00212     }
00213 }
00214 
00215 
00220 void
00221 _dbus_condvar_free (DBusCondVar *cond)
00222 {
00223   if (cond && thread_functions.condvar_free)
00224     (* thread_functions.condvar_free) (cond);
00225 }
00226 
00232 void
00233 _dbus_condvar_free_at_location (DBusCondVar **location_p)
00234 {
00235   if (location_p)
00236     {
00237       if (thread_init_generation != _dbus_current_generation)
00238         _dbus_list_remove (&uninitialized_condvar_list, location_p);
00239 
00240       _dbus_condvar_free (*location_p);
00241     }
00242 }
00243 
00250 void
00251 _dbus_condvar_wait (DBusCondVar *cond,
00252                     DBusMutex   *mutex)
00253 {
00254   if (cond && mutex && thread_functions.condvar_wait)
00255     (* thread_functions.condvar_wait) (cond, mutex);
00256 }
00257 
00269 dbus_bool_t
00270 _dbus_condvar_wait_timeout (DBusCondVar               *cond,
00271                             DBusMutex                 *mutex,
00272                             int                        timeout_milliseconds)
00273 {
00274   if (cond && mutex && thread_functions.condvar_wait)
00275     return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
00276   else
00277     return TRUE;
00278 }
00279 
00285 void
00286 _dbus_condvar_wake_one (DBusCondVar *cond)
00287 {
00288   if (cond && thread_functions.condvar_wake_one)
00289     (* thread_functions.condvar_wake_one) (cond);
00290 }
00291 
00297 void
00298 _dbus_condvar_wake_all (DBusCondVar *cond)
00299 {
00300   if (cond && thread_functions.condvar_wake_all)
00301     (* thread_functions.condvar_wake_all) (cond);
00302 }
00303 
00304 static void
00305 shutdown_global_locks (void *data)
00306 {
00307   DBusMutex ***locks = data;
00308   int i;
00309 
00310   i = 0;
00311   while (i < _DBUS_N_GLOBAL_LOCKS)
00312     {
00313       _dbus_mutex_free (*(locks[i]));
00314       *(locks[i]) = NULL;
00315       ++i;
00316     }
00317   
00318   dbus_free (locks);
00319 }
00320 
00321 static void
00322 shutdown_uninitialized_locks (void *data)
00323 {
00324   _dbus_list_clear (&uninitialized_mutex_list);
00325   _dbus_list_clear (&uninitialized_condvar_list);
00326 }
00327 
00328 static dbus_bool_t
00329 init_uninitialized_locks (void)
00330 {
00331   DBusList *link;
00332 
00333   _dbus_assert (thread_init_generation != _dbus_current_generation);
00334 
00335   link = uninitialized_mutex_list;
00336   while (link != NULL)
00337     {
00338       DBusMutex **mp;
00339 
00340       mp = (DBusMutex **)link->data;
00341       _dbus_assert (*mp == _DBUS_DUMMY_MUTEX);
00342 
00343       *mp = _dbus_mutex_new ();
00344       if (*mp == NULL)
00345         goto fail_mutex;
00346 
00347       link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
00348     }
00349 
00350   link = uninitialized_condvar_list;
00351   while (link != NULL)
00352     {
00353       DBusCondVar **cp;
00354 
00355       cp = (DBusCondVar **)link->data;
00356       _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR);
00357 
00358       *cp = _dbus_condvar_new ();
00359       if (*cp == NULL)
00360         goto fail_condvar;
00361 
00362       link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
00363     }
00364 
00365   _dbus_list_clear (&uninitialized_mutex_list);
00366   _dbus_list_clear (&uninitialized_condvar_list);
00367 
00368   if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks,
00369                                      NULL))
00370     goto fail_condvar;
00371 
00372   return TRUE;
00373 
00374  fail_condvar:
00375   link = uninitialized_condvar_list;
00376   while (link != NULL)
00377     {
00378       DBusCondVar **cp;
00379 
00380       cp = (DBusCondVar **)link->data;
00381 
00382       if (*cp != _DBUS_DUMMY_CONDVAR)
00383         _dbus_condvar_free (*cp);
00384       else
00385         break;
00386 
00387       *cp = _DBUS_DUMMY_CONDVAR;
00388 
00389       link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
00390     }
00391 
00392  fail_mutex:
00393   link = uninitialized_mutex_list;
00394   while (link != NULL)
00395     {
00396       DBusMutex **mp;
00397 
00398       mp = (DBusMutex **)link->data;
00399 
00400       if (*mp != _DBUS_DUMMY_MUTEX)
00401         _dbus_mutex_free (*mp);
00402       else
00403         break;
00404 
00405       *mp = _DBUS_DUMMY_MUTEX;
00406 
00407       link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
00408     }
00409 
00410   return FALSE;
00411 }
00412 
00413 static dbus_bool_t
00414 init_locks (void)
00415 {
00416   int i;
00417   DBusMutex ***dynamic_global_locks;
00418   
00419   DBusMutex **global_locks[] = {
00420 #define LOCK_ADDR(name) (& _dbus_lock_##name)
00421     LOCK_ADDR (win_fds),
00422     LOCK_ADDR (sid_atom_cache),
00423     LOCK_ADDR (list),
00424     LOCK_ADDR (connection_slots),
00425     LOCK_ADDR (pending_call_slots),
00426     LOCK_ADDR (server_slots),
00427     LOCK_ADDR (message_slots),
00428 #if !DBUS_USE_SYNC
00429     LOCK_ADDR (atomic),
00430 #endif
00431     LOCK_ADDR (bus),
00432     LOCK_ADDR (bus_datas),
00433     LOCK_ADDR (shutdown_funcs),
00434     LOCK_ADDR (system_users),
00435     LOCK_ADDR (message_cache),
00436     LOCK_ADDR (shared_connections),
00437     LOCK_ADDR (machine_uuid)
00438 #undef LOCK_ADDR
00439   };
00440 
00441   _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
00442                 _DBUS_N_GLOBAL_LOCKS);
00443 
00444   i = 0;
00445   
00446   dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
00447   if (dynamic_global_locks == NULL)
00448     goto failed;
00449   
00450   while (i < _DBUS_N_ELEMENTS (global_locks))
00451     {
00452       *global_locks[i] = _dbus_mutex_new ();
00453       
00454       if (*global_locks[i] == NULL)
00455         goto failed;
00456 
00457       dynamic_global_locks[i] = global_locks[i];
00458 
00459       ++i;
00460     }
00461   
00462   if (!_dbus_register_shutdown_func (shutdown_global_locks,
00463                                      dynamic_global_locks))
00464     goto failed;
00465 
00466   if (!init_uninitialized_locks ())
00467     goto failed;
00468   
00469   return TRUE;
00470 
00471  failed:
00472   dbus_free (dynamic_global_locks);
00473                                      
00474   for (i = i - 1; i >= 0; i--)
00475     {
00476       _dbus_mutex_free (*global_locks[i]);
00477       *global_locks[i] = NULL;
00478     }
00479   return FALSE;
00480 }
00481  /* end of internals */
00483 
00547 dbus_bool_t
00548 dbus_threads_init (const DBusThreadFunctions *functions)
00549 {
00550   dbus_bool_t mutex_set;
00551   dbus_bool_t recursive_mutex_set;
00552 
00553   _dbus_assert (functions != NULL);
00554 
00555   /* these base functions are required. Future additions to
00556    * DBusThreadFunctions may be optional.
00557    */
00558   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
00559   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
00560   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
00561   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
00562   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
00563   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
00564   _dbus_assert (functions->condvar_new != NULL);
00565   _dbus_assert (functions->condvar_free != NULL);
00566   _dbus_assert (functions->condvar_wait != NULL);
00567   _dbus_assert (functions->condvar_wait_timeout != NULL);
00568   _dbus_assert (functions->condvar_wake_one != NULL);
00569   _dbus_assert (functions->condvar_wake_all != NULL);
00570 
00571   /* Either the mutex function set or recursive mutex set needs 
00572    * to be available but not both
00573    */
00574   mutex_set = (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK) &&  
00575               (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK) && 
00576               (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK) &&
00577               (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK) &&
00578                functions->mutex_new &&
00579                functions->mutex_free &&
00580                functions->mutex_lock &&
00581                functions->mutex_unlock;
00582 
00583   recursive_mutex_set = 
00584               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) && 
00585               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) && 
00586               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) && 
00587               (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) &&
00588                 functions->recursive_mutex_new &&
00589                 functions->recursive_mutex_free &&
00590                 functions->recursive_mutex_lock &&
00591                 functions->recursive_mutex_unlock;
00592 
00593   if (!(mutex_set || recursive_mutex_set))
00594     _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " 
00595                               "functions sets should be passed into "
00596                               "dbus_threads_init. Neither sets were passed.");
00597 
00598   if (mutex_set && recursive_mutex_set)
00599     _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " 
00600                               "functions sets should be passed into "
00601                               "dbus_threads_init. Both sets were passed. "
00602                               "You most likely just want to set the recursive "
00603                               "mutex functions to avoid deadlocks in D-Bus.");
00604                           
00605   /* Check that all bits in the mask actually are valid mask bits.
00606    * ensures people won't write code that breaks when we add
00607    * new bits.
00608    */
00609   _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
00610 
00611   if (thread_init_generation != _dbus_current_generation)
00612     thread_functions.mask = 0; /* allow re-init in new generation */
00613  
00614   /* Silently allow multiple init
00615    * First init wins and D-Bus will always use its threading system 
00616    */ 
00617   if (thread_functions.mask != 0)
00618     return TRUE;
00619   
00620   thread_functions.mutex_new = functions->mutex_new;
00621   thread_functions.mutex_free = functions->mutex_free;
00622   thread_functions.mutex_lock = functions->mutex_lock;
00623   thread_functions.mutex_unlock = functions->mutex_unlock;
00624   
00625   thread_functions.condvar_new = functions->condvar_new;
00626   thread_functions.condvar_free = functions->condvar_free;
00627   thread_functions.condvar_wait = functions->condvar_wait;
00628   thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
00629   thread_functions.condvar_wake_one = functions->condvar_wake_one;
00630   thread_functions.condvar_wake_all = functions->condvar_wake_all;
00631  
00632   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK)
00633     thread_functions.recursive_mutex_new = functions->recursive_mutex_new;
00634   
00635   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK)
00636     thread_functions.recursive_mutex_free = functions->recursive_mutex_free;
00637   
00638   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK)
00639     thread_functions.recursive_mutex_lock = functions->recursive_mutex_lock;
00640 
00641   if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK)
00642     thread_functions.recursive_mutex_unlock = functions->recursive_mutex_unlock;
00643 
00644   thread_functions.mask = functions->mask;
00645 
00646   if (!init_locks ())
00647     return FALSE;
00648 
00649   thread_init_generation = _dbus_current_generation;
00650   
00651   return TRUE;
00652 }
00653 
00654 
00655 
00656 /* Default thread implemenation */
00657 
00673 dbus_bool_t
00674 dbus_threads_init_default (void)
00675 {
00676   return _dbus_threads_init_platform_specific ();
00677 }
00678 
00679 
00682 #ifdef DBUS_BUILD_TESTS
00683 
00684 typedef struct DBusFakeMutex DBusFakeMutex;
00686 struct DBusFakeMutex
00687 {
00688   dbus_bool_t locked; 
00689 };      
00690 
00691 static DBusMutex *  dbus_fake_mutex_new            (void);
00692 static void         dbus_fake_mutex_free           (DBusMutex   *mutex);
00693 static dbus_bool_t  dbus_fake_mutex_lock           (DBusMutex   *mutex);
00694 static dbus_bool_t  dbus_fake_mutex_unlock         (DBusMutex   *mutex);
00695 static DBusCondVar* dbus_fake_condvar_new          (void);
00696 static void         dbus_fake_condvar_free         (DBusCondVar *cond);
00697 static void         dbus_fake_condvar_wait         (DBusCondVar *cond,
00698                                                     DBusMutex   *mutex);
00699 static dbus_bool_t  dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
00700                                                     DBusMutex   *mutex,
00701                                                     int          timeout_msec);
00702 static void         dbus_fake_condvar_wake_one     (DBusCondVar *cond);
00703 static void         dbus_fake_condvar_wake_all     (DBusCondVar *cond);
00704 
00705 
00706 static const DBusThreadFunctions fake_functions =
00707 {
00708   DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
00709   DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
00710   DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
00711   DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
00712   DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
00713   DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
00714   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
00715   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
00716   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
00717   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
00718   dbus_fake_mutex_new,
00719   dbus_fake_mutex_free,
00720   dbus_fake_mutex_lock,
00721   dbus_fake_mutex_unlock,
00722   dbus_fake_condvar_new,
00723   dbus_fake_condvar_free,
00724   dbus_fake_condvar_wait,
00725   dbus_fake_condvar_wait_timeout,
00726   dbus_fake_condvar_wake_one,
00727   dbus_fake_condvar_wake_all
00728 };
00729 
00730 static DBusMutex *
00731 dbus_fake_mutex_new (void)
00732 {
00733   DBusFakeMutex *mutex;
00734 
00735   mutex = dbus_new0 (DBusFakeMutex, 1);
00736 
00737   return (DBusMutex *)mutex;
00738 }
00739 
00740 static void
00741 dbus_fake_mutex_free (DBusMutex *mutex)
00742 {
00743   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
00744 
00745   _dbus_assert (!fake->locked);
00746   
00747   dbus_free (fake);
00748 }
00749 
00750 static dbus_bool_t
00751 dbus_fake_mutex_lock (DBusMutex *mutex)
00752 {
00753   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
00754 
00755   _dbus_assert (!fake->locked);
00756 
00757   fake->locked = TRUE;
00758   
00759   return TRUE;
00760 }
00761 
00762 static dbus_bool_t
00763 dbus_fake_mutex_unlock (DBusMutex *mutex)
00764 {
00765   DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
00766 
00767   _dbus_assert (fake->locked);
00768 
00769   fake->locked = FALSE;
00770   
00771   return TRUE;
00772 }
00773 
00774 static DBusCondVar*
00775 dbus_fake_condvar_new (void)
00776 {
00777   return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
00778 }
00779 
00780 static void
00781 dbus_fake_condvar_free (DBusCondVar *cond)
00782 {
00783   dbus_free (cond);
00784 }
00785 
00786 static void
00787 dbus_fake_condvar_wait (DBusCondVar *cond,
00788                         DBusMutex   *mutex)
00789 {
00790   
00791 }
00792 
00793 static dbus_bool_t
00794 dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
00795                                 DBusMutex   *mutex,
00796                                 int         timeout_msec)
00797 {
00798   return TRUE;
00799 }
00800 
00801 static void
00802 dbus_fake_condvar_wake_one (DBusCondVar *cond)
00803 {
00804 
00805 }
00806 
00807 static void
00808 dbus_fake_condvar_wake_all (DBusCondVar *cond)
00809 {
00810 
00811 }
00812 
00813 dbus_bool_t
00814 _dbus_threads_init_debug (void)
00815 {
00816 #ifdef DBUS_WIN
00817   return _dbus_threads_init_platform_specific();
00818 #else
00819   return dbus_threads_init (&fake_functions);
00820 #endif
00821 }
00822 
00823 #endif /* DBUS_BUILD_TESTS */