// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include "interprocess_sync_file.h"
+#include <util/interprocess_sync_file.h>
+#include <boost/weak_ptr.hpp>
+
+#include <map>
#include <string>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
+using namespace isc::util::thread;
+
namespace isc {
namespace util {
+namespace { // unnamed namespace
+
+typedef std::map<std::string, boost::weak_ptr<Mutex> > SyncMap;
+typedef boost::shared_ptr<Mutex> MutexPtr;
+
+Mutex sync_map_mutex;
+SyncMap sync_map;
+
+} // end of unnamed namespace
+
+InterprocessSyncFile::InterprocessSyncFile(const std::string& task_name) :
+ InterprocessSync(task_name),
+ fd_(-1)
+{
+ Mutex::Locker locker(sync_map_mutex);
+
+ SyncMap::iterator it = sync_map.find(task_name);
+ if (it != sync_map.end()) {
+ mutex_ = it->second.lock();
+ } else {
+ mutex_.reset(new Mutex());
+ sync_map[task_name] = mutex_;
+ }
+
+ // Lock on sync_map_mutex is automatically unlocked during
+ // destruction when basic block is exited.
+}
+
InterprocessSyncFile::~InterprocessSyncFile() {
if (fd_ != -1) {
// This will also release any applied locks.
// The lockfile will continue to exist, and we must not delete
// it.
}
+
+ Mutex::Locker locker(sync_map_mutex);
+
+ // Unref the shared mutex first.
+ mutex_.reset();
+
+ SyncMap::iterator it = sync_map.find(task_name_);
+ assert(it != sync_map.end());
+
+ if (it->second.expired()) {
+ sync_map.erase(it);
+ }
+
+ // Lock on sync_map_mutex is automatically unlocked during
+ // destruction when basic block is exited.
}
bool
return (true);
}
- if (do_lock(F_SETLKW, F_WRLCK)) {
- is_locked_ = true;
- return (true);
+ // First grab the thread lock...
+ mutex_->lock();
+
+ // ... then the file lock.
+ try {
+ if (do_lock(F_SETLKW, F_WRLCK)) {
+ is_locked_ = true;
+ return (true);
+ }
+ } catch (...) {
+ mutex_->unlock();
+ throw;
}
+ mutex_->unlock();
return (false);
}
return (true);
}
- if (do_lock(F_SETLK, F_WRLCK)) {
- is_locked_ = true;
- return (true);
+ // First grab the thread lock...
+ if (!mutex_->tryLock()) {
+ return (false);
+ }
+
+ // ... then the file lock.
+ try {
+ // ... then the file lock.
+ if (do_lock(F_SETLK, F_WRLCK)) {
+ is_locked_ = true;
+ return (true);
+ }
+ } catch (...) {
+ mutex_->unlock();
+ throw;
}
+ mutex_->unlock();
return (false);
}
return (true);
}
- if (do_lock(F_SETLKW, F_UNLCK)) {
- is_locked_ = false;
- return (true);
+ // First release the file lock...
+ if (do_lock(F_SETLKW, F_UNLCK) == 0) {
+ return (false);
}
- return (false);
+ mutex_->unlock();
+ is_locked_ = false;
+ return (true);
}
} // namespace util
#define __INTERPROCESS_SYNC_FILE_H__
#include <util/interprocess_sync.h>
+#include <util/threads/lock.h>
#include <exceptions/exceptions.h>
+#include <boost/shared_ptr.hpp>
+
namespace isc {
namespace util {
/// \param name Name of the synchronization task. This has to be
/// identical among the various processes that need to be
/// synchronized for the same task.
- InterprocessSyncFile(const std::string& task_name) :
- InterprocessSync(task_name), fd_(-1)
- {}
+ InterprocessSyncFile(const std::string& task_name);
/// \brief Destructor
virtual ~InterprocessSyncFile();
bool do_lock(int cmd, short l_type);
int fd_; ///< The descriptor for the open file
+
+ typedef boost::shared_ptr<isc::util::thread::Mutex> MutexPtr;
+ MutexPtr mutex_; ///< A mutex for mutual exclusion among threads
};
} // namespace util