Browse Source

[2202] Interface of Mutex wrapper

Created with minimalistic set of functionality. Created a new library
for it, there'll be more thread-related stuff here.
Michal 'vorner' Vaner 12 years ago
parent
commit
88b2af9980

+ 2 - 0
configure.ac

@@ -1186,6 +1186,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/server_common/tests/Makefile
                  src/lib/util/Makefile
                  src/lib/util/io/Makefile
+                 src/lib/util/threads/Makefile
+                 src/lib/util/threads/tests/Makefile
                  src/lib/util/unittests/Makefile
                  src/lib/util/python/Makefile
                  src/lib/util/pyunittests/Makefile

+ 1 - 1
src/lib/util/Makefile.am

@@ -1,4 +1,4 @@
-SUBDIRS = . io unittests tests pyunittests python
+SUBDIRS = . io unittests tests pyunittests python threads
 
 AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/util -I$(top_builddir)/src/lib/util

+ 11 - 0
src/lib/util/threads/Makefile.am

@@ -0,0 +1,11 @@
+SUBDIRS = . tests
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+lib_LTLIBRARIES = libb10-threads.la
+libb10_threads_la_SOURCES = lock.h lock.cc
+libb10_threads_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.la
+
+CLEANFILES = *.gcno *.gcda

+ 15 - 0
src/lib/util/threads/lock.cc

@@ -0,0 +1,15 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include "lock.h"

+ 131 - 0
src/lib/util/threads/lock.h

@@ -0,0 +1,131 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef B10_THREAD_LOCK_H
+#define B10_THREAD_LOCK_H
+
+#include <boost/noncopyable.hpp>
+
+#include <cstdlib> // for NULL.
+
+namespace isc {
+namespace util {
+namespace thread {
+
+/// \brief Mutex with very simple interface
+///
+/// Since mutexes are very system dependant, we create our own wrapper around
+/// whatever is available on the system and hide it.
+///
+/// To use this mutex, create it and then lock and unlock it by creating the
+/// Mutex::Locker object.
+///
+/// Also, as mutex is a low-level system object, an error might happen at any
+/// operation with it. We convert many errors to the isc::InvalidOperation,
+/// since the errors usually happen only when used in a wrong way. Any methods,
+/// constructors or even destructors in this class can throw. Allocation errors
+/// are converted to std::bad_alloc (for example when OS-dependant limit of
+/// mutexes is exceeded).
+///
+/// The current interface is somewhat minimalistic. If we ever need more, we
+/// can add it later.
+class Mutex : public boost::noncopyable {
+public:
+    /// \brief Constructor.
+    ///
+    /// Creates a mutex. Depending on the parameter, it is either recursive
+    /// (the same thread may lock it multiple times, others wait; it must be
+    /// unlocked as many times to become really unlocked) or normal (can be
+    /// locked just once, if the same threads tries to lock it again, Bad
+    /// Things Happen).
+    ///
+    /// Depending on compilation parameters and OS, the mutex may or may not
+    /// do some error and sanity checking. However, such checking is meant
+    /// only to aid development, not rely on it as a feature.
+    ///
+    /// \param recursive If the thread should be recursive (lockable multiple
+    ///     times from the same thread) or not.
+    /// \throw std::bad_alloc In case allocation of something (memory, the
+    ///     OS mutex) fails.
+    /// \throw isc::InvalidOperation Other unspecified errors around the mutex.
+    ///     This should be rare.
+    Mutex(bool recursive = false);
+    /// \brief Destructor.
+    ///
+    /// Destroyes the mutex. It is not allowed to destroy a mutex which is
+    /// currently locked. This means a Locker created with this Mutex must
+    /// never live longer than the Mutex itself.
+    ///
+    /// \throw isc::InvalidOperation when the OS reports an error. This should
+    ///     generally happen only when the Mutex was used in a wrong way,
+    ///     meaning programmer error.
+    ~ Mutex();
+    /// \brief This holds a lock on a Mutex.
+    ///
+    /// To lock a mutex, create a locket. It'll get unlocked when the locker
+    /// is destroyed.
+    ///
+    /// If you create the locker on the stack or using some other "garbage
+    /// collecting" mechanism (auto_ptr, for example), it ensures exception
+    /// safety with regards to the mutex - it'll get released on the exit
+    /// of function no matter by what means.
+    class Locker : public boost::noncopyable {
+    public:
+        /// \brief Constructor.
+        ///
+        /// Locks the mutex. May block for extended period of time.
+        ///
+        /// \throw isc::InvalidOperation when OS reports error. This usually
+        ///     means an attempt to use the mutex in a wrong way (locking
+        ///     a non-recursive mutex a second time from the same thread,
+        ///     for example).
+        Locker(Mutex& mutex) :
+            mutex_(NULL)
+        {
+            // Set the mutex_ after we acquire the lock. This is because of
+            // exception safety. If lock() throws, it didn't work, so we must
+            // not unlock when we are destroyed. In such case, mutex_ is
+            // NULL and checked in the destructor.
+            mutex.lock();
+            mutex_ = &mutex;
+        }
+        /// \brief Destructor.
+        ///
+        /// Unlocks the mutex.
+        ///
+        /// \throw isc::InvalidOperation when OS repotrs error. This usually
+        ///     means an attempt to use the mutex in a wrong way (unlocking
+        ///     a mutex belonging to a differen thread).
+        ~ Locker() {
+            if (mutex_ != NULL) {
+                mutex_->unlock();
+            }
+        }
+    private:
+        Mutex* mutex_;
+    };
+private:
+    friend class Locker;
+    struct Impl;
+    Impl* impl_;
+    void lock();
+    void unlock();
+};
+
+
+}
+}
+}
+
+#endif

+ 34 - 0
src/lib/util/threads/tests/Makefile.am

@@ -0,0 +1,34 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+# XXX: we'll pollute the top builddir for creating a temporary test file
+# # used to bind a UNIX domain socket so we can minimize the risk of exceeding
+# # the limit of file name path size.
+AM_CPPFLAGS += -DTEST_DATA_TOPBUILDDIR=\"$(abs_top_builddir)\"
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS_ENVIRONMENT = \
+        $(LIBTOOL) --mode=execute $(VALGRIND_COMMAND)
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES  = run_unittests.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+
+run_unittests_LDADD = $(top_builddir)/src/lib/util/threads/libb10-threads.la
+run_unittests_LDADD += \
+        $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
+run_unittests_LDADD += $(GTEST_LDADD)
+endif
+
+noinst_PROGRAMS = $(TESTS)

+ 25 - 0
src/lib/util/threads/tests/run_unittests.cc

@@ -0,0 +1,25 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <gtest/gtest.h>
+#include <util/unittests/run_all.h>
+#include <stdlib.h>
+
+int
+main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    setenv("B10_LOCKFILE_DIR_FROM_BUILD", TEST_DATA_TOPBUILDDIR, 1);
+    return (isc::util::unittests::run_all());
+}