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>
26 #include <basis/utf_conversion.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 
35 using namespace basis;
36 using namespace filesystem;
37 
38 namespace 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.
55 astring unix_rendez_file(const astring &lock_name)
56 {
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.
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 
70 rendezvous::rendezvous(const astring &root_name)
71 : _handle(NULL_POINTER),
72  _locked(false),
73  _root_name(new astring(root_name))
74 {
75 #ifdef DEBUG_RENDEZVOUS
76  FUNCDEF("constructor");
77 #endif
78  astring lock_name = general_lock_name(root_name);
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
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
locking_methods
different ways that the lock() attempt can be made.
Definition: rendezvous.h:50
virtual void repeal_lock()
Definition: rendezvous.cpp:134
bool lock(locking_methods how=ENDLESS_WAIT)
grab the lock, if possible.
Definition: rendezvous.cpp:141
bool healthy() const
returns true if the rendezvous object is operable.
Definition: rendezvous.cpp:136
void unlock()
releases a previously acquired lock.
Definition: rendezvous.cpp:181
virtual void establish_lock()
Definition: rendezvous.cpp:132
const basis::astring & root_name() const
returns the root name passed in the constructor.
virtual ~rendezvous()
any lock held is released and the lower level structures freed.
Definition: rendezvous.cpp:98
#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:57
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.
Definition: byte_filer.cpp:37
astring general_lock_name(const astring &root_part)
Definition: rendezvous.cpp:50
astring unix_rendez_file(const astring &lock_name)
Definition: rendezvous.cpp:55
#define LOG(tp)
Definition: rendezvous.cpp:44
Support for unicode builds.
Aids in achievement of platform independence.
void * HANDLE