rendezvous.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : rendezvous                                                        *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *******************************************************************************
00007 * Copyright (c) 2001-$now By Author.  This program is free software; you can  *
00008 * redistribute it and/or modify it under the terms of the GNU General Public  *
00009 * License as published by the Free Software Foundation; either version 2 of   *
00010 * the License or (at your option) any later version.  This is online at:      *
00011 *     http://www.fsf.org/copyleft/gpl.html                                    *
00012 * Please send any updates to: fred@gruntose.com                               *
00013 \*****************************************************************************/
00014 
00015 //note: after repeated investigation, it seems that if we unlink the rendezvous
00016 //      file on destruction, then this hoses up any locks attempted ever after.
00017 //      instead of waiting for a lock, new attempts think they can go ahead,
00018 //      even though someone else might also have been given the lock.  it seems
00019 //      we cannot remove the files without destroying the semantics.
00020 
00021 #include "rendezvous.h"
00022 
00023 #include <application/windoze_helper.h>
00024 #include <basis/astring.h>
00025 #include <basis/functions.h>
00026 #include <basis/utf_conversion.h>
00027 #include <filesystem/filename.h>
00028 
00029 #ifdef __UNIX__
00030   #include <stdio.h>
00031   #include <sys/stat.h>
00032   #include <unistd.h>
00033 #endif
00034 
00035 using namespace basis;
00036 using namespace filesystem;
00037 
00038 namespace processes {
00039 
00040 //#define DEBUG_RENDEZVOUS
00041   // uncomment for a noisier file.
00042 
00043 #undef LOG
00044 #define LOG(tp) printf("%s%s\n", time_stamp::notarize(true).s(), astring(tp).s())
00045   // we can only use simple logging here since the rendezvous is relied on
00046   // at very low levels and use of a log_base object would cause infinite
00047   // loops.
00048 
00049 // used for the name of a mutex or part of the unix lock filename.
00050 astring general_lock_name(const astring &root_part)
00051 { return root_part + "_app_lock"; }
00052 
00053 #ifdef __UNIX__
00054 // the name of the locking file used in unix.
00055 astring unix_rendez_file(const astring &lock_name)
00056 {
00057   astring clean_name = lock_name;
00058   // remove troublesome characters from the name.
00059   filename::detooth_filename(clean_name);
00060   // make sure our target directory exists.
00061 
00062   // this choice is only user specific.
00063 //  astring tmp_dir = portable::env_string("TMP") + "/rendezvous";
00064 
00065   // this choice uses a system-wide location.
00066   astring tmp_dir = "/tmp/rendezvous";
00067 
00068   mkdir(tmp_dir.observe(), 0777);
00069   return tmp_dir + "/ren_" + clean_name;
00070 }
00071 #endif
00072 
00073 rendezvous::rendezvous(const astring &root_name)
00074 : _handle(NIL),
00075   _locked(false),
00076   _root_name(new astring(root_name))
00077 {
00078 #ifdef DEBUG_RENDEZVOUS
00079   FUNCDEF("constructor");
00080 #endif
00081   astring lock_name = general_lock_name(root_name);
00082 #ifdef __UNIX__
00083   astring real_name = unix_rendez_file(lock_name);
00084   FILE *locking_file = fopen(real_name.s(), "wb");
00085   if (!locking_file) {
00086 #ifdef DEBUG_RENDEZVOUS
00087     LOG(astring("failure to create locking file ") + real_name
00088         + ": " + critical_events::system_error_text(critical_events::system_error()) );
00089 #endif
00090     return;
00091   }
00092   // success now.
00093   _handle = locking_file;
00094 #endif
00095 #ifdef __WIN32__
00096   _handle = CreateMutex(NIL, false, to_unicode_temp(lock_name));
00097   if (!_handle) return;
00098 #endif
00099 }
00100 
00101 rendezvous::~rendezvous()
00102 {
00103 #ifdef DEBUG_RENDEZVOUS
00104   FUNCDEF("destructor");
00105   LOG("okay, into destructor for rendezvous.");
00106 #endif
00107 #ifdef __UNIX__
00108   if (_handle) {
00109     if (_locked) {
00110       int ret = lockf(fileno((FILE *)_handle), F_ULOCK, sizeof(int));
00111       if (ret) {
00112 #ifdef DEBUG_RENDEZVOUS
00113         LOG("failure to get lock on file.");
00114 #endif
00115       }
00116       _locked = false;  // clear our locked status since we no longer have one.
00117 
00118 //note: after repeated investigation, it seems that if we unlink the rendezvous
00119 //      file on destruction, then this hoses up any locks attempted ever after.
00120 //      instead of waiting for a lock, new attempts think they can go ahead,
00121 //      even though someone else might also have been given the lock.  it seems
00122 //      we cannot remove the files without destroying the semantics.
00123     }
00124 
00125     fclose((FILE *)_handle);
00126     _handle = NIL;
00127   }
00128 #endif
00129 #ifdef __WIN32__
00130   if (_handle) CloseHandle((HANDLE)_handle);
00131 #endif
00132   WHACK(_root_name);
00133 }
00134 
00135 void rendezvous::establish_lock() { lock(); }
00136 
00137 void rendezvous::repeal_lock() { unlock(); }
00138 
00139 bool rendezvous::healthy() const
00140 {
00141   return !!_handle;
00142 }
00143 
00144 bool rendezvous::lock(locking_methods how)
00145 {
00146 #ifdef DEBUG_RENDEZVOUS
00147   FUNCDEF("lock");
00148 #endif
00149   if (how == NO_LOCKING) return false;
00150   if (!healthy()) return false;
00151 #ifdef __UNIX__
00152   int command = F_TLOCK;
00153   if (how == ENDLESS_WAIT) command = F_LOCK;
00154   int ret = lockf(fileno((FILE *)_handle), command, sizeof(int));
00155   if (ret) {
00156 #ifdef DEBUG_RENDEZVOUS
00157     LOG("failure to get lock on file.");
00158 #endif
00159     return false;
00160   }
00161 #ifdef DEBUG_RENDEZVOUS
00162   LOG("okay, got lock on shared mem.");
00163 #endif
00164   _locked = true;
00165   return true;
00166 #endif
00167 #ifdef __WIN32__
00168   int timing = 0;  // immediate return.
00169   if (how == ENDLESS_WAIT) timing = INFINITE;
00170   int ret = WaitForSingleObject((HANDLE)_handle, timing);
00171   if ( (ret == WAIT_ABANDONED) || (ret == WAIT_TIMEOUT) ) return false;
00172   else if (ret != WAIT_OBJECT_0) {
00173 #ifdef DEBUG_RENDEZVOUS
00174     LOG("got an unanticipated error from waiting for the mutex.");
00175 #endif
00176     return false;
00177   }
00178   _locked = true;
00179   return true;
00180 #endif
00181   return false;
00182 }
00183 
00184 void rendezvous::unlock()
00185 {
00186 #ifdef DEBUG_RENDEZVOUS
00187   FUNCDEF("unlock");
00188 #endif
00189   if (!healthy()) return;
00190   if (_locked) {
00191 #ifdef __UNIX__
00192     int ret = lockf(fileno((FILE *)_handle), F_ULOCK, sizeof(int));
00193     if (ret) {
00194 #ifdef DEBUG_RENDEZVOUS
00195       LOG("failure to get lock on file.");
00196 #endif
00197     }
00198 #endif
00199 #ifdef __WIN32__
00200     ReleaseMutex((HANDLE)_handle);
00201 #endif
00202     _locked = false;
00203   } else {
00204 #ifdef DEBUG_RENDEZVOUS
00205     LOG("okay, rendezvous wasn't locked.");
00206 #endif
00207   }
00208 }
00209 
00210 } //namespace.
00211 
Generated on Sat Jan 28 04:22:24 2012 for hoople2 project by  doxygen 1.6.3