Merge branch '1.x' of ssh://authdev.it.ohio-state.edu/~scantor/git/cpp-xmltooling...
[shibboleth/cpp-xmltooling.git] / xmltooling / util / Threads.h
index 648b457..abb8c10 100644 (file)
-/*
- *  Copyright 2001-2007 Internet2
- * 
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the
+ * License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
  */
 
 /**
- * @file Threads.h
- * 
- * Thread and locking wrappers 
+ * @file xmltooling/util/Threads.h
+ *
+ * Thread and locking wrappers.
  */
 
 #ifndef _xmltooling_threads_h
 #define _xmltooling_threads_h
 
-#include <xmltooling/base.h>
 #include <xmltooling/exceptions.h>
 
+#include <signal.h>
+
 namespace xmltooling
 {
     DECL_XMLTOOLING_EXCEPTION(ThreadingException,XMLTOOL_EXCEPTIONAPI(XMLTOOL_API),xmltooling,XMLToolingException,Exceptions during threading/locking operations);
-    
+
     /**
      * A class for manual thread creation and synchronization.
      */
     class XMLTOOL_API Thread
     {
         MAKE_NONCOPYABLE(Thread);
-    public:
+    protected:
         Thread() {}
+    public:
         virtual ~Thread() {}
 
         /**
          * Disassociate from the thread.
-         * 
+         *
          * @return 0 for success, non-zero for failure
          */
         virtual int detach()=0;
-        
+
         /**
          * Join with the thread and wait for its completion.
-         * 
+         *
          * @param thread_return holds the return value of the thread routine
          * @return 0 for success, non-zero for failure
          */
         virtual int join(void** thread_return)=0;
-        
+
         /**
          * Kill the thread.
-         * 
+         *
          * @param signo the signal to send to the thread
          * @return 0 for success, non-zero for failure
          */
         virtual int kill(int signo)=0;
-        
+
         /**
          * Creates a new thread object to run the supplied start routine.
-         * 
+         *
          * @param start_routine the function to execute on the thread
          * @param arg           a parameter for the start routine
-         * @return  the created and running thread object 
+         * @param stacksize     size of stack to use, or 0 for default
+         * @return  the created and running thread object
          */
-        static Thread* create(void* (*start_routine)(void*), void* arg);
-        
+        static Thread* create(void* (*start_routine)(void*), void* arg, size_t stacksize=0);
+
         /**
          * Exits a thread gracefully.
-         * 
+         *
          * @param return_val    the return value for the thread
          */
         static void exit(void* return_val);
 
         /**
          * Sleeps the current thread for the specified amount of time.
-         * 
+         *
          * @param seconds   time to sleep
          */
-        static void sleep(int seconds);        
+        static void sleep(int seconds);
 #ifndef WIN32
         /**
-         * Masks all signals from a thread. 
+         * Masks all signals from a thread.
          */
         static void mask_all_signals(void);
-        
+
         /**
          * Masks specific signals from a thread.
-         * 
+         *
          * @param how
          * @param newmask   the new signal mask
          * @param oldmask   the old signal mask
@@ -109,13 +116,14 @@ namespace xmltooling
     class XMLTOOL_API ThreadKey
     {
         MAKE_NONCOPYABLE(ThreadKey);
-    public:
+    protected:
         ThreadKey() {}
+    public:
         virtual ~ThreadKey() {}
 
         /**
          * Sets the value for a TLS key.
-         * 
+         *
          * @param data  the value to set
          * @return 0 for success, non-zero for failure
          */
@@ -123,18 +131,28 @@ namespace xmltooling
 
         /**
          * Returns the value for a TLS key.
-         * 
-         * @return the value or NULL
-         */        
+         *
+         * @return the value or nullptr
+         */
         virtual void* getData() const=0;
 
         /**
          * Creates a new TLS key.
-         * 
+         *
          * @param destroy_fn    a functon to cleanup key values
          * @return the new key
          */
         static ThreadKey* create(void (*destroy_fn)(void*));
+
+#ifdef WIN32
+        /**
+         * Allows system to notify TLS implementation when a thread completes.
+         *
+         * <p>Windows doesn't support TLS destructors, so only the DllMain detach
+         * notification can be used to trigger per-thread cleanup.
+         */
+        static void onDetach();
+#endif
     };
 
     /**
@@ -143,121 +161,124 @@ namespace xmltooling
     class XMLTOOL_API Mutex
     {
         MAKE_NONCOPYABLE(Mutex);
-    public:
+    protected:
         Mutex() {}
+    public:
         virtual ~Mutex() {}
 
         /**
          * Locks the mutex for exclusive access.
-         * 
+         *
          * @return 0 for success, non-zero for failure
          */
         virtual int lock()=0;
-        
+
         /**
          * Unlocks the mutex for exclusive access.
-         * 
+         *
          * @return 0 for success, non-zero for failure
          */
         virtual int unlock()=0;
 
         /**
          * Creates a new mutex object.
-         * 
+         *
          * @return the new mutex
          */
         static Mutex* create();
     };
-    
+
     /**
      * A class for managing shared and exclusive access to resources.
      */
     class XMLTOOL_API RWLock
     {
         MAKE_NONCOPYABLE(RWLock);
-    public:
+    protected:
         RWLock() {}
+    public:
         virtual ~RWLock() {}
 
         /**
          * Obtains a shared lock.
-         * 
+         *
          * @return 0 for success, non-zero for failure
          */
         virtual int rdlock()=0;
-        
+
         /**
          * Obtains an exclusive lock.
-         * 
+         *
          * @return 0 for success, non-zero for failure
          */
         virtual int wrlock()=0;
 
         /**
          * Unlocks the lock.
-         * 
+         *
          * @return 0 for success, non-zero for failure
          */
         virtual int unlock()=0;
 
         /**
          * Creates a new read/write lock.
-         * 
+         *
          * @return the new lock
          */
         static RWLock* create();
     };
-    
+
     /**
      * A class for establishing queues on a mutex based on a periodic condition.
      */
     class XMLTOOL_API CondWait
     {
         MAKE_NONCOPYABLE(CondWait);
-    public:
+    protected:
         CondWait() {}
+    public:
         virtual ~CondWait() {}
-        
+
         /**
          * Waits for a condition variable using the supplied mutex as a queue.
-         * 
+         *
          * @param lock  mutex to queue on
          * @return 0 for success, non-zero for failure
          */
         virtual int wait(Mutex* lock)=0;
-        
+
         /**
          * Waits for a condition variable using the supplied mutex as a queue,
          * but only for a certain time limit.
-         * 
+         *
          * @param lock          mutex to queue on
          * @param delay_seconds maximum time to wait before waking up
          * @return 0 for success, non-zero for failure
          */
         virtual int timedwait(Mutex* lock, int delay_seconds)=0;
-        
+
         /**
          * Signal a single thread to wake up if a condition changes.
-         * 
+         *
          * @return 0 for success, non-zero for failure
          */
         virtual int signal()=0;
-        
+
         /**
          * Signal all threads to wake up if a condition changes.
-         * 
+         *
          * @return 0 for success, non-zero for failure
          */
         virtual int broadcast()=0;
 
         /**
          * Creates a new condition variable.
-         * 
+         *
          * @return the new condition variable
          */
         static CondWait* create();
     };
-    
+
     /**
      * RAII wrapper for a mutex lock.
      */
@@ -266,24 +287,26 @@ namespace xmltooling
     public:
         /**
          * Locks and wraps the designated mutex.
-         * 
-         * @param mtx mutex to lock 
+         *
+         * @param mtx mutex to lock
          */
         Lock(Mutex* mtx) : mutex(mtx) {
-            mutex->lock();
+            if (mutex)
+                mutex->lock();
         }
-        
+
         /**
          * Unlocks the wrapped mutex.
          */
         ~Lock() {
-            mutex->unlock();
+            if (mutex)
+                mutex->unlock();
         }
-    
+
     private:
         Mutex* mutex;
     };
-    
+
     /**
      * RAII wrapper for a shared lock.
      */
@@ -292,22 +315,23 @@ namespace xmltooling
     public:
         /**
          * Locks and wraps the designated shared lock.
-         * 
-         * @param lock      lock to acquire 
+         *
+         * @param lock      lock to acquire
          * @param lockit    true if the lock should be acquired here, false if already acquired
          */
         SharedLock(RWLock* lock, bool lockit=true) : rwlock(lock) {
-            if (lockit)
+            if (rwlock && lockit)
                 rwlock->rdlock();
         }
-        
+
         /**
          * Unlocks the wrapped shared lock.
          */
         ~SharedLock() {
-            rwlock->unlock();
+            if (rwlock)
+                rwlock->unlock();
         }
-    
+
     private:
         RWLock* rwlock;
     };