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