D-Bus 1.6.12

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 int thread_init_generation = 0;
00030  
00031 static DBusList *uninitialized_rmutex_list = NULL;
00032 static DBusList *uninitialized_cmutex_list = NULL;
00033 static DBusList *uninitialized_condvar_list = NULL;
00034 
00036 #define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
00037 #define _DBUS_DUMMY_RMUTEX ((DBusRMutex *) _DBUS_DUMMY_MUTEX)
00038 #define _DBUS_DUMMY_CMUTEX ((DBusCMutex *) _DBUS_DUMMY_MUTEX)
00039 
00041 #define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
00042 
00069 void
00070 _dbus_rmutex_new_at_location (DBusRMutex **location_p)
00071 {
00072   _dbus_assert (location_p != NULL);
00073 
00074   if (thread_init_generation == _dbus_current_generation)
00075     {
00076       *location_p = _dbus_platform_rmutex_new ();
00077     }
00078   else
00079     {
00080       *location_p = _DBUS_DUMMY_RMUTEX;
00081 
00082       if (!_dbus_list_append (&uninitialized_rmutex_list, location_p))
00083         *location_p = NULL;
00084     }
00085 }
00086 
00102 void
00103 _dbus_cmutex_new_at_location (DBusCMutex **location_p)
00104 {
00105   _dbus_assert (location_p != NULL);
00106 
00107   if (thread_init_generation == _dbus_current_generation)
00108     {
00109       *location_p = _dbus_platform_cmutex_new ();
00110     }
00111   else
00112     {
00113       *location_p = _DBUS_DUMMY_CMUTEX;
00114 
00115       if (!_dbus_list_append (&uninitialized_cmutex_list, location_p))
00116         *location_p = NULL;
00117     }
00118 }
00119 
00124 void
00125 _dbus_rmutex_free_at_location (DBusRMutex **location_p)
00126 {
00127   if (location_p == NULL)
00128     return;
00129 
00130   if (thread_init_generation == _dbus_current_generation)
00131     {
00132       if (*location_p != NULL)
00133         _dbus_platform_rmutex_free (*location_p);
00134     }
00135   else
00136     {
00137       _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_RMUTEX);
00138 
00139       _dbus_list_remove (&uninitialized_rmutex_list, location_p);
00140     }
00141 }
00142 
00148 void
00149 _dbus_cmutex_free_at_location (DBusCMutex **location_p)
00150 {
00151   if (location_p == NULL)
00152     return;
00153 
00154   if (thread_init_generation == _dbus_current_generation)
00155     {
00156       if (*location_p != NULL)
00157         _dbus_platform_cmutex_free (*location_p);
00158     }
00159   else
00160     {
00161       _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_CMUTEX);
00162 
00163       _dbus_list_remove (&uninitialized_cmutex_list, location_p);
00164     }
00165 }
00166 
00172 void
00173 _dbus_rmutex_lock (DBusRMutex *mutex)
00174 {
00175   if (mutex && thread_init_generation == _dbus_current_generation)
00176     _dbus_platform_rmutex_lock (mutex);
00177 }
00178 
00184 void
00185 _dbus_cmutex_lock (DBusCMutex *mutex)
00186 {
00187   if (mutex && thread_init_generation == _dbus_current_generation)
00188     _dbus_platform_cmutex_lock (mutex);
00189 }
00190 
00196 void
00197 _dbus_rmutex_unlock (DBusRMutex *mutex)
00198 {
00199   if (mutex && thread_init_generation == _dbus_current_generation)
00200     _dbus_platform_rmutex_unlock (mutex);
00201 }
00202 
00208 void
00209 _dbus_cmutex_unlock (DBusCMutex *mutex)
00210 {
00211   if (mutex && thread_init_generation == _dbus_current_generation)
00212     _dbus_platform_cmutex_unlock (mutex);
00213 }
00214 
00223 DBusCondVar *
00224 _dbus_condvar_new (void)
00225 {
00226   if (thread_init_generation == _dbus_current_generation)
00227     return _dbus_platform_condvar_new ();
00228   else
00229     return _DBUS_DUMMY_CONDVAR;
00230 }
00231 
00232 
00243 void 
00244 _dbus_condvar_new_at_location (DBusCondVar **location_p)
00245 {
00246   _dbus_assert (location_p != NULL);
00247 
00248   if (thread_init_generation == _dbus_current_generation)
00249     {
00250       *location_p = _dbus_condvar_new();
00251     }
00252   else
00253     {
00254       *location_p = _DBUS_DUMMY_CONDVAR;
00255 
00256       if (!_dbus_list_append (&uninitialized_condvar_list, location_p))
00257         *location_p = NULL;
00258     }
00259 }
00260 
00261 
00266 void
00267 _dbus_condvar_free (DBusCondVar *cond)
00268 {
00269   if (cond && thread_init_generation == _dbus_current_generation)
00270     _dbus_platform_condvar_free (cond);
00271 }
00272 
00278 void
00279 _dbus_condvar_free_at_location (DBusCondVar **location_p)
00280 {
00281   if (location_p == NULL)
00282     return;
00283 
00284   if (thread_init_generation == _dbus_current_generation)
00285     {
00286       if (*location_p != NULL)
00287         _dbus_platform_condvar_free (*location_p);
00288     }
00289   else
00290     {
00291       _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_CONDVAR);
00292 
00293       _dbus_list_remove (&uninitialized_condvar_list, location_p);
00294     }
00295 }
00296 
00303 void
00304 _dbus_condvar_wait (DBusCondVar *cond,
00305                     DBusCMutex  *mutex)
00306 {
00307   if (cond && mutex && thread_init_generation == _dbus_current_generation)
00308     _dbus_platform_condvar_wait (cond, mutex);
00309 }
00310 
00322 dbus_bool_t
00323 _dbus_condvar_wait_timeout (DBusCondVar               *cond,
00324                             DBusCMutex                *mutex,
00325                             int                        timeout_milliseconds)
00326 {
00327   if (cond && mutex && thread_init_generation == _dbus_current_generation)
00328     return _dbus_platform_condvar_wait_timeout (cond, mutex,
00329                                                 timeout_milliseconds);
00330   else
00331     return TRUE;
00332 }
00333 
00339 void
00340 _dbus_condvar_wake_one (DBusCondVar *cond)
00341 {
00342   if (cond && thread_init_generation == _dbus_current_generation)
00343     _dbus_platform_condvar_wake_one (cond);
00344 }
00345 
00346 static void
00347 shutdown_global_locks (void *data)
00348 {
00349   DBusRMutex ***locks = data;
00350   int i;
00351 
00352   i = 0;
00353   while (i < _DBUS_N_GLOBAL_LOCKS)
00354     {
00355       if (*(locks[i]) != NULL)
00356         _dbus_platform_rmutex_free (*(locks[i]));
00357 
00358       *(locks[i]) = NULL;
00359       ++i;
00360     }
00361   
00362   dbus_free (locks);
00363 }
00364 
00365 static void
00366 shutdown_uninitialized_locks (void *data)
00367 {
00368   _dbus_list_clear (&uninitialized_rmutex_list);
00369   _dbus_list_clear (&uninitialized_cmutex_list);
00370   _dbus_list_clear (&uninitialized_condvar_list);
00371 }
00372 
00373 static dbus_bool_t
00374 init_uninitialized_locks (void)
00375 {
00376   DBusList *link;
00377 
00378   _dbus_assert (thread_init_generation != _dbus_current_generation);
00379 
00380   link = uninitialized_rmutex_list;
00381   while (link != NULL)
00382     {
00383       DBusRMutex **mp;
00384 
00385       mp = link->data;
00386       _dbus_assert (*mp == _DBUS_DUMMY_RMUTEX);
00387 
00388       *mp = _dbus_platform_rmutex_new ();
00389       if (*mp == NULL)
00390         goto fail_mutex;
00391 
00392       link = _dbus_list_get_next_link (&uninitialized_rmutex_list, link);
00393     }
00394 
00395   link = uninitialized_cmutex_list;
00396   while (link != NULL)
00397     {
00398       DBusCMutex **mp;
00399 
00400       mp = link->data;
00401       _dbus_assert (*mp == _DBUS_DUMMY_CMUTEX);
00402 
00403       *mp = _dbus_platform_cmutex_new ();
00404       if (*mp == NULL)
00405         goto fail_mutex;
00406 
00407       link = _dbus_list_get_next_link (&uninitialized_cmutex_list, link);
00408     }
00409 
00410   link = uninitialized_condvar_list;
00411   while (link != NULL)
00412     {
00413       DBusCondVar **cp;
00414 
00415       cp = (DBusCondVar **)link->data;
00416       _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR);
00417 
00418       *cp = _dbus_platform_condvar_new ();
00419       if (*cp == NULL)
00420         goto fail_condvar;
00421 
00422       link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
00423     }
00424 
00425   _dbus_list_clear (&uninitialized_rmutex_list);
00426   _dbus_list_clear (&uninitialized_cmutex_list);
00427   _dbus_list_clear (&uninitialized_condvar_list);
00428 
00429   if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks,
00430                                      NULL))
00431     goto fail_condvar;
00432 
00433   return TRUE;
00434 
00435  fail_condvar:
00436   link = uninitialized_condvar_list;
00437   while (link != NULL)
00438     {
00439       DBusCondVar **cp;
00440 
00441       cp = link->data;
00442 
00443       if (*cp != _DBUS_DUMMY_CONDVAR && *cp != NULL)
00444         _dbus_platform_condvar_free (*cp);
00445 
00446       *cp = _DBUS_DUMMY_CONDVAR;
00447 
00448       link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
00449     }
00450 
00451  fail_mutex:
00452   link = uninitialized_rmutex_list;
00453   while (link != NULL)
00454     {
00455       DBusRMutex **mp;
00456 
00457       mp = link->data;
00458 
00459       if (*mp != _DBUS_DUMMY_RMUTEX && *mp != NULL)
00460         _dbus_platform_rmutex_free (*mp);
00461 
00462       *mp = _DBUS_DUMMY_RMUTEX;
00463 
00464       link = _dbus_list_get_next_link (&uninitialized_rmutex_list, link);
00465     }
00466 
00467   link = uninitialized_cmutex_list;
00468   while (link != NULL)
00469     {
00470       DBusCMutex **mp;
00471 
00472       mp = link->data;
00473 
00474       if (*mp != _DBUS_DUMMY_CMUTEX && *mp != NULL)
00475         _dbus_platform_cmutex_free (*mp);
00476 
00477       *mp = _DBUS_DUMMY_CMUTEX;
00478 
00479       link = _dbus_list_get_next_link (&uninitialized_cmutex_list, link);
00480     }
00481 
00482   return FALSE;
00483 }
00484 
00485 static dbus_bool_t
00486 init_locks (void)
00487 {
00488   int i;
00489   DBusRMutex ***dynamic_global_locks;
00490   DBusRMutex **global_locks[] = {
00491 #define LOCK_ADDR(name) (& _dbus_lock_##name)
00492     LOCK_ADDR (win_fds),
00493     LOCK_ADDR (sid_atom_cache),
00494     LOCK_ADDR (list),
00495     LOCK_ADDR (connection_slots),
00496     LOCK_ADDR (pending_call_slots),
00497     LOCK_ADDR (server_slots),
00498     LOCK_ADDR (message_slots),
00499 #if !DBUS_USE_SYNC
00500     LOCK_ADDR (atomic),
00501 #endif
00502     LOCK_ADDR (bus),
00503     LOCK_ADDR (bus_datas),
00504     LOCK_ADDR (shutdown_funcs),
00505     LOCK_ADDR (system_users),
00506     LOCK_ADDR (message_cache),
00507     LOCK_ADDR (shared_connections),
00508     LOCK_ADDR (machine_uuid)
00509 #undef LOCK_ADDR
00510   };
00511 
00512   _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
00513                 _DBUS_N_GLOBAL_LOCKS);
00514 
00515   i = 0;
00516   
00517   dynamic_global_locks = dbus_new (DBusRMutex**, _DBUS_N_GLOBAL_LOCKS);
00518   if (dynamic_global_locks == NULL)
00519     goto failed;
00520   
00521   while (i < _DBUS_N_ELEMENTS (global_locks))
00522     {
00523       *global_locks[i] = _dbus_platform_rmutex_new ();
00524 
00525       if (*global_locks[i] == NULL)
00526         goto failed;
00527 
00528       dynamic_global_locks[i] = global_locks[i];
00529 
00530       ++i;
00531     }
00532   
00533   if (!_dbus_register_shutdown_func (shutdown_global_locks,
00534                                      dynamic_global_locks))
00535     goto failed;
00536 
00537   if (!init_uninitialized_locks ())
00538     goto failed;
00539   
00540   return TRUE;
00541 
00542  failed:
00543   dbus_free (dynamic_global_locks);
00544                                      
00545   for (i = i - 1; i >= 0; i--)
00546     {
00547       _dbus_platform_rmutex_free (*global_locks[i]);
00548       *global_locks[i] = NULL;
00549     }
00550   return FALSE;
00551 }
00552  /* end of internals */
00554 
00584 dbus_bool_t
00585 dbus_threads_init (const DBusThreadFunctions *functions)
00586 {
00587   if (thread_init_generation == _dbus_current_generation)
00588     return TRUE;
00589 
00590   if (!init_locks ())
00591     return FALSE;
00592 
00593   thread_init_generation = _dbus_current_generation;
00594   
00595   return TRUE;
00596 }
00597 
00598 
00599 
00600 /* Default thread implemenation */
00601 
00616 dbus_bool_t
00617 dbus_threads_init_default (void)
00618 {
00619   return _dbus_threads_init_platform_specific ();
00620 }
00621 
00622 
00625 #ifdef DBUS_BUILD_TESTS
00626 
00627 dbus_bool_t
00628 _dbus_threads_init_debug (void)
00629 {
00630   return _dbus_threads_init_platform_specific();
00631 }
00632 
00633 #endif /* DBUS_BUILD_TESTS */