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