2006-10-26 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-sysdeps-pthread.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-sysdeps-pthread.c Implements threads using pthreads (internal to libdbus)
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-sysdeps.h"
26 #include "dbus-threads.h"
27
28 #include <sys/time.h>
29 #include <pthread.h>
30 #include <string.h>
31
32 typedef struct {
33   pthread_mutex_t lock;
34 } DBusMutexPThread;
35
36 typedef struct {
37   pthread_cond_t cond;
38 } DBusCondVarPThread;
39
40 #define DBUS_MUTEX(m)         ((DBusMutex*) m)
41 #define DBUS_MUTEX_PTHREAD(m) ((DBusMutexPThread*) m)
42
43 #define DBUS_COND_VAR(c)         ((DBusCondVar*) c)
44 #define DBUS_COND_VAR_PTHREAD(c) ((DBusCondVarPThread*) c)
45
46
47 #define PTHREAD_CHECK(func_name, result_or_call) do {                                  \
48     int tmp = (result_or_call);                                                        \
49     if (tmp != 0) {                                                                    \
50       _dbus_warn_check_failed ("pthread function %s failed with %d %s in %s\n",        \
51                                func_name, tmp, strerror(tmp), _DBUS_FUNCTION_NAME);    \
52     }                                                                                  \
53 } while (0)
54             
55 static DBusMutex*
56 _dbus_pthread_mutex_new (void)
57 {
58   DBusMutexPThread *pmutex;
59   int result;
60   
61   pmutex = dbus_new (DBusMutexPThread, 1);
62   if (pmutex == NULL)
63     return NULL;
64
65   result = pthread_mutex_init (&pmutex->lock, NULL);
66
67   if (result == ENOMEM || result == EAGAIN)
68     {
69       dbus_free (pmutex);
70       return NULL;
71     }
72   else
73     {
74       PTHREAD_CHECK ("pthread_mutex_init", result);
75     }
76
77   return DBUS_MUTEX (pmutex);
78 }
79
80 static void
81 _dbus_pthread_mutex_free (DBusMutex *mutex)
82 {
83   DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
84   
85   PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&pmutex->lock));
86
87   dbus_free (pmutex);
88 }
89
90 static dbus_bool_t
91 _dbus_pthread_mutex_lock (DBusMutex *mutex)
92 {
93   DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
94
95   PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&pmutex->lock));
96
97   return TRUE;
98 }
99
100 static dbus_bool_t
101 _dbus_pthread_mutex_unlock (DBusMutex *mutex)
102 {
103   DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
104
105   PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&pmutex->lock));
106
107   return TRUE;
108 }
109
110 static DBusCondVar *
111 _dbus_pthread_condvar_new (void)
112 {
113   DBusCondVarPThread *pcond;
114   int result;
115   
116   pcond = dbus_new (DBusCondVarPThread, 1);
117   if (pcond == NULL)
118     return NULL;
119
120   result = pthread_cond_init (&pcond->cond, NULL);
121
122   if (result == EAGAIN || result == ENOMEM)
123     {
124       dbus_free (pcond);
125       return NULL;
126     }
127   else
128     {
129       PTHREAD_CHECK ("pthread_cond_init", result);
130     }
131   
132   return DBUS_COND_VAR (pcond);
133 }
134
135 static void
136 _dbus_pthread_condvar_free (DBusCondVar *cond)
137 {  
138   DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
139   
140   PTHREAD_CHECK ("pthread_cond_destroy", pthread_cond_destroy (&pcond->cond));
141
142   dbus_free (pcond);
143 }
144
145 static void
146 _dbus_pthread_condvar_wait (DBusCondVar *cond,
147                             DBusMutex   *mutex)
148 {
149   DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
150   DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
151   
152   PTHREAD_CHECK ("pthread_cond_wait", pthread_cond_wait (&pcond->cond, &pmutex->lock));
153 }
154
155 static dbus_bool_t
156 _dbus_pthread_condvar_wait_timeout (DBusCondVar               *cond,
157                                     DBusMutex                 *mutex,
158                                     int                        timeout_milliseconds)
159 {
160   DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
161   DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
162   struct timeval time_now;
163   struct timespec end_time;
164   int result;
165   
166   gettimeofday (&time_now, NULL);
167   
168   end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000;
169   end_time.tv_nsec = (time_now.tv_usec + (timeout_milliseconds % 1000) * 1000) * 1000;
170   if (end_time.tv_nsec > 1000*1000*1000)
171     {
172       end_time.tv_sec += 1;
173       end_time.tv_nsec -= 1000*1000*1000;
174     }
175
176   result = pthread_cond_timedwait (&pcond->cond, &pmutex->lock, &end_time);
177
178   if (result != ETIMEDOUT)
179     {
180       PTHREAD_CHECK ("pthread_cond_timedwait", result);
181     }
182   
183   /* return true if we did not time out */
184   return result != ETIMEDOUT;
185 }
186
187 static void
188 _dbus_pthread_condvar_wake_one (DBusCondVar *cond)
189 {
190   DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
191
192   PTHREAD_CHECK ("pthread_cond_signal", pthread_cond_signal (&pcond->cond));
193 }
194
195 static void
196 _dbus_pthread_condvar_wake_all (DBusCondVar *cond)
197 {
198   DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
199   
200   PTHREAD_CHECK ("pthread_cond_broadcast", pthread_cond_broadcast (&pcond->cond));
201 }
202
203 static const DBusThreadFunctions pthread_functions =
204 {
205   DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
206   DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
207   DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
208   DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
209   DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
210   DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
211   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
212   DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
213   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
214   DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
215   _dbus_pthread_mutex_new,
216   _dbus_pthread_mutex_free,
217   _dbus_pthread_mutex_lock,
218   _dbus_pthread_mutex_unlock,
219   _dbus_pthread_condvar_new,
220   _dbus_pthread_condvar_free,
221   _dbus_pthread_condvar_wait,
222   _dbus_pthread_condvar_wait_timeout,
223   _dbus_pthread_condvar_wake_one,
224   _dbus_pthread_condvar_wake_all
225 };
226
227 dbus_bool_t
228 _dbus_threads_init_platform_specific (void)
229 {
230   return dbus_threads_init (&pthread_functions);
231 }