Threading support.
[shibboleth/cpp-xmltooling.git] / xmltooling / util / PThreads.cpp
1 /*\r
2  *  Copyright 2001-2005 Internet2\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 /**\r
18  * PThreads.cpp\r
19  * \r
20  * Thread and locking wrappers for POSIX platforms\r
21  */\r
22 \r
23 #include "internal.h"\r
24 #include "util/Threads.h"\r
25 \r
26 #include <ctime>\r
27 #include <log4cpp/Category.hh>\r
28 \r
29 #ifdef HAVE_PTHREAD\r
30 # include <pthread.h>\r
31 # ifndef HAVE_PTHREAD_RWLOCK_INIT\r
32 #  include <synch.h>\r
33 # endif\r
34 #else\r
35 # error "This implementation is for POSIX platforms."\r
36 #endif\r
37 \r
38 using namespace xmltooling;\r
39 using namespace log4cpp;\r
40 using namespace std;\r
41 \r
42 namespace xmltooling {\r
43 \r
44     class XMLTOOL_DLLLOCAL ThreadImpl : public Thread {\r
45         pthread_t thread_id;\r
46     public:\r
47         ThreadImpl(void* (*start_routine)(void*), void* arg);\r
48         virtual ~ThreadImpl() {}\r
49     \r
50         int detach() {\r
51             return pthread_detach(thread_id);\r
52         }\r
53         \r
54         int join(void** thread_return) {\r
55             return pthread_join(thread_id, thread_return);\r
56         }\r
57         \r
58         int kill(int signo) {\r
59             return pthread_kill(thread_id, signo);\r
60         }\r
61     };\r
62     \r
63     class XMLTOOL_DLLLOCAL MutexImpl : public Mutex {\r
64         pthread_mutex_t mutex;\r
65     public:\r
66         MutexImpl();\r
67         virtual ~MutexImpl() {\r
68             pthread_mutex_destroy(&mutex);\r
69         }\r
70     \r
71         int lock() {\r
72             return pthread_mutex_lock(&mutex);\r
73         }\r
74         \r
75         int unlock() {\r
76             return pthread_mutex_unlock(&mutex);\r
77         }\r
78     };\r
79     \r
80     class XMLTOOL_DLLLOCAL CondWaitImpl : public CondWait {\r
81         pthread_cond_t cond;\r
82     public:\r
83         CondWaitImpl();\r
84         virtual ~CondWaitImpl() {\r
85             pthread_cond_destroy(&cond);\r
86         }\r
87     \r
88         int wait(Mutex* mutex) {\r
89             return wait(static_cast<MutexImpl*>(mutex));\r
90         }\r
91         \r
92         int wait(MutexImpl* mutex) {\r
93             return pthread_cond_wait(&cond, &(mutex->mutex));\r
94         }\r
95         \r
96         int timedwait(Mutex* mutex, int delay_seconds) {\r
97             return timedwait(static_cast<MutexImpl*>(mutex), delay_seconds);\r
98         }\r
99         \r
100         int timedwait(MutexImpl* mutex, int delay_seconds) {\r
101             struct timespec ts;\r
102             memset(&ts, 0, sizeof(ts));\r
103             ts.tv_sec = time(NULL) + delay_seconds;\r
104             return pthread_cond_timedwait(&cond, &(mutex->mutex), &ts);\r
105         }\r
106         \r
107         int signal() {\r
108             return pthread_cond_signal(&cond);\r
109         }\r
110         \r
111         int broadcast() {\r
112             return pthread_cond_broadcast(&cond);\r
113         }\r
114     };\r
115     \r
116     class XMLTOOL_DLLLOCAL RWLockImpl : public RWLock {\r
117 #ifdef HAVE_PTHREAD_RWLOCK_INIT\r
118         pthread_rwlock_t lock;\r
119     public:\r
120         RWLockImpl();\r
121         virtual ~RWLockImpl() {\r
122             pthread_rwlock_destroy(&lock);\r
123         }\r
124     \r
125         int rdlock() {\r
126             return pthread_rwlock_rdlock(&lock);\r
127         }\r
128         \r
129         int wrlock() {\r
130             return pthread_rwlock_wrlock(&lock);\r
131         }\r
132         \r
133         int unlock() {\r
134             return pthread_rwlock_unlock(&lock);\r
135         }\r
136 #else\r
137         rwlock_t lock;\r
138     public:\r
139         RWLockImpl();\r
140         virtual ~RWLockImpl() {\r
141             rwlock_destroy (&lock);\r
142         }\r
143     \r
144         int rdlock() {\r
145             return rw_rdlock(&lock);\r
146         }\r
147         \r
148         int wrlock() {\r
149             return rw_wrlock(&lock);\r
150         }\r
151         \r
152         int unlock() {\r
153             return rw_unlock(&lock);\r
154         }\r
155 #endif\r
156     };\r
157     \r
158     class XMLTOOL_DLLLOCAL ThreadKeyImpl : public ThreadKey {\r
159         pthread_key_t key;\r
160     public:\r
161         ThreadKeyImpl(void (*destroy_fcn)(void*));\r
162         virtual ~ThreadKeyImpl() {\r
163             pthread_key_delete(key);\r
164         }\r
165     \r
166         int setData(void* data) {\r
167             return pthread_setspecific(key,data);\r
168         }\r
169         \r
170         void* getData() const {\r
171             return pthread_getspecific(key);\r
172         }\r
173     };\r
174 \r
175 };\r
176 \r
177 ThreadImpl::ThreadImpl(void* (*start_routine)(void*), void* arg)\r
178 {\r
179     int rc=pthread_create(&thread_id, NULL, start_routine, arg);\r
180     if (rc) {\r
181 #ifdef HAVE_STRERROR_R\r
182         char buf[256];\r
183         strerror_r(rc,buf,sizeof(buf));\r
184         buf[255]=0;\r
185         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_create error (%d): %s",rc,buf);\r
186 #else\r
187         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_create error (%d): %s",rc,strerror(rc));\r
188 #endif\r
189         throw ThreadingException("Thread creation failed.");\r
190     }\r
191 }\r
192 \r
193 MutexImpl::MutexImpl()\r
194 {\r
195     int rc=pthread_mutex_init(&mutex, NULL);\r
196     if (rc) {\r
197 #ifdef HAVE_STRERROR_R\r
198         char buf[256];\r
199         strerror_r(rc,buf,sizeof(buf));\r
200         buf[255]=0;\r
201         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_mutex_init error (%d): %s",rc,buf);\r
202 #else\r
203         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_mutex_init error (%d): %s",rc,strerror(rc));\r
204 #endif\r
205         throw ThreadingException("Mutex creation failed.");\r
206     }\r
207 }\r
208 \r
209 CondWaitImpl::CondWaitImpl()\r
210 {\r
211     int rc=pthread_cond_init(&cond, NULL);\r
212     if (rc) {\r
213 #ifdef HAVE_STRERROR_R\r
214         char buf[256];\r
215         strerror_r(rc,buf,sizeof(buf));\r
216         buf[255]=0;\r
217         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_cond_init error (%d): %s",rc,buf);\r
218 #else\r
219         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_cond_init error (%d): %s",rc,strerror(rc));\r
220 #endif\r
221         throw ThreadingException("Condition variable creation failed.");\r
222     }\r
223 }\r
224 \r
225 RWLockImpl::RWLockImpl()\r
226 {\r
227 #ifdef HAVE_PTHREAD_RWLOCK_INIT\r
228     int rc=pthread_rwlock_init(&lock, NULL);\r
229 #else\r
230     int rc=rwlock_init(&lock, USYNC_THREAD, NULL);\r
231 #endif\r
232     if (rc) {\r
233 #ifdef HAVE_STRERROR_R\r
234         char buf[256];\r
235         strerror_r(rc,buf,sizeof(buf));\r
236         buf[255]=0;\r
237         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_rwlock_init error (%d): %s",rc,buf);\r
238 #else\r
239         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_rwlock_init error (%d): %s",rc,strerror(rc));\r
240 #endif\r
241         throw ThreadingException("Shared lock creation failed.");\r
242     }\r
243 }\r
244 \r
245 ThreadKeyImpl::ThreadKeyImpl(void (*destroy_fcn)(void*))\r
246 {\r
247     int rc=pthread_key_create(&key, destroy_fcn);\r
248     if (rc) {\r
249 #ifdef HAVE_STRERROR_R\r
250         char buf[256];\r
251         strerror_r(rc,buf,sizeof(buf));\r
252         buf[255]=0;\r
253         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_key_create error (%d): %s",rc,buf);\r
254 #else\r
255         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_key_create error (%d): %s",rc,strerror(rc));\r
256 #endif\r
257         throw ThreadingException("Thread key creation failed.");\r
258     }\r
259 }\r
260 \r
261 Thread* Thread::create(void* (*start_routine)(void*), void* arg)\r
262 {\r
263     return new ThreadImpl(start_routine, arg);\r
264 }\r
265 \r
266 void Thread::exit(void* return_val)\r
267 {\r
268     pthread_exit(return_val);\r
269 }\r
270     \r
271 void Thread::mask_all_signals(void)\r
272 {\r
273     sigset_t sigmask;\r
274     sigfillset(&sigmask);\r
275     Thread::mask_signals(SIG_BLOCK, &sigmask, NULL);\r
276 }\r
277 \r
278 int Thread::mask_signals(int how, const sigset_t *newmask, sigset_t *oldmask)\r
279 {\r
280     return pthread_sigmask(how,newmask,oldmask);\r
281 }\r
282 \r
283 Mutex * Mutex::create()\r
284 {\r
285     return new MutexImpl();\r
286 }\r
287 \r
288 CondWait * CondWait::create()\r
289 {\r
290     return new CondWaitImpl();\r
291 }\r
292 \r
293 RWLock * RWLock::create()\r
294 {\r
295     return new RWLockImpl();\r
296 }\r
297 \r
298 ThreadKey* ThreadKey::create (void (*destroy_fcn)(void*))\r
299 {\r
300     return new ThreadKeyImpl(destroy_fcn);\r
301 }\r