Logging fixes.
[shibboleth/cpp-sp.git] / shib / shib-threads.cpp
1 /*
2  *  Copyright 2001-2005 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  * shib-threads.cpp -- an abstraction around Pthreads
19  *
20  * Created by:  Derek Atkins <derek@ihtfp.com>
21  *
22  * $Id: shib-threads.cpp,v 1.5 2003/01/30 15:18:36 warlord Exp $
23  */
24
25 #include "internal.h"
26 #include "shib-threads.h"
27
28 #ifdef HAVE_PTHREAD
29 #include <pthread.h>
30 #ifndef HAVE_PTHREAD_RWLOCK_INIT
31 #include <synch.h>
32 #endif
33 #else
34 #error "You need to create the proper thread implementation."
35 #endif
36
37 #include <stdexcept>
38
39 using namespace shibboleth::logging;
40 using namespace shibboleth;
41 using namespace std;
42
43 // pthread implementation of the Shib Target Threads API
44
45 //
46 // "Private" Implementation
47 //
48
49 class ThreadImpl : public Thread {
50 public:
51   ThreadImpl(void* (*start_routine)(void*), void* arg);
52   ~ThreadImpl() {}
53
54   int detach() { return pthread_detach(thread_id); }
55   int join(void** thread_return) { return pthread_join(thread_id, thread_return); }
56   int kill(int signo) { return pthread_kill(thread_id, signo); }
57
58   pthread_t     thread_id;
59 };
60
61 class MutexImpl : public Mutex {
62 public:
63   MutexImpl();
64   ~MutexImpl() { pthread_mutex_destroy (&mutex); }
65
66   int lock() { return pthread_mutex_lock (&mutex); }
67   int unlock() { return pthread_mutex_unlock (&mutex); }
68
69   pthread_mutex_t mutex;
70 };
71
72 class CondWaitImpl : public CondWait {
73 public:
74   CondWaitImpl();
75   ~CondWaitImpl() { pthread_cond_destroy (&cond); }
76
77   int wait(Mutex* mutex) { return wait (dynamic_cast<MutexImpl*>(mutex)); }
78   int wait(MutexImpl* mutex) { return pthread_cond_wait (&cond, &(mutex->mutex)); }
79   int timedwait(Mutex* mutex, int delay_seconds)
80         { return timedwait (dynamic_cast<MutexImpl*>(mutex), delay_seconds); }
81   int timedwait(MutexImpl* mutex, int delay_seconds) {
82     struct timespec ts;
83     memset (&ts, 0, sizeof(ts));
84     ts.tv_sec = time(NULL) + delay_seconds;
85     return pthread_cond_timedwait (&cond, &(mutex->mutex), &ts);
86   }
87   int signal() { return pthread_cond_signal (&cond); }
88   int broadcast() { return pthread_cond_broadcast (&cond); }
89
90   pthread_cond_t cond;
91 };
92
93 class RWLockImpl : public RWLock {
94 public:
95 #ifdef HAVE_PTHREAD_RWLOCK_INIT
96   RWLockImpl();
97   ~RWLockImpl() { pthread_rwlock_destroy (&lock); }
98
99   int rdlock() { return pthread_rwlock_rdlock (&lock); }
100   int wrlock() { return pthread_rwlock_wrlock (&lock); }
101   int unlock() { return pthread_rwlock_unlock (&lock); }
102
103   pthread_rwlock_t lock;
104 #else
105   RWLockImpl();
106   ~RWLockImpl() { rwlock_destroy (&lock); }
107
108   int rdlock() { return rw_rdlock (&lock); }
109   int wrlock() { return rw_wrlock (&lock); }
110   int unlock() { return rw_unlock (&lock); }
111
112   rwlock_t lock;
113 #endif
114 };
115
116 class ThreadKeyImpl : public ThreadKey {
117 public:
118   ThreadKeyImpl(void (*destroy_fcn)(void*));
119   ~ThreadKeyImpl() { pthread_key_delete (key); }
120
121   int setData(void* data) { return pthread_setspecific (key,data); }
122   void* getData() { return pthread_getspecific (key); }
123
124   pthread_key_t key;
125 };
126
127 //
128 // Constructor Implementation follows...
129 //
130
131 ThreadImpl::ThreadImpl(void* (*start_routine)(void*), void* arg)
132 {
133     int rc=pthread_create(&thread_id, NULL, start_routine, arg);
134     if (rc) {
135 #ifdef HAVE_STRERROR_R
136         char buf[256];
137         strerror_r(rc,buf,sizeof(buf));
138         buf[255]=0;
139         Category::getInstance(SHIB_LOGCAT".threads").error("pthread_create error (%d): %s",rc,buf);
140 #else
141         Category::getInstance(SHIB_LOGCAT".threads").error("pthread_create error (%d): %s",rc,strerror(rc));
142 #endif
143         throw rc;
144     }
145 }
146
147 MutexImpl::MutexImpl()
148 {
149     int rc=pthread_mutex_init(&mutex, NULL);
150     if (rc) {
151 #ifdef HAVE_STRERROR_R
152         char buf[256];
153         strerror_r(rc,buf,sizeof(buf));
154         buf[255]=0;
155         Category::getInstance(SHIB_LOGCAT".threads").error("pthread_mutex_init error (%d): %s",rc,buf);
156 #else
157         Category::getInstance(SHIB_LOGCAT".threads").error("pthread_mutex_init error (%d): %s",rc,strerror(rc));
158 #endif
159         throw rc;
160     }
161 }
162
163 CondWaitImpl::CondWaitImpl()
164 {
165     int rc=pthread_cond_init(&cond, NULL);
166     if (rc) {
167 #ifdef HAVE_STRERROR_R
168         char buf[256];
169         strerror_r(rc,buf,sizeof(buf));
170         buf[255]=0;
171         Category::getInstance(SHIB_LOGCAT".threads").error("pthread_cond_init error (%d): %s",rc,buf);
172 #else
173         Category::getInstance(SHIB_LOGCAT".threads").error("pthread_cond_init error (%d): %s",rc,strerror(rc));
174 #endif
175         throw rc;
176     }
177 }
178
179 RWLockImpl::RWLockImpl()
180 {
181 #ifdef HAVE_PTHREAD_RWLOCK_INIT
182     int rc=pthread_rwlock_init(&lock, NULL);
183 #else
184     int rc=rwlock_init(&lock, USYNC_THREAD, NULL);
185 #endif
186     if (rc) {
187 #ifdef HAVE_STRERROR_R
188         char buf[256];
189         strerror_r(rc,buf,sizeof(buf));
190         buf[255]=0;
191         Category::getInstance(SHIB_LOGCAT".threads").error("pthread_rwlock_init error (%d): %s",rc,buf);
192 #else
193         Category::getInstance(SHIB_LOGCAT".threads").error("pthread_rwlock_init error (%d): %s",rc,strerror(rc));
194 #endif
195         throw rc;
196     }
197 }
198
199 ThreadKeyImpl::ThreadKeyImpl(void (*destroy_fcn)(void*))
200 {
201     int rc=pthread_key_create(&key, destroy_fcn);
202     if (rc) {
203 #ifdef HAVE_STRERROR_R
204         char buf[256];
205         strerror_r(rc,buf,sizeof(buf));
206         buf[255]=0;
207         Category::getInstance(SHIB_LOGCAT".threads").error("pthread_key_create error (%d): %s",rc,buf);
208 #else
209         Category::getInstance(SHIB_LOGCAT".threads").error("pthread_key_create error (%d): %s",rc,strerror(rc));
210 #endif
211         throw rc;
212     }
213 }
214
215 //
216 // public "static" creation functions
217 //
218
219 Thread* Thread::create(void* (*start_routine)(void*), void* arg)
220 {
221   return new ThreadImpl(start_routine, arg);
222 }
223
224 void Thread::exit(void* return_val)
225 {
226   pthread_exit (return_val);
227 }
228     
229 void Thread::mask_all_signals(void)
230 {
231   sigset_t sigmask;
232   sigfillset(&sigmask);
233   Thread::mask_signals(SIG_BLOCK, &sigmask, NULL);
234 }
235
236 int Thread::mask_signals(int how, const sigset_t *newmask, sigset_t *oldmask)
237 {
238   return pthread_sigmask(how,newmask,oldmask);
239 }
240
241 Mutex * Mutex::create()
242 {
243   return new MutexImpl();
244 }
245
246 CondWait * CondWait::create()
247 {
248   return new CondWaitImpl();
249 }
250
251 RWLock * RWLock::create()
252 {
253   return new RWLockImpl();
254 }
255
256 ThreadKey* ThreadKey::create (void (*destroy_fcn)(void*))
257 {
258   return new ThreadKeyImpl(destroy_fcn);
259 }