Browse Source

[1704] Add InterprocessSync interface and a file based implementation

Mukund Sivaraman 13 years ago
parent
commit
588bffd507

+ 2 - 0
src/lib/util/Makefile.am

@@ -4,6 +4,7 @@ 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
 AM_CPPFLAGS += -I$(top_srcdir)/src/lib/exceptions -I$(top_builddir)/src/lib/exceptions
 AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CPPFLAGS += -DLOCKFILE_DIR=\"${localstatedir}/${PACKAGE_NAME}\"
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 lib_LTLIBRARIES = libutil.la
@@ -12,6 +13,7 @@ libutil_la_SOURCES += locks.h lru_list.h
 libutil_la_SOURCES += strutil.h strutil.cc
 libutil_la_SOURCES += buffer.h io_utilities.h
 libutil_la_SOURCES += time_utilities.h time_utilities.cc
+libutil_la_SOURCES += interprocess_sync.h interprocess_sync_file.h interprocess_sync_file.cc
 libutil_la_SOURCES += range_utilities.h
 libutil_la_SOURCES += hash/sha1.h hash/sha1.cc
 libutil_la_SOURCES += encode/base16_from_binary.h

+ 60 - 0
src/lib/util/interprocess_sync.h

@@ -0,0 +1,60 @@
+// 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 __INTERPROCESS_SYNC_H__
+#define __INTERPROCESS_SYNC_H__
+
+#include <string>
+
+namespace isc {
+namespace util {
+
+class InterprocessSyncLocker;
+
+class InterprocessSync {
+public:
+    /// \brief Constructor
+    ///
+    /// Creates a interprocess synchronization object
+    InterprocessSync(const std::string component_name) : component_name_(component_name) {}
+
+    /// \brief Destructor
+    virtual ~InterprocessSync() {}
+
+    virtual InterprocessSyncLocker* getLocker() = 0;
+
+protected:
+    std::string component_name_;
+};
+
+class InterprocessSyncLocker {
+friend class InterprocessSync;
+public:
+    virtual bool lock() = 0;
+    virtual bool tryLock() = 0;
+    virtual bool unlock() = 0;
+
+    /// \brief Destructor
+    virtual ~InterprocessSyncLocker() {}
+
+protected:
+    InterprocessSyncLocker(InterprocessSync* sync) : sync_(sync), is_locked_(false) {}
+    InterprocessSync *sync_;
+    bool is_locked_;
+};
+
+} // namespace util
+} // namespace isc
+
+#endif // __INTERPROCESS_SYNC_H__

+ 173 - 0
src/lib/util/interprocess_sync_file.cc

@@ -0,0 +1,173 @@
+// 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 "interprocess_sync_file.h"
+
+#include <string>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+namespace isc {
+namespace util {
+
+InterprocessSyncFile::InterprocessSyncFile(const std::string component_name) :
+    InterprocessSync(component_name) {
+
+    std::string lockfile_path = LOCKFILE_DIR;
+
+    const char* const env = getenv("B10_FROM_SOURCE");
+    if (env != NULL) {
+        lockfile_path = env;
+    }
+
+    const char* const env2 = getenv("B10_FROM_SOURCE_LOCALSTATEDIR");
+    if (env2 != NULL) {
+        lockfile_path = env2;
+    }
+
+    lockfile_path += "/" + component_name_ + "_lockfile";
+
+    // Open the lockfile in the constructor so it doesn't do the access
+    // checks every time a message is logged.
+    mode_t mode = umask(0111);
+    fd_ = open(lockfile_path.c_str(), O_CREAT | O_RDWR, 0660);
+    umask(mode);
+
+    if (fd_ == -1) {
+        isc_throw(InterprocessSyncFileError,
+                  "Unable to use interprocess sync lockfile: " + lockfile_path);
+    }
+}
+
+InterprocessSyncFile::~InterprocessSyncFile() {
+    if (fd_ != -1) {
+        close(fd_);
+    }
+
+    // The lockfile will continue to exist, and we must not delete it.
+}
+
+InterprocessSyncLocker*
+InterprocessSyncFile::getLocker() {
+    InterprocessSyncLocker *locker = new InterprocessSyncFileLocker(this);
+    return locker;
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+
+InterprocessSyncFileLocker::InterprocessSyncFileLocker(InterprocessSync* sync) :
+    InterprocessSyncLocker(sync) {
+}
+
+InterprocessSyncFileLocker::~InterprocessSyncFileLocker() {
+    unlock();
+}
+
+bool
+InterprocessSyncFileLocker::lock() {
+    if (is_locked_) {
+        return (true);
+    }
+
+    InterprocessSyncFile *sync = dynamic_cast<InterprocessSyncFile*>(sync_);
+    int fd = sync->getFd();
+
+    if (fd != -1) {
+        struct flock lock;
+        int status;
+
+        // Acquire the exclusive lock
+        memset(&lock, 0, sizeof lock);
+        lock.l_type = F_WRLCK;
+        lock.l_whence = SEEK_SET;
+        lock.l_start = 0;
+        lock.l_len = 1;
+
+        status = fcntl(fd, F_SETLKW, &lock);
+        if (status == 0) {
+            is_locked_ = true;
+            return (true);
+        }
+    }
+
+    return (false);
+}
+
+bool
+InterprocessSyncFileLocker::tryLock() {
+    if (is_locked_) {
+        return (true);
+    }
+
+    InterprocessSyncFile *sync = dynamic_cast<InterprocessSyncFile*>(sync_);
+    int fd = sync->getFd();
+
+    if (fd != -1) {
+        struct flock lock;
+        int status;
+
+        // Acquire the exclusive lock
+        memset(&lock, 0, sizeof lock);
+        lock.l_type = F_WRLCK;
+        lock.l_whence = SEEK_SET;
+        lock.l_start = 0;
+        lock.l_len = 1;
+
+        status = fcntl(fd, F_SETLK, &lock);
+        if (status == 0) {
+            is_locked_ = true;
+            return (true);
+        }
+    }
+
+    return (false);
+}
+
+bool
+InterprocessSyncFileLocker::unlock() {
+    if (!is_locked_) {
+        return (true);
+    }
+
+    InterprocessSyncFile *sync = dynamic_cast<InterprocessSyncFile*>(sync_);
+    int fd = sync->getFd();
+
+    if (fd != -1) {
+        struct flock lock;
+        int status;
+
+        // Release the exclusive lock
+        memset(&lock, 0, sizeof lock);
+        lock.l_type = F_UNLCK;
+        lock.l_whence = SEEK_SET;
+        lock.l_start = 0;
+        lock.l_len = 1;
+
+        status = fcntl(fd, F_SETLKW, &lock);
+        if (status == 0) {
+            is_locked_ = false;
+            return (true);
+        }
+    }
+
+    return (false);
+}
+
+} // namespace util
+} // namespace isc

+ 69 - 0
src/lib/util/interprocess_sync_file.h

@@ -0,0 +1,69 @@
+// 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 __INTERPROCESS_SYNC_FILE_H__
+#define __INTERPROCESS_SYNC_FILE_H__
+
+#include "util/interprocess_sync.h"
+#include "exceptions/exceptions.h"
+
+namespace isc {
+namespace util {
+
+///
+/// \brief Exception that is thrown if it's not possible to open the
+/// lock file.
+///
+class InterprocessSyncFileError : public Exception {
+public:
+    InterprocessSyncFileError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+class InterprocessSyncFile : public InterprocessSync {
+public:
+    /// \brief Constructor
+    InterprocessSyncFile(const std::string component_name);
+
+    /// \brief Destructor
+    ~InterprocessSyncFile();
+
+    InterprocessSyncLocker* getLocker();
+
+    int getFd() {
+        return fd_;
+    }
+
+private:
+    int fd_;
+};
+
+class InterprocessSyncFileLocker : public InterprocessSyncLocker {
+friend class InterprocessSyncFile;
+public:
+    /// \brief Destructor
+    ~InterprocessSyncFileLocker();
+
+    bool lock();
+    bool tryLock();
+    bool unlock();
+
+protected:
+    InterprocessSyncFileLocker(InterprocessSync* sync);
+};
+
+} // namespace util
+} // namespace isc
+
+#endif // __INTERPROCESS_SYNC_FILE_H__