rendezvous.cpp

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

Generated on Fri Nov 21 04:29:55 2008 for HOOPLE Libraries by  doxygen 1.5.1