D-Bus  1.4.10
dbus-threads.c
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-threads.h D-Bus threads handling
3  *
4  * Copyright (C) 2002, 2003, 2006 Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  *
22  */
23 #include <config.h>
24 #include "dbus-threads.h"
25 #include "dbus-internals.h"
26 #include "dbus-threads-internal.h"
27 #include "dbus-list.h"
28 
29 static DBusThreadFunctions thread_functions =
30 {
31  0,
32  NULL, NULL, NULL, NULL, NULL,
33  NULL, NULL, NULL, NULL, NULL,
34  NULL, NULL, NULL, NULL,
35 
36  NULL, NULL, NULL, NULL
37 };
38 
39 static int thread_init_generation = 0;
40 
41 static DBusList *uninitialized_mutex_list = NULL;
42 static DBusList *uninitialized_condvar_list = NULL;
43 
45 #define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
46 
48 #define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
49 
68 DBusMutex*
70 {
71  if (thread_functions.recursive_mutex_new)
72  return (* thread_functions.recursive_mutex_new) ();
73  else if (thread_functions.mutex_new)
74  return (* thread_functions.mutex_new) ();
75  else
76  return _DBUS_DUMMY_MUTEX;
77 }
78 
88 void
90 {
91  _dbus_assert (location_p != NULL);
92 
93  *location_p = _dbus_mutex_new();
94 
95  if (thread_init_generation != _dbus_current_generation && *location_p)
96  {
97  if (!_dbus_list_append (&uninitialized_mutex_list, location_p))
98  {
99  _dbus_mutex_free (*location_p);
100  *location_p = NULL;
101  }
102  }
103 }
104 
109 void
111 {
112  if (mutex)
113  {
114  if (mutex && thread_functions.recursive_mutex_free)
115  (* thread_functions.recursive_mutex_free) (mutex);
116  else if (mutex && thread_functions.mutex_free)
117  (* thread_functions.mutex_free) (mutex);
118  }
119 }
120 
126 void
128 {
129  if (location_p)
130  {
131  if (thread_init_generation != _dbus_current_generation)
132  _dbus_list_remove (&uninitialized_mutex_list, location_p);
133 
134  _dbus_mutex_free (*location_p);
135  }
136 }
137 
143 void
145 {
146  if (mutex)
147  {
148  if (thread_functions.recursive_mutex_lock)
149  (* thread_functions.recursive_mutex_lock) (mutex);
150  else if (thread_functions.mutex_lock)
151  (* thread_functions.mutex_lock) (mutex);
152  }
153 }
154 
160 void
162 {
163  if (mutex)
164  {
165  if (thread_functions.recursive_mutex_unlock)
166  (* thread_functions.recursive_mutex_unlock) (mutex);
167  else if (thread_functions.mutex_unlock)
168  (* thread_functions.mutex_unlock) (mutex);
169  }
170 }
171 
180 DBusCondVar *
182 {
183  if (thread_functions.condvar_new)
184  return (* thread_functions.condvar_new) ();
185  else
186  return _DBUS_DUMMY_CONDVAR;
187 }
188 
189 
200 void
202 {
203  *location_p = _dbus_condvar_new();
204 
205  if (thread_init_generation != _dbus_current_generation && *location_p)
206  {
207  if (!_dbus_list_append (&uninitialized_condvar_list, location_p))
208  {
209  _dbus_condvar_free (*location_p);
210  *location_p = NULL;
211  }
212  }
213 }
214 
215 
220 void
222 {
223  if (cond && thread_functions.condvar_free)
224  (* thread_functions.condvar_free) (cond);
225 }
226 
232 void
234 {
235  if (location_p)
236  {
237  if (thread_init_generation != _dbus_current_generation)
238  _dbus_list_remove (&uninitialized_condvar_list, location_p);
239 
240  _dbus_condvar_free (*location_p);
241  }
242 }
243 
250 void
252  DBusMutex *mutex)
253 {
254  if (cond && mutex && thread_functions.condvar_wait)
255  (* thread_functions.condvar_wait) (cond, mutex);
256 }
257 
271  DBusMutex *mutex,
272  int timeout_milliseconds)
273 {
274  if (cond && mutex && thread_functions.condvar_wait)
275  return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
276  else
277  return TRUE;
278 }
279 
285 void
287 {
288  if (cond && thread_functions.condvar_wake_one)
289  (* thread_functions.condvar_wake_one) (cond);
290 }
291 
297 void
299 {
300  if (cond && thread_functions.condvar_wake_all)
301  (* thread_functions.condvar_wake_all) (cond);
302 }
303 
304 static void
305 shutdown_global_locks (void *data)
306 {
307  DBusMutex ***locks = data;
308  int i;
309 
310  i = 0;
311  while (i < _DBUS_N_GLOBAL_LOCKS)
312  {
313  _dbus_mutex_free (*(locks[i]));
314  *(locks[i]) = NULL;
315  ++i;
316  }
317 
318  dbus_free (locks);
319 }
320 
321 static void
322 shutdown_uninitialized_locks (void *data)
323 {
324  _dbus_list_clear (&uninitialized_mutex_list);
325  _dbus_list_clear (&uninitialized_condvar_list);
326 }
327 
328 static dbus_bool_t
329 init_uninitialized_locks (void)
330 {
331  DBusList *link;
332 
333  _dbus_assert (thread_init_generation != _dbus_current_generation);
334 
335  link = uninitialized_mutex_list;
336  while (link != NULL)
337  {
338  DBusMutex **mp;
339 
340  mp = (DBusMutex **)link->data;
341  _dbus_assert (*mp == _DBUS_DUMMY_MUTEX);
342 
343  *mp = _dbus_mutex_new ();
344  if (*mp == NULL)
345  goto fail_mutex;
346 
347  link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
348  }
349 
350  link = uninitialized_condvar_list;
351  while (link != NULL)
352  {
353  DBusCondVar **cp;
354 
355  cp = (DBusCondVar **)link->data;
356  _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR);
357 
358  *cp = _dbus_condvar_new ();
359  if (*cp == NULL)
360  goto fail_condvar;
361 
362  link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
363  }
364 
365  _dbus_list_clear (&uninitialized_mutex_list);
366  _dbus_list_clear (&uninitialized_condvar_list);
367 
368  if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks,
369  NULL))
370  goto fail_condvar;
371 
372  return TRUE;
373 
374  fail_condvar:
375  link = uninitialized_condvar_list;
376  while (link != NULL)
377  {
378  DBusCondVar **cp;
379 
380  cp = (DBusCondVar **)link->data;
381 
382  if (*cp != _DBUS_DUMMY_CONDVAR)
383  _dbus_condvar_free (*cp);
384  else
385  break;
386 
387  *cp = _DBUS_DUMMY_CONDVAR;
388 
389  link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
390  }
391 
392  fail_mutex:
393  link = uninitialized_mutex_list;
394  while (link != NULL)
395  {
396  DBusMutex **mp;
397 
398  mp = (DBusMutex **)link->data;
399 
400  if (*mp != _DBUS_DUMMY_MUTEX)
401  _dbus_mutex_free (*mp);
402  else
403  break;
404 
405  *mp = _DBUS_DUMMY_MUTEX;
406 
407  link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
408  }
409 
410  return FALSE;
411 }
412 
413 static dbus_bool_t
414 init_locks (void)
415 {
416  int i;
417  DBusMutex ***dynamic_global_locks;
418 
419  DBusMutex **global_locks[] = {
420 #define LOCK_ADDR(name) (& _dbus_lock_##name)
421  LOCK_ADDR (win_fds),
422  LOCK_ADDR (sid_atom_cache),
423  LOCK_ADDR (list),
424  LOCK_ADDR (connection_slots),
425  LOCK_ADDR (pending_call_slots),
426  LOCK_ADDR (server_slots),
427  LOCK_ADDR (message_slots),
428 #if !DBUS_USE_SYNC
429  LOCK_ADDR (atomic),
430 #endif
431  LOCK_ADDR (bus),
432  LOCK_ADDR (bus_datas),
433  LOCK_ADDR (shutdown_funcs),
434  LOCK_ADDR (system_users),
435  LOCK_ADDR (message_cache),
436  LOCK_ADDR (shared_connections),
437  LOCK_ADDR (machine_uuid)
438 #undef LOCK_ADDR
439  };
440 
441  _dbus_assert (_DBUS_N_ELEMENTS (global_locks) ==
442  _DBUS_N_GLOBAL_LOCKS);
443 
444  i = 0;
445 
446  dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
447  if (dynamic_global_locks == NULL)
448  goto failed;
449 
450  while (i < _DBUS_N_ELEMENTS (global_locks))
451  {
452  *global_locks[i] = _dbus_mutex_new ();
453 
454  if (*global_locks[i] == NULL)
455  goto failed;
456 
457  dynamic_global_locks[i] = global_locks[i];
458 
459  ++i;
460  }
461 
462  if (!_dbus_register_shutdown_func (shutdown_global_locks,
463  dynamic_global_locks))
464  goto failed;
465 
466  if (!init_uninitialized_locks ())
467  goto failed;
468 
469  return TRUE;
470 
471  failed:
472  dbus_free (dynamic_global_locks);
473 
474  for (i = i - 1; i >= 0; i--)
475  {
476  _dbus_mutex_free (*global_locks[i]);
477  *global_locks[i] = NULL;
478  }
479  return FALSE;
480 }
481  /* end of internals */
483 
549 {
550  dbus_bool_t mutex_set;
551  dbus_bool_t recursive_mutex_set;
552 
553  _dbus_assert (functions != NULL);
554 
555  /* these base functions are required. Future additions to
556  * DBusThreadFunctions may be optional.
557  */
558  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
559  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
560  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
561  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
562  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
563  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
564  _dbus_assert (functions->condvar_new != NULL);
565  _dbus_assert (functions->condvar_free != NULL);
566  _dbus_assert (functions->condvar_wait != NULL);
567  _dbus_assert (functions->condvar_wait_timeout != NULL);
568  _dbus_assert (functions->condvar_wake_one != NULL);
569  _dbus_assert (functions->condvar_wake_all != NULL);
570 
571  /* Either the mutex function set or recursive mutex set needs
572  * to be available but not both
573  */
574  mutex_set = (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK) &&
575  (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK) &&
576  (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK) &&
577  (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK) &&
578  functions->mutex_new &&
579  functions->mutex_free &&
580  functions->mutex_lock &&
581  functions->mutex_unlock;
582 
583  recursive_mutex_set =
584  (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) &&
585  (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) &&
586  (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) &&
587  (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) &&
588  functions->recursive_mutex_new &&
589  functions->recursive_mutex_free &&
590  functions->recursive_mutex_lock &&
591  functions->recursive_mutex_unlock;
592 
593  if (!(mutex_set || recursive_mutex_set))
594  _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex "
595  "functions sets should be passed into "
596  "dbus_threads_init. Neither sets were passed.");
597 
598  if (mutex_set && recursive_mutex_set)
599  _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex "
600  "functions sets should be passed into "
601  "dbus_threads_init. Both sets were passed. "
602  "You most likely just want to set the recursive "
603  "mutex functions to avoid deadlocks in D-Bus.");
604 
605  /* Check that all bits in the mask actually are valid mask bits.
606  * ensures people won't write code that breaks when we add
607  * new bits.
608  */
609  _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
610 
611  if (thread_init_generation != _dbus_current_generation)
612  thread_functions.mask = 0; /* allow re-init in new generation */
613 
614  /* Silently allow multiple init
615  * First init wins and D-Bus will always use its threading system
616  */
617  if (thread_functions.mask != 0)
618  return TRUE;
619 
620  thread_functions.mutex_new = functions->mutex_new;
621  thread_functions.mutex_free = functions->mutex_free;
622  thread_functions.mutex_lock = functions->mutex_lock;
623  thread_functions.mutex_unlock = functions->mutex_unlock;
624 
625  thread_functions.condvar_new = functions->condvar_new;
626  thread_functions.condvar_free = functions->condvar_free;
627  thread_functions.condvar_wait = functions->condvar_wait;
628  thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
629  thread_functions.condvar_wake_one = functions->condvar_wake_one;
630  thread_functions.condvar_wake_all = functions->condvar_wake_all;
631 
632  if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK)
633  thread_functions.recursive_mutex_new = functions->recursive_mutex_new;
634 
635  if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK)
636  thread_functions.recursive_mutex_free = functions->recursive_mutex_free;
637 
638  if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK)
639  thread_functions.recursive_mutex_lock = functions->recursive_mutex_lock;
640 
641  if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK)
642  thread_functions.recursive_mutex_unlock = functions->recursive_mutex_unlock;
643 
644  thread_functions.mask = functions->mask;
645 
646  if (!init_locks ())
647  return FALSE;
648 
649  thread_init_generation = _dbus_current_generation;
650 
651  return TRUE;
652 }
653 
654 
655 
656 /* Default thread implemenation */
657 
675 {
677 }
678 
679 
682 #ifdef DBUS_BUILD_TESTS
683 
684 typedef struct DBusFakeMutex DBusFakeMutex;
686 struct DBusFakeMutex
687 {
688  dbus_bool_t locked;
689 };
690 
691 static DBusMutex * dbus_fake_mutex_new (void);
692 static void dbus_fake_mutex_free (DBusMutex *mutex);
693 static dbus_bool_t dbus_fake_mutex_lock (DBusMutex *mutex);
694 static dbus_bool_t dbus_fake_mutex_unlock (DBusMutex *mutex);
695 static DBusCondVar* dbus_fake_condvar_new (void);
696 static void dbus_fake_condvar_free (DBusCondVar *cond);
697 static void dbus_fake_condvar_wait (DBusCondVar *cond,
698  DBusMutex *mutex);
699 static dbus_bool_t dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
700  DBusMutex *mutex,
701  int timeout_msec);
702 static void dbus_fake_condvar_wake_one (DBusCondVar *cond);
703 static void dbus_fake_condvar_wake_all (DBusCondVar *cond);
704 
705 
706 static const DBusThreadFunctions fake_functions =
707 {
708  DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
709  DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
710  DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
711  DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
712  DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
713  DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
714  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
715  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
716  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
717  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
718  dbus_fake_mutex_new,
719  dbus_fake_mutex_free,
720  dbus_fake_mutex_lock,
721  dbus_fake_mutex_unlock,
722  dbus_fake_condvar_new,
723  dbus_fake_condvar_free,
724  dbus_fake_condvar_wait,
725  dbus_fake_condvar_wait_timeout,
726  dbus_fake_condvar_wake_one,
727  dbus_fake_condvar_wake_all
728 };
729 
730 static DBusMutex *
731 dbus_fake_mutex_new (void)
732 {
733  DBusFakeMutex *mutex;
734 
735  mutex = dbus_new0 (DBusFakeMutex, 1);
736 
737  return (DBusMutex *)mutex;
738 }
739 
740 static void
741 dbus_fake_mutex_free (DBusMutex *mutex)
742 {
743  DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
744 
745  _dbus_assert (!fake->locked);
746 
747  dbus_free (fake);
748 }
749 
750 static dbus_bool_t
751 dbus_fake_mutex_lock (DBusMutex *mutex)
752 {
753  DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
754 
755  _dbus_assert (!fake->locked);
756 
757  fake->locked = TRUE;
758 
759  return TRUE;
760 }
761 
762 static dbus_bool_t
763 dbus_fake_mutex_unlock (DBusMutex *mutex)
764 {
765  DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
766 
767  _dbus_assert (fake->locked);
768 
769  fake->locked = FALSE;
770 
771  return TRUE;
772 }
773 
774 static DBusCondVar*
775 dbus_fake_condvar_new (void)
776 {
777  return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
778 }
779 
780 static void
781 dbus_fake_condvar_free (DBusCondVar *cond)
782 {
783  dbus_free (cond);
784 }
785 
786 static void
787 dbus_fake_condvar_wait (DBusCondVar *cond,
788  DBusMutex *mutex)
789 {
790 
791 }
792 
793 static dbus_bool_t
794 dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
795  DBusMutex *mutex,
796  int timeout_msec)
797 {
798  return TRUE;
799 }
800 
801 static void
802 dbus_fake_condvar_wake_one (DBusCondVar *cond)
803 {
804 
805 }
806 
807 static void
808 dbus_fake_condvar_wake_all (DBusCondVar *cond)
809 {
810 
811 }
812 
814 _dbus_threads_init_debug (void)
815 {
816 #ifdef DBUS_WIN
818 #else
819  return dbus_threads_init (&fake_functions);
820 #endif
821 }
822 
823 #endif /* DBUS_BUILD_TESTS */