1 /*****************************************************************************\
4 * Author : Chris Koeritz *
6 *******************************************************************************
7 * Copyright (c) 2001-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
15 //note: after repeated investigation, it seems that if we unlink the rendezvous
16 // file on destruction, then this hoses up any locks attempted ever after.
17 // instead of waiting for a lock, new attempts think they can go ahead,
18 // even though someone else might also have been given the lock. it seems
19 // we cannot remove the files without destroying the semantics.
21 #include "rendezvous.h"
23 #include <application/windoze_helper.h>
24 #include <basis/astring.h>
25 #include <basis/functions.h>
26 #include <basis/utf_conversion.h>
27 #include <filesystem/filename.h>
35 using namespace basis;
36 using namespace filesystem;
40 //#define DEBUG_RENDEZVOUS
41 // uncomment for a noisier file.
44 #define LOG(tp) printf("%s%s\n", time_stamp::notarize(true).s(), astring(tp).s())
45 // we can only use simple logging here since the rendezvous is relied on
46 // at very low levels and use of a log_base object would cause infinite
49 // used for the name of a mutex or part of the unix lock filename.
50 astring general_lock_name(const astring &root_part)
51 { return root_part + "_app_lock"; }
54 // the name of the locking file used in unix.
55 astring unix_rendez_file(const astring &lock_name)
57 astring clean_name = lock_name;
58 // remove troublesome characters from the name.
59 filename::detooth_filename(clean_name);
60 // make sure our target directory exists.
62 // this choice is only user specific.
63 // astring tmp_dir = portable::env_string("TMP") + "/rendezvous";
65 // this choice uses a system-wide location.
66 astring tmp_dir = "/tmp/rendezvous";
68 mkdir(tmp_dir.observe(), 0777);
69 return tmp_dir + "/ren_" + clean_name;
73 rendezvous::rendezvous(const astring &root_name)
76 _root_name(new astring(root_name))
78 #ifdef DEBUG_RENDEZVOUS
79 FUNCDEF("constructor");
81 astring lock_name = general_lock_name(root_name);
83 astring real_name = unix_rendez_file(lock_name);
84 FILE *locking_file = fopen(real_name.s(), "wb");
86 #ifdef DEBUG_RENDEZVOUS
87 LOG(astring("failure to create locking file ") + real_name
88 + ": " + critical_events::system_error_text(critical_events::system_error()) );
93 _handle = locking_file;
96 _handle = CreateMutex(NIL, false, to_unicode_temp(lock_name));
101 rendezvous::~rendezvous()
103 #ifdef DEBUG_RENDEZVOUS
104 FUNCDEF("destructor");
105 LOG("okay, into destructor for rendezvous.");
110 int ret = lockf(fileno((FILE *)_handle), F_ULOCK, sizeof(int));
112 #ifdef DEBUG_RENDEZVOUS
113 LOG("failure to get lock on file.");
116 _locked = false; // clear our locked status since we no longer have one.
118 //note: after repeated investigation, it seems that if we unlink the rendezvous
119 // file on destruction, then this hoses up any locks attempted ever after.
120 // instead of waiting for a lock, new attempts think they can go ahead,
121 // even though someone else might also have been given the lock. it seems
122 // we cannot remove the files without destroying the semantics.
125 fclose((FILE *)_handle);
130 if (_handle) CloseHandle((HANDLE)_handle);
135 void rendezvous::establish_lock() { lock(); }
137 void rendezvous::repeal_lock() { unlock(); }
139 bool rendezvous::healthy() const
144 bool rendezvous::lock(locking_methods how)
146 #ifdef DEBUG_RENDEZVOUS
149 if (how == NO_LOCKING) return false;
150 if (!healthy()) return false;
152 int command = F_TLOCK;
153 if (how == ENDLESS_WAIT) command = F_LOCK;
154 int ret = lockf(fileno((FILE *)_handle), command, sizeof(int));
156 #ifdef DEBUG_RENDEZVOUS
157 LOG("failure to get lock on file.");
161 #ifdef DEBUG_RENDEZVOUS
162 LOG("okay, got lock on shared mem.");
168 int timing = 0; // immediate return.
169 if (how == ENDLESS_WAIT) timing = INFINITE;
170 int ret = WaitForSingleObject((HANDLE)_handle, timing);
171 if ( (ret == WAIT_ABANDONED) || (ret == WAIT_TIMEOUT) ) return false;
172 else if (ret != WAIT_OBJECT_0) {
173 #ifdef DEBUG_RENDEZVOUS
174 LOG("got an unanticipated error from waiting for the mutex.");
184 void rendezvous::unlock()
186 #ifdef DEBUG_RENDEZVOUS
189 if (!healthy()) return;
192 int ret = lockf(fileno((FILE *)_handle), F_ULOCK, sizeof(int));
194 #ifdef DEBUG_RENDEZVOUS
195 LOG("failure to get lock on file.");
200 ReleaseMutex((HANDLE)_handle);
204 #ifdef DEBUG_RENDEZVOUS
205 LOG("okay, rendezvous wasn't locked.");