X-Git-Url: https://feistymeow.org/gitweb/?a=blobdiff_plain;ds=inline;f=nucleus%2Flibrary%2Fprocesses%2Frendezvous.cpp;fp=nucleus%2Flibrary%2Fprocesses%2Frendezvous.cpp;h=3f3385e8e109c064cbc72232ad3cec02c55dd2a2;hb=457b128b77b5b4a0b7dd3094de543de2ce1477ad;hp=0000000000000000000000000000000000000000;hpb=32d7caf45d886d0d24e69eea00511c7815ac15d0;p=feisty_meow.git diff --git a/nucleus/library/processes/rendezvous.cpp b/nucleus/library/processes/rendezvous.cpp new file mode 100644 index 00000000..3f3385e8 --- /dev/null +++ b/nucleus/library/processes/rendezvous.cpp @@ -0,0 +1,211 @@ +/*****************************************************************************\ +* * +* Name : rendezvous * +* Author : Chris Koeritz * +* * +******************************************************************************* +* Copyright (c) 2001-$now By Author. This program is free software; you can * +* redistribute it and/or modify it under the terms of the GNU General Public * +* License as published by the Free Software Foundation; either version 2 of * +* the License or (at your option) any later version. This is online at: * +* http://www.fsf.org/copyleft/gpl.html * +* Please send any updates to: fred@gruntose.com * +\*****************************************************************************/ + +//note: after repeated investigation, it seems that if we unlink the rendezvous +// file on destruction, then this hoses up any locks attempted ever after. +// instead of waiting for a lock, new attempts think they can go ahead, +// even though someone else might also have been given the lock. it seems +// we cannot remove the files without destroying the semantics. + +#include "rendezvous.h" + +#include +#include +#include +#include +#include + +#ifdef __UNIX__ + #include + #include + #include +#endif + +using namespace basis; +using namespace filesystem; + +namespace processes { + +//#define DEBUG_RENDEZVOUS + // uncomment for a noisier file. + +#undef LOG +#define LOG(tp) printf("%s%s\n", time_stamp::notarize(true).s(), astring(tp).s()) + // we can only use simple logging here since the rendezvous is relied on + // at very low levels and use of a log_base object would cause infinite + // loops. + +// used for the name of a mutex or part of the unix lock filename. +astring general_lock_name(const astring &root_part) +{ return root_part + "_app_lock"; } + +#ifdef __UNIX__ +// the name of the locking file used in unix. +astring unix_rendez_file(const astring &lock_name) +{ + astring clean_name = lock_name; + // remove troublesome characters from the name. + filename::detooth_filename(clean_name); + // make sure our target directory exists. + + // this choice is only user specific. +// astring tmp_dir = portable::env_string("TMP") + "/rendezvous"; + + // this choice uses a system-wide location. + astring tmp_dir = "/tmp/rendezvous"; + + mkdir(tmp_dir.observe(), 0777); + return tmp_dir + "/ren_" + clean_name; +} +#endif + +rendezvous::rendezvous(const astring &root_name) +: _handle(NIL), + _locked(false), + _root_name(new astring(root_name)) +{ +#ifdef DEBUG_RENDEZVOUS + FUNCDEF("constructor"); +#endif + astring lock_name = general_lock_name(root_name); +#ifdef __UNIX__ + astring real_name = unix_rendez_file(lock_name); + FILE *locking_file = fopen(real_name.s(), "wb"); + if (!locking_file) { +#ifdef DEBUG_RENDEZVOUS + LOG(astring("failure to create locking file ") + real_name + + ": " + critical_events::system_error_text(critical_events::system_error()) ); +#endif + return; + } + // success now. + _handle = locking_file; +#endif +#ifdef __WIN32__ + _handle = CreateMutex(NIL, false, to_unicode_temp(lock_name)); + if (!_handle) return; +#endif +} + +rendezvous::~rendezvous() +{ +#ifdef DEBUG_RENDEZVOUS + FUNCDEF("destructor"); + LOG("okay, into destructor for rendezvous."); +#endif +#ifdef __UNIX__ + if (_handle) { + if (_locked) { + int ret = lockf(fileno((FILE *)_handle), F_ULOCK, sizeof(int)); + if (ret) { +#ifdef DEBUG_RENDEZVOUS + LOG("failure to get lock on file."); +#endif + } + _locked = false; // clear our locked status since we no longer have one. + +//note: after repeated investigation, it seems that if we unlink the rendezvous +// file on destruction, then this hoses up any locks attempted ever after. +// instead of waiting for a lock, new attempts think they can go ahead, +// even though someone else might also have been given the lock. it seems +// we cannot remove the files without destroying the semantics. + } + + fclose((FILE *)_handle); + _handle = NIL; + } +#endif +#ifdef __WIN32__ + if (_handle) CloseHandle((HANDLE)_handle); +#endif + WHACK(_root_name); +} + +void rendezvous::establish_lock() { lock(); } + +void rendezvous::repeal_lock() { unlock(); } + +bool rendezvous::healthy() const +{ + return !!_handle; +} + +bool rendezvous::lock(locking_methods how) +{ +#ifdef DEBUG_RENDEZVOUS + FUNCDEF("lock"); +#endif + if (how == NO_LOCKING) return false; + if (!healthy()) return false; +#ifdef __UNIX__ + int command = F_TLOCK; + if (how == ENDLESS_WAIT) command = F_LOCK; + int ret = lockf(fileno((FILE *)_handle), command, sizeof(int)); + if (ret) { +#ifdef DEBUG_RENDEZVOUS + LOG("failure to get lock on file."); +#endif + return false; + } +#ifdef DEBUG_RENDEZVOUS + LOG("okay, got lock on shared mem."); +#endif + _locked = true; + return true; +#endif +#ifdef __WIN32__ + int timing = 0; // immediate return. + if (how == ENDLESS_WAIT) timing = INFINITE; + int ret = WaitForSingleObject((HANDLE)_handle, timing); + if ( (ret == WAIT_ABANDONED) || (ret == WAIT_TIMEOUT) ) return false; + else if (ret != WAIT_OBJECT_0) { +#ifdef DEBUG_RENDEZVOUS + LOG("got an unanticipated error from waiting for the mutex."); +#endif + return false; + } + _locked = true; + return true; +#endif + return false; +} + +void rendezvous::unlock() +{ +#ifdef DEBUG_RENDEZVOUS + FUNCDEF("unlock"); +#endif + if (!healthy()) return; + if (_locked) { +#ifdef __UNIX__ + int ret = lockf(fileno((FILE *)_handle), F_ULOCK, sizeof(int)); + if (ret) { +#ifdef DEBUG_RENDEZVOUS + LOG("failure to get lock on file."); +#endif + } +#endif +#ifdef __WIN32__ + ReleaseMutex((HANDLE)_handle); +#endif + _locked = false; + } else { +#ifdef DEBUG_RENDEZVOUS + LOG("okay, rendezvous wasn't locked."); +#endif + } +} + +} //namespace. +