5269763726f2e4d0dbb7ac52467b32fd058802ae
[shibboleth/cpp-xmltooling.git] / xmltooling / util / Threads.h
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  * @file xmltooling/util/Threads.h
23  *
24  * Thread and locking wrappers.
25  */
26
27 #ifndef _xmltooling_threads_h
28 #define _xmltooling_threads_h
29
30 #include <xmltooling/exceptions.h>
31
32 #include <memory>
33 #include <signal.h>
34
35 namespace xmltooling
36 {
37     DECL_XMLTOOLING_EXCEPTION(ThreadingException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmltooling,XMLToolingException,Exceptions during threading/locking operations);
38
39     /**
40      * A class for manual thread creation and synchronization.
41      */
42     class XMLTOOL_API Thread
43     {
44         MAKE_NONCOPYABLE(Thread);
45     protected:
46         Thread() {}
47     public:
48         virtual ~Thread() {}
49
50         /**
51          * Disassociate from the thread.
52          *
53          * @return 0 for success, non-zero for failure
54          */
55         virtual int detach()=0;
56
57         /**
58          * Join with the thread and wait for its completion.
59          *
60          * @param thread_return holds the return value of the thread routine
61          * @return 0 for success, non-zero for failure
62          */
63         virtual int join(void** thread_return)=0;
64
65         /**
66          * Kill the thread.
67          *
68          * @param signo the signal to send to the thread
69          * @return 0 for success, non-zero for failure
70          */
71         virtual int kill(int signo)=0;
72
73         /**
74          * Creates a new thread object to run the supplied start routine.
75          *
76          * @param start_routine the function to execute on the thread
77          * @param arg           a parameter for the start routine
78          * @param stacksize     size of stack to use, or 0 for default
79          * @return  the created and running thread object
80          */
81         static Thread* create(void* (*start_routine)(void*), void* arg, size_t stacksize=0);
82
83         /**
84          * Exits a thread gracefully.
85          *
86          * @param return_val    the return value for the thread
87          */
88         static void exit(void* return_val);
89
90         /**
91          * Sleeps the current thread for the specified amount of time.
92          *
93          * @param seconds   time to sleep
94          */
95         static void sleep(int seconds);
96 #ifndef WIN32
97         /**
98          * Masks all signals from a thread.
99          */
100         static void mask_all_signals(void);
101
102         /**
103          * Masks specific signals from a thread.
104          *
105          * @param how
106          * @param newmask   the new signal mask
107          * @param oldmask   the old signal mask
108          * @return 0 for success, non-zero for failure
109          */
110         static int mask_signals(int how, const sigset_t *newmask, sigset_t *oldmask);
111 #endif
112     };
113
114     /**
115      * A class for managing Thread Local Storage values.
116      */
117     class XMLTOOL_API ThreadKey
118     {
119         MAKE_NONCOPYABLE(ThreadKey);
120     protected:
121         ThreadKey() {}
122     public:
123         virtual ~ThreadKey() {}
124
125         /**
126          * Sets the value for a TLS key.
127          *
128          * @param data  the value to set
129          * @return 0 for success, non-zero for failure
130          */
131         virtual int setData(void* data)=0;
132
133         /**
134          * Returns the value for a TLS key.
135          *
136          * @return the value or nullptr
137          */
138         virtual void* getData() const=0;
139
140         /**
141          * Creates a new TLS key.
142          *
143          * @param destroy_fn    a functon to cleanup key values
144          * @return the new key
145          */
146         static ThreadKey* create(void (*destroy_fn)(void*));
147
148 #ifdef WIN32
149         /**
150          * Allows system to notify TLS implementation when a thread completes.
151          *
152          * <p>Windows doesn't support TLS destructors, so only the DllMain detach
153          * notification can be used to trigger per-thread cleanup.
154          */
155         static void onDetach();
156 #endif
157     };
158
159     /**
160      * A class for managing exclusive access to resources.
161      */
162     class XMLTOOL_API Mutex
163     {
164         MAKE_NONCOPYABLE(Mutex);
165     protected:
166         Mutex() {}
167     public:
168         virtual ~Mutex() {}
169
170         /**
171          * Locks the mutex for exclusive access.
172          *
173          * @return 0 for success, non-zero for failure
174          */
175         virtual int lock()=0;
176
177         /**
178          * Unlocks the mutex for exclusive access.
179          *
180          * @return 0 for success, non-zero for failure
181          */
182         virtual int unlock()=0;
183
184         /**
185          * Creates a new mutex object.
186          *
187          * @return the new mutex
188          */
189         static Mutex* create();
190     };
191
192     /**
193      * A class for managing shared and exclusive access to resources.
194      */
195     class XMLTOOL_API RWLock
196     {
197         MAKE_NONCOPYABLE(RWLock);
198     protected:
199         RWLock() {}
200     public:
201         virtual ~RWLock() {}
202
203         /**
204          * Obtains a shared lock.
205          *
206          * @return 0 for success, non-zero for failure
207          */
208         virtual int rdlock()=0;
209
210         /**
211          * Obtains an exclusive lock.
212          *
213          * @return 0 for success, non-zero for failure
214          */
215         virtual int wrlock()=0;
216
217         /**
218          * Unlocks the lock.
219          *
220          * @return 0 for success, non-zero for failure
221          */
222         virtual int unlock()=0;
223
224         /**
225          * Creates a new read/write lock.
226          *
227          * @return the new lock
228          */
229         static RWLock* create();
230     };
231
232     /**
233      * A class for establishing queues on a mutex based on a periodic condition.
234      */
235     class XMLTOOL_API CondWait
236     {
237         MAKE_NONCOPYABLE(CondWait);
238     protected:
239         CondWait() {}
240     public:
241         virtual ~CondWait() {}
242
243         /**
244          * Waits for a condition variable using the supplied mutex as a queue.
245          *
246          * @param lock  mutex to queue on
247          * @return 0 for success, non-zero for failure
248          */
249         virtual int wait(Mutex* lock)=0;
250
251         /**
252          * Waits for a condition variable using the supplied mutex as a queue,
253          * but only for a certain time limit.
254          *
255          * @param lock          mutex to queue on
256          * @param delay_seconds maximum time to wait before waking up
257          * @return 0 for success, non-zero for failure
258          */
259         virtual int timedwait(Mutex* lock, int delay_seconds)=0;
260
261         /**
262          * Signal a single thread to wake up if a condition changes.
263          *
264          * @return 0 for success, non-zero for failure
265          */
266         virtual int signal()=0;
267
268         /**
269          * Signal all threads to wake up if a condition changes.
270          *
271          * @return 0 for success, non-zero for failure
272          */
273         virtual int broadcast()=0;
274
275         /**
276          * Creates a new condition variable.
277          *
278          * @return the new condition variable
279          */
280         static CondWait* create();
281     };
282
283     /**
284      * RAII wrapper for a mutex lock.
285      */
286     class XMLTOOL_API Lock {
287         MAKE_NONCOPYABLE(Lock);
288     public:
289         /**
290          * Locks and wraps the designated mutex.
291          *
292          * @param mtx mutex to lock
293          */
294         Lock(Mutex* mtx) : mutex(mtx) {
295             if (mutex)
296                 mutex->lock();
297         }
298
299         /**
300          * Locks and wraps the designated mutex.
301          *
302          * @param mtx mutex to lock
303          */
304         Lock(Mutex& mtx) : mutex(&mtx) {
305             mtx.lock();
306         }
307
308         /**
309          * Locks and wraps the designated mutex.
310          *
311          * @param mtx mutex to lock
312          */
313         Lock(std::auto_ptr<Mutex>& mtx) : mutex(mtx.get()) {
314             if (mutex)
315                 mutex->lock();
316         }
317
318         /**
319          * Unlocks the wrapped mutex.
320          */
321         ~Lock() {
322             if (mutex)
323                 mutex->unlock();
324         }
325
326     private:
327         Mutex* mutex;
328     };
329
330     /**
331      * RAII wrapper for a shared lock.
332      */
333     class XMLTOOL_API SharedLock {
334         MAKE_NONCOPYABLE(SharedLock);
335     public:
336         /**
337          * Locks and wraps the designated shared lock.
338          *
339          * @param lock      lock to acquire
340          * @param lockit    true if the lock should be acquired here, false if already acquired
341          */
342         SharedLock(RWLock* lock, bool lockit=true) : rwlock(lock) {
343             if (rwlock && lockit)
344                 rwlock->rdlock();
345         }
346
347         /**
348          * Locks and wraps the designated shared lock.
349          *
350          * @param lock      lock to acquire
351          * @param lockit    true if the lock should be acquired here, false if already acquired
352          */
353         SharedLock(std::auto_ptr<RWLock>& lock, bool lockit=true) : rwlock(lock.get()) {
354             if (rwlock && lockit)
355                 rwlock->rdlock();
356         }
357
358         /**
359          * Unlocks the wrapped shared lock.
360          */
361         ~SharedLock() {
362             if (rwlock)
363                 rwlock->unlock();
364         }
365
366     private:
367         RWLock* rwlock;
368     };
369
370 }
371
372 #endif /* _xmltooling_threads_h */