43437e75f501b291a3b4529e0c109739c05e7083
[shibboleth/cpp-xmltooling.git] / xmltooling / util / PThreads.cpp
1 /*
2  *  Copyright 2001-2010 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 "logging.h"
25 #include "util/Threads.h"
26
27 #include <ctime>
28 #include <signal.h>
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::logging;
40 using namespace xmltooling;
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, size_t stacksize);
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(nullptr) + 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, size_t stacksize)
180 {
181     int rc;
182
183     if (stacksize > 0) {
184         pthread_attr_t attrs;
185         rc = pthread_attr_init(&attrs);
186         if (rc) {
187             Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_attr_init error (%d)", rc);
188             throw ThreadingException("Thread creation failed.");
189         }
190         rc = pthread_attr_setstacksize(&attrs, stacksize);
191         if (rc) {
192             Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_attr_setstacksize error (%d)", rc);
193             throw ThreadingException("Thread creation failed.");
194         }
195         rc = pthread_create(&thread_id, &attrs, start_routine, arg);
196     }
197     else {
198         rc = pthread_create(&thread_id, nullptr, start_routine, arg);
199     }
200     if (rc) {
201 #ifdef HAVE_STRERROR_R
202         char buf[256];
203         strerror_r(rc,buf,sizeof(buf));
204         buf[255]=0;
205         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_create error (%d): %s",rc,buf);
206 #else
207         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_create error (%d): %s",rc,strerror(rc));
208 #endif
209         throw ThreadingException("Thread creation failed.");
210     }
211 }
212
213 MutexImpl::MutexImpl()
214 {
215     int rc=pthread_mutex_init(&mutex, nullptr);
216     if (rc) {
217 #ifdef HAVE_STRERROR_R
218         char buf[256];
219         strerror_r(rc,buf,sizeof(buf));
220         buf[255]=0;
221         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_mutex_init error (%d): %s",rc,buf);
222 #else
223         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_mutex_init error (%d): %s",rc,strerror(rc));
224 #endif
225         throw ThreadingException("Mutex creation failed.");
226     }
227 }
228
229 CondWaitImpl::CondWaitImpl()
230 {
231     int rc=pthread_cond_init(&cond, nullptr);
232     if (rc) {
233 #ifdef HAVE_STRERROR_R
234         char buf[256];
235         strerror_r(rc,buf,sizeof(buf));
236         buf[255]=0;
237         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_cond_init error (%d): %s",rc,buf);
238 #else
239         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_cond_init error (%d): %s",rc,strerror(rc));
240 #endif
241         throw ThreadingException("Condition variable creation failed.");
242     }
243 }
244
245 RWLockImpl::RWLockImpl()
246 {
247 #ifdef HAVE_PTHREAD_RWLOCK_INIT
248     int rc=pthread_rwlock_init(&lock, nullptr);
249 #else
250     int rc=rwlock_init(&lock, USYNC_THREAD, nullptr);
251 #endif
252     if (rc) {
253 #ifdef HAVE_STRERROR_R
254         char buf[256];
255         strerror_r(rc,buf,sizeof(buf));
256         buf[255]=0;
257         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_rwlock_init error (%d): %s",rc,buf);
258 #else
259         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_rwlock_init error (%d): %s",rc,strerror(rc));
260 #endif
261         throw ThreadingException("Shared lock creation failed.");
262     }
263 }
264
265 ThreadKeyImpl::ThreadKeyImpl(void (*destroy_fcn)(void*))
266 {
267     int rc=pthread_key_create(&key, destroy_fcn);
268     if (rc) {
269 #ifdef HAVE_STRERROR_R
270         char buf[256];
271         strerror_r(rc,buf,sizeof(buf));
272         buf[255]=0;
273         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_key_create error (%d): %s",rc,buf);
274 #else
275         Category::getInstance(XMLTOOLING_LOGCAT".Threads").error("pthread_key_create error (%d): %s",rc,strerror(rc));
276 #endif
277         throw ThreadingException("Thread key creation failed.");
278     }
279 }
280
281 Thread* Thread::create(void* (*start_routine)(void*), void* arg, size_t stacksize)
282 {
283     return new ThreadImpl(start_routine, arg, stacksize);
284 }
285
286 void Thread::exit(void* return_val)
287 {
288     pthread_exit(return_val);
289 }
290
291 void Thread::sleep(int seconds)
292 {
293     sleep(seconds);
294 }
295
296 void Thread::mask_all_signals(void)
297 {
298     sigset_t sigmask;
299     sigfillset(&sigmask);
300     Thread::mask_signals(SIG_BLOCK, &sigmask, nullptr);
301 }
302
303 int Thread::mask_signals(int how, const sigset_t *newmask, sigset_t *oldmask)
304 {
305     return pthread_sigmask(how,newmask,oldmask);
306 }
307
308 Mutex * Mutex::create()
309 {
310     return new MutexImpl();
311 }
312
313 CondWait * CondWait::create()
314 {
315     return new CondWaitImpl();
316 }
317
318 RWLock * RWLock::create()
319 {
320     return new RWLockImpl();
321 }
322
323 ThreadKey* ThreadKey::create (void (*destroy_fcn)(void*))
324 {
325     return new ThreadKeyImpl(destroy_fcn);
326 }