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