2003-01-05 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-threads.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-threads.h  D-BUS threads handling
3  *
4  * Copyright (C) 2002  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "dbus-threads.h"
24 #include "dbus-internals.h"
25
26 static DBusThreadFunctions thread_functions =
27 {
28   0,
29   NULL, NULL, NULL, NULL,
30
31   NULL, NULL, NULL, NULL,
32   NULL, NULL, NULL, NULL
33 };
34
35 static DBusMutex *static_mutex_init_lock = NULL;
36
37 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
38 #define _DBUS_DUMMY_MUTEX ((void*)0xABCDEF)
39
40 /**
41  * @defgroup DBusThreads Thread functions
42  * @ingroup  DBus
43  * @brief dbus_threads_init(), dbus_mutex_lock(), etc.
44  *
45  * Functions and macros related to threads and thread locks.
46  *
47  * @{
48  */
49
50 /**
51  * Creates a new mutex using the function supplied to dbus_threads_init(),
52  * or creates a no-op mutex if threads are not initialized.
53  * May return #NULL even if threads are initialized, indicating
54  * out-of-memory.
55  *
56  * @returns new mutex or #NULL
57  */
58 DBusMutex*
59 dbus_mutex_new (void)
60 {
61   if (thread_functions.mutex_new)
62     return (* thread_functions.mutex_new) ();
63   else
64     return _DBUS_DUMMY_MUTEX;
65 }
66
67 /**
68  * Frees a mutex created with dbus_mutex_new(); does
69  * nothing if passed a #NULL pointer.
70  */
71 void
72 dbus_mutex_free (DBusMutex *mutex)
73 {
74   if (mutex && thread_functions.mutex_free)
75     (* thread_functions.mutex_free) (mutex);
76 }
77
78 /**
79  * Locks a mutex. Does nothing if passed a #NULL pointer.
80  * Locks are not recursive.
81  *
82  * @returns #TRUE on success
83  */
84 dbus_bool_t
85 dbus_mutex_lock (DBusMutex *mutex)
86 {
87   if (mutex && thread_functions.mutex_lock)
88     return (* thread_functions.mutex_lock) (mutex);
89   else
90     return TRUE;
91 }
92
93 /**
94  * Unlocks a mutex. Does nothing if passed a #NULL pointer.
95  *
96  * @returns #TRUE on success
97  */
98 dbus_bool_t
99 dbus_mutex_unlock (DBusMutex *mutex)
100 {
101   if (mutex && thread_functions.mutex_unlock)
102     return (* thread_functions.mutex_unlock) (mutex);
103   else
104     return TRUE;
105 }
106
107 /**
108  * Initializes threads. If this function is not called,
109  * the D-BUS library will not lock any data structures.
110  * If it is called, D-BUS will do locking, at some cost
111  * in efficiency. Note that this function must be called
112  * BEFORE using any other D-BUS functions.
113  *
114  * @todo right now this function can only be called once,
115  * maybe we should instead silently ignore multiple calls.
116  *
117  * @param functions functions for using threads
118  * @returns #TRUE on success, #FALSE if no memory
119  */
120 dbus_bool_t
121 dbus_threads_init (const DBusThreadFunctions *functions)
122 {
123   _dbus_assert (functions != NULL);
124
125   /* these base functions are required. Future additions to
126    * DBusThreadFunctions may be optional.
127    */
128   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_NEW_MASK);
129   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_FREE_MASK);
130   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_LOCK_MASK);
131   _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_UNLOCK_MASK);
132   _dbus_assert (functions->mutex_new != NULL);
133   _dbus_assert (functions->mutex_free != NULL);
134   _dbus_assert (functions->mutex_lock != NULL);
135   _dbus_assert (functions->mutex_unlock != NULL);
136
137   /* Check that all bits in the mask actually are valid mask bits.
138    * ensures people won't write code that breaks when we add
139    * new bits.
140    */
141   _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
142   
143   if (thread_functions.mask != 0)
144     {
145       _dbus_warn ("dbus_threads_init() may only be called one time\n");
146       return FALSE;
147     }
148   
149   thread_functions.mutex_new = functions->mutex_new;
150   thread_functions.mutex_free = functions->mutex_free;
151   thread_functions.mutex_lock = functions->mutex_lock;
152   thread_functions.mutex_unlock = functions->mutex_unlock;
153   
154   thread_functions.mask = functions->mask;
155
156   static_mutex_init_lock = dbus_mutex_new ();
157
158   if (static_mutex_init_lock == NULL)
159     {
160       thread_functions.mask = 0;
161       return FALSE;
162     }
163
164   return TRUE;
165 }
166
167 /** Accesses the field of DBusStaticMutex that
168  * stores the DBusMutex used to implement.
169  */
170 #define _DBUS_STATIC_MUTEX_IMPL(mutex) ((mutex)->pad1)
171
172 /**
173  * Lock a static mutex
174  *
175  * @param mutex the mutex to lock
176  * @returns #TRUE on success
177  */
178 dbus_bool_t
179 dbus_static_mutex_lock (DBusStaticMutex *mutex)
180 {
181   if (_DBUS_STATIC_MUTEX_IMPL (mutex))
182     return dbus_mutex_lock (_DBUS_STATIC_MUTEX_IMPL (mutex));
183
184   if (!dbus_mutex_lock (static_mutex_init_lock))
185     return FALSE;
186
187   if (_DBUS_STATIC_MUTEX_IMPL (mutex) == NULL)
188     _DBUS_STATIC_MUTEX_IMPL (mutex) = dbus_mutex_new ();
189   
190   dbus_mutex_unlock (static_mutex_init_lock);
191
192   if (_DBUS_STATIC_MUTEX_IMPL (mutex))
193     return dbus_mutex_lock (_DBUS_STATIC_MUTEX_IMPL (mutex));
194   else
195     return FALSE;
196 }
197
198 /**
199  * Unlock a static mutex
200  * @param mutex the mutex to lock
201  * @returns #TRUE on success
202  */
203 dbus_bool_t
204 dbus_static_mutex_unlock (DBusStaticMutex *mutex)
205 {
206   _dbus_assert (_DBUS_STATIC_MUTEX_IMPL (mutex) != NULL);
207   
208   return dbus_mutex_unlock (_DBUS_STATIC_MUTEX_IMPL (mutex));
209 }
210
211 /** @} */