feisty meow concerns codebase 2.140
rendezvous.cpp
Go to the documentation of this file.
1/*****************************************************************************\
2* *
3* Name : rendezvous *
4* Author : Chris Koeritz *
5* *
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\*****************************************************************************/
14
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.
20
21#include "rendezvous.h"
22
24#include <basis/astring.h>
25#include <basis/functions.h>
27#include <filesystem/filename.h>
28
29#ifdef __UNIX__
30 #include <stdio.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33#endif
34
35using namespace basis;
36using namespace filesystem;
37
38namespace processes {
39
40//#define DEBUG_RENDEZVOUS
41 // uncomment for a noisier file.
42
43#undef LOG
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
47 // loops.
48
49// used for the name of a mutex or part of the unix lock filename.
51{ return root_part + "_app_lock"; }
52
53#ifdef __UNIX__
54// the name of the locking file used in unix.
56{
57 astring clean_name = lock_name;
58 // remove troublesome characters from the name.
60 // make sure our target directory exists.
61
62 // use a system-wide location for rendezvous state files.
63 astring tmp_dir = "/tmp/rendezvous";
64
65 mkdir(tmp_dir.observe(), 0777);
66 return tmp_dir + "/ren_" + clean_name;
67}
68#endif
69
71: _handle(NULL_POINTER),
72 _locked(false),
73 _root_name(new astring(root_name))
74{
75#ifdef DEBUG_RENDEZVOUS
76 FUNCDEF("constructor");
77#endif
79#ifdef __UNIX__
80 astring real_name = unix_rendez_file(lock_name);
81 FILE *locking_file = fopen(real_name.s(), "wb");
82 if (!locking_file) {
83#ifdef DEBUG_RENDEZVOUS
84 LOG(astring("failure to create locking file ") + real_name
85 + ": " + critical_events::system_error_text(critical_events::system_error()) );
86#endif
87 return;
88 }
89 // success now.
90 _handle = locking_file;
91#endif
92#ifdef __WIN32__
93 _handle = CreateMutex(NULL_POINTER, false, to_unicode_temp(lock_name));
94 if (!_handle) return;
95#endif
96}
97
99{
100#ifdef DEBUG_RENDEZVOUS
101 FUNCDEF("destructor");
102 LOG("okay, into destructor for rendezvous.");
103#endif
104#ifdef __UNIX__
105 if (_handle) {
106 if (_locked) {
107 int ret = lockf(fileno((FILE *)_handle), F_ULOCK, sizeof(int));
108 if (ret) {
109#ifdef DEBUG_RENDEZVOUS
110 LOG("failure to get lock on file.");
111#endif
112 }
113 _locked = false; // clear our locked status since we no longer have one.
114
115//note: after repeated investigation, it seems that if we unlink the rendezvous
116// file on destruction, then this hoses up any locks attempted ever after.
117// instead of waiting for a lock, new attempts think they can go ahead,
118// even though someone else might also have been given the lock. it seems
119// we cannot remove the files without destroying the semantics.
120 }
121
122 fclose((FILE *)_handle);
123 _handle = NULL_POINTER;
124 }
125#endif
126#ifdef __WIN32__
127 if (_handle) CloseHandle((HANDLE)_handle);
128#endif
129 WHACK(_root_name);
130}
131
133
135
137{
138 return !!_handle;
139}
140
142{
143#ifdef DEBUG_RENDEZVOUS
144 FUNCDEF("lock");
145#endif
146 if (how == NO_LOCKING) return false;
147 if (!healthy()) return false;
148#ifdef __UNIX__
149 int command = F_TLOCK;
150 if (how == ENDLESS_WAIT) command = F_LOCK;
151 int ret = lockf(fileno((FILE *)_handle), command, sizeof(int));
152 if (ret) {
153#ifdef DEBUG_RENDEZVOUS
154 LOG("failure to get lock on file.");
155#endif
156 return false;
157 }
158#ifdef DEBUG_RENDEZVOUS
159 LOG("okay, got lock on shared mem.");
160#endif
161 _locked = true;
162 return true;
163#endif
164#ifdef __WIN32__
165 int timing = 0; // immediate return.
166 if (how == ENDLESS_WAIT) timing = INFINITE;
167 int ret = WaitForSingleObject((HANDLE)_handle, timing);
168 if ( (ret == WAIT_ABANDONED) || (ret == WAIT_TIMEOUT) ) return false;
169 else if (ret != WAIT_OBJECT_0) {
170#ifdef DEBUG_RENDEZVOUS
171 LOG("got an unanticipated error from waiting for the mutex.");
172#endif
173 return false;
174 }
175 _locked = true;
176 return true;
177#endif
178 return false;
179}
180
182{
183#ifdef DEBUG_RENDEZVOUS
184 FUNCDEF("unlock");
185#endif
186 if (!healthy()) return;
187 if (_locked) {
188#ifdef __UNIX__
189 int ret = lockf(fileno((FILE *)_handle), F_ULOCK, sizeof(int));
190 if (ret) {
191#ifdef DEBUG_RENDEZVOUS
192 LOG("failure to get lock on file.");
193#endif
194 }
195#endif
196#ifdef __WIN32__
197 ReleaseMutex((HANDLE)_handle);
198#endif
199 _locked = false;
200 } else {
201#ifdef DEBUG_RENDEZVOUS
202 LOG("okay, rendezvous wasn't locked.");
203#endif
204 }
205}
206
207} //namespace.
208
#define fileno
Definition Xos2defs.h:27
#define mkdir
Definition Xos2defs.h:34
#define LOG(s)
Provides a dynamically resizable ASCII character string.
Definition astring.h:35
const char * s() const
synonym for observe. the 's' stands for "string", if that helps.
Definition astring.h:113
virtual const char * observe() const
observes the underlying pointer to the zero-terminated string.
Definition astring.cpp:140
static void detooth_filename(basis::astring &to_clean, char replacement='_')
takes any known illegal file system characters out of "to_clean".
Definition filename.cpp:452
locking_methods
different ways that the lock() attempt can be made.
Definition rendezvous.h:50
virtual void repeal_lock()
rendezvous(const basis::astring &root_name)
the healthy() method should be checked to ensure creation succeeded.
bool lock(locking_methods how=ENDLESS_WAIT)
grab the lock, if possible.
bool healthy() const
returns true if the rendezvous object is operable.
const basis::astring & root_name() const
returns the root name passed in the constructor.
void unlock()
releases a previously acquired lock.
virtual void establish_lock()
virtual ~rendezvous()
any lock held is released and the lower level structures freed.
#define NULL_POINTER
The value representing a pointer to nothing.
Definition definitions.h:32
#define FUNCDEF(func_in)
FUNCDEF sets the name of a function (and plugs it into the callstack).
Definition enhance_cpp.h:54
The guards collection helps in testing preconditions and reporting errors.
Definition array.h:30
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition functions.h:121
A platform independent way to obtain the timestamp of a file.
astring general_lock_name(const astring &root_part)
astring unix_rendez_file(const astring &lock_name)
Support for unicode builds.
Aids in achievement of platform independence.
void * HANDLE