#include <PidFileLock.h>
Public Member Functions | |
PidFileLock () | |
Constructor. | |
~PidFileLock () | |
Destructor. | |
bool | lock (const string &filename_) |
Lock the file. | |
int | get_error () const |
Return last errno value. | |
const char * | get_error_msg () const |
In case of error, return a verbal description of the last error. | |
void | dump () |
Write the state of the lock to debug file. | |
Private Member Functions | |
pid_t | open_pid_file (const std::string &fname_) |
Open pid file in a cross-platform way. | |
int | lock_region () |
Lock the entire file. | |
int | lock_region_exclusive () |
Lock the entire file (only under Cygwin). | |
int | unlock_region () |
Unlock the entire file. | |
int | get_lock_status () |
Retrieve lock status. | |
int | write_pid () |
Write our process pid to the lock file. | |
pid_t | test_region () |
Test if file is unlocked. | |
void | log_error (const char *msg_) |
Log an error message to the log file and set internal error to errno. | |
Private Attributes | |
string | m_filename |
Lock file name. | |
int | m_fd |
Lock file descriptor. | |
int | m_error |
Last system call error. | |
string | m_error_msg |
Error explanation. |
Definition at line 43 of file PidFileLock.h.
PidFileLock::PidFileLock | ( | ) |
Constructor.
Definition at line 32 of file PidFileLock.cpp.
References ASSA::PIDFLOCK, and trace_with_mask.
00032 : 00033 m_fd (-1), 00034 m_error (0), 00035 m_error_msg ("no errors") 00036 { 00037 trace_with_mask ("PidFileLock::PidFileLock", PIDFLOCK); 00038 00039 l_whence = SEEK_SET; 00040 l_start = l_len = l_pid = 0; 00041 }
PidFileLock::~PidFileLock | ( | ) |
Destructor.
If process is holds the lock on the file, file is removed from the file system.
Definition at line 44 of file PidFileLock.cpp.
References DL, m_fd, m_filename, ASSA::PIDFLOCK, trace_with_mask, and unlock_region().
00045 { 00046 trace_with_mask ("PidFileLock::~PidFileLock", PIDFLOCK); 00047 00048 if (m_fd != -1) { 00049 if (unlock_region () == 0) { // if we had a lock 00050 DL((PIDFLOCK,"PID file unlocked.\n")); 00051 00052 unlink (m_filename.c_str ()); 00053 DL((PIDFLOCK,"PID file removed.\n")); 00054 } 00055 close (m_fd); 00056 DL((PIDFLOCK,"PID lock file closed.\n")); 00057 } 00058 }
void PidFileLock::dump | ( | void | ) |
Write the state of the lock to debug file.
m_fd = -1
indicates that lock file is not opened.
Definition at line 384 of file PidFileLock.cpp.
References DL, get_error(), get_error_msg(), m_fd, m_filename, ASSA::PIDFLOCK, test_region(), and trace_with_mask.
00385 { 00386 trace_with_mask("PidFileLock::dump", PIDFLOCK); 00387 00388 #if !defined (WIN32) 00389 00390 DL((PIDFLOCK,"m_filename : \"%s\"\n", m_filename.c_str())); 00391 DL((PIDFLOCK,"m_error : %d\n", get_error ())); 00392 DL((PIDFLOCK,"m_error_msg: \"%s\"\n", get_error_msg ())); 00393 DL((PIDFLOCK,"m_fd : %d\n", m_fd)); 00394 00395 if (m_fd == -1) return; 00396 00397 test_region (); 00398 00399 if (this->l_type == F_RDLCK) 00400 DL((PIDFLOCK,"l_type : F_RDLCK")); 00401 00402 if (this->l_type == F_WRLCK) 00403 DL((PIDFLOCK,"l_type : F_WRLCK")); 00404 00405 if (this->l_type == F_UNLCK) 00406 DL((PIDFLOCK,"l_type : F_UNLCK")); 00407 00408 DL((PIDFLOCK,"l_whence : %s\n", 00409 this->l_whence == SEEK_SET ? "SEEK_SET" : 00410 this->l_whence == SEEK_CUR ? "SEEK_CUR" : "SEEK_END")); 00411 00412 DL((PIDFLOCK,"l_start : %d\n", this->l_start)); 00413 DL((PIDFLOCK,"l_len : %d\n", this->l_len )); 00414 DL((PIDFLOCK,"l_pid : %ld\n", this->l_pid )); 00415 00416 #endif // !def WIN32 00417 }
int ASSA::PidFileLock::get_error | ( | ) | const [inline] |
const char * ASSA::PidFileLock::get_error_msg | ( | ) | const [inline] |
In case of error, return a verbal description of the last error.
Definition at line 141 of file PidFileLock.h.
References m_error_msg.
Referenced by dump(), and ASSA::GenServer::init_internals().
00142 { 00143 return m_error_msg.c_str (); 00144 }
int PidFileLock::get_lock_status | ( | ) | [private] |
Retrieve lock status.
Read the file descriptor's flags.
CYGWIN port does not support F_GETLK command with fcntl() because: 1) LockFileEx() is not implemented on 9x/ME 2) Lock requests given to LockFileEx() may not overlap existing locked regions of the file. 3) There is not nearly a functionality similar to F_GETLK in the Win32 API.
Instead, we try to set a lock. We might fail even if we already hold the lock ourselves. If we fail, try to unlock the file, and if that fails, then we know that file is locked by someone else. This method is not reliable, of course, but that's the best we can do.
Definition at line 294 of file PidFileLock.cpp.
References DL, EL, lock_region_exclusive(), m_fd, ASSA::PIDFLOCK, trace_with_mask, and unlock_region().
Referenced by test_region().
00295 { 00296 trace_with_mask ("PidFileLock::get_lock_status", PIDFLOCK); 00297 int ret; 00298 00299 #if defined (WIN32) 00300 return 0; 00301 #else 00302 00303 #ifndef __CYGWIN__ // POSIX-compliant locking 00304 00305 this->l_type = F_WRLCK; 00306 this->l_start = 0; 00307 this->l_whence = SEEK_SET; 00308 this->l_len = 0; 00309 00310 ret = ::fcntl (m_fd, F_GETLK, static_cast<struct flock*>(this)); 00311 00312 DL((PIDFLOCK,"fcntl(fd=%d, F_GETLK, %s) returned: %d\n", 00313 m_fd, 00314 (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"), 00315 ret)); 00316 if (ret < 0) { 00317 EL ((PIDFLOCK,"fcntl() failed. l_pid = %d\n", this->l_pid)); 00318 } 00319 return (ret); 00320 00321 #else // CYGWIN 00322 00323 if (lock_region_exclusive () < 0) { // why exclusive? 00324 if (unlock_region () < 0) { // already locked 00325 char buf[64]; 00326 pid_t pid; // someone else got it 00327 this->l_type = F_RDLCK; 00328 if (read (m_fd, buf, 64) > 0) { 00329 if (sscanf (buf, "%d", &pid) == 1) { 00330 this->l_pid = pid; 00331 } 00332 } 00333 else { 00334 this->l_pid = 1; // no real PID information 00335 } 00336 } 00337 } 00338 else { 00339 unlock_region (); // return the lock into its prestine state 00340 } 00341 return (0); 00342 00343 #endif // !def CYGWIN 00344 00345 #endif // !def WIN32 00346 00347 }
bool PidFileLock::lock | ( | const string & | filename_ | ) |
Lock the file.
Now that we have the lock, truncate file to zero length
Store our PID in the file
Set close-on-exec flag
Definition at line 62 of file PidFileLock.cpp.
References DL, get_error(), log_error(), m_error, m_fd, m_filename, open_pid_file(), ASSA::PIDFLOCK, ASSA::Utils::strenv(), trace_with_mask, and write_pid().
Referenced by ASSA::GenServer::init_internals().
00063 { 00064 trace_with_mask ("PidFileLock::lock", PIDFLOCK); 00065 00066 #if defined(WIN32) 00067 return true; 00068 #else 00069 int val; 00070 int len; 00071 m_filename = Utils::strenv (fname_.c_str ()); 00072 val = len = 0; 00073 00074 DL((PIDFLOCK,"PID lock file: \"%s\"\n", m_filename.c_str ())); 00075 00076 if (open_pid_file (m_filename) < 0) { 00077 goto done; 00078 } 00079 DL((PIDFLOCK,"PID lock file opened and locked (fd=%d).\n", m_fd)); 00080 00083 if (ftruncate (m_fd, 0) < 0) { 00084 log_error("ftruncate() error"); 00085 goto done; 00086 } 00087 DL((PIDFLOCK,"PID lock file truncated.\n")); 00088 00091 if (write_pid () < 0) { 00092 log_error("write(PID) error"); 00093 goto done; 00094 } 00095 00098 if ((val = ::fcntl(m_fd, F_GETFD, 0)) < 0) { 00099 log_error("fcntl(F_GETFD) error"); 00100 goto done; 00101 } 00102 val |= FD_CLOEXEC; 00103 00104 if (::fcntl (m_fd, F_SETFD, val) < 0) { 00105 log_error("fcntl(F_SETFD) error"); 00106 goto done; 00107 } 00108 DL((PIDFLOCK,"CLOSE-ON-EXEC is set on FD.\n")); 00109 00110 done: 00111 if (get_error () != 0) { 00112 ::close (m_fd); 00113 m_fd = -1; 00114 } 00115 return m_error == 0 ? true : false; 00116 00117 #endif // !def WIN32 00118 }
int PidFileLock::lock_region | ( | ) | [private] |
Lock the entire file.
Definition at line 178 of file PidFileLock.cpp.
References DL, m_fd, ASSA::PIDFLOCK, and trace_with_mask.
Referenced by open_pid_file(), and write_pid().
00179 { 00180 trace_with_mask ("PidFileLock::lock_region", PIDFLOCK); 00181 int ret; 00182 00183 #if defined (WIN32) 00184 return 0; 00185 #else 00186 00187 #ifdef __CYGWIN__ 00188 this->l_type = F_RDLCK; // shared lock 00189 #else 00190 this->l_type = F_WRLCK; 00191 #endif 00192 00193 this->l_start = 0; 00194 this->l_whence = SEEK_SET; 00195 this->l_len = 0; 00196 00197 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this)); 00198 00199 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, %s) returned: %d\n", 00200 m_fd, 00201 (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"), 00202 ret)); 00203 00204 return (ret); 00205 00206 #endif // !def WIN32 00207 }
int PidFileLock::lock_region_exclusive | ( | ) | [private] |
Lock the entire file (only under Cygwin).
Definition at line 212 of file PidFileLock.cpp.
References DL, m_fd, ASSA::PIDFLOCK, and trace_with_mask.
Referenced by get_lock_status(), and write_pid().
00213 { 00214 trace_with_mask ("PidFileLock::lock_region_exclusive", PIDFLOCK); 00215 int ret = 0; 00216 00217 #if defined (WIN32) 00218 return 0; 00219 #else 00220 00221 #ifdef __CYGWIN__ 00222 this->l_type = F_WRLCK; // exclusive lock - read would fail 00223 this->l_start = 0; 00224 this->l_whence = SEEK_SET; 00225 this->l_len = 0; 00226 00227 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this)); 00228 00229 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_WRLCK) returned: %d\n", m_fd, ret)); 00230 #endif 00231 00232 return (ret); 00233 00234 #endif // !def WIN32 00235 }
void PidFileLock::log_error | ( | const char * | msg_ | ) | [private] |
Log an error message to the log file and set internal error to errno.
Definition at line 421 of file PidFileLock.cpp.
References ASSA::ASSAERR, EL, and m_error.
Referenced by lock(), and open_pid_file().
00422 { 00423 m_error = errno; 00424 EL((ASSAERR, 00425 "Error: \"Failed to get a lock on PID file - %s\".\n", msg_)); 00426 }
pid_t PidFileLock::open_pid_file | ( | const std::string & | fname_ | ) | [private] |
Open pid file in a cross-platform way.
Cygwin doesn't implement file locking via fcntl() - for it we test in one step.
If we cannot get lock status, or already have a lock, or if PID file is already locked by another process, then terminate. Otherwise (file is unlocked), proceed with locking.
Try to set a write lock on the entire file
Definition at line 435 of file PidFileLock.cpp.
References lock_region(), log_error(), m_error, m_fd, ASSA::PIDFLOCK, test_region(), and trace_with_mask.
Referenced by lock().
00436 { 00437 trace_with_mask("PidFileLock::open_pid_file", PIDFLOCK); 00438 00439 #if !defined (WIN32) 00440 00441 m_fd = ::open (fname_.c_str (), O_WRONLY|O_CREAT, 0644); 00442 if (m_fd < 0) { 00443 log_error("open() error."); 00444 return -1; 00445 } 00446 00451 pid_t owner_pid; 00452 if ((owner_pid = test_region ()) > 0) { 00453 log_error ("PID file is already locked (by someone)."); 00454 m_error = EPERM; 00455 return -1; 00456 } 00457 00460 if (lock_region () < 0) { 00461 if (errno == EACCES || errno == EAGAIN) { 00462 log_error("PID file is locked by another process"); 00463 } 00464 else { 00465 log_error("write lock error"); 00466 } 00467 return -1; 00468 } 00469 00470 #endif // !def WIN32 00471 00472 return 0; 00473 }
pid_t PidFileLock::test_region | ( | ) | [private] |
Test if file is unlocked.
Test to see if file is locked by some other process.
Definition at line 355 of file PidFileLock.cpp.
References DL, get_lock_status(), ASSA::PIDFLOCK, and trace_with_mask.
Referenced by dump(), and open_pid_file().
00356 { 00357 trace_with_mask ("PidFileLock::test_region", PIDFLOCK); 00358 int ret; 00359 00360 #if defined (WIN32) 00361 return 0; 00362 #else 00363 00364 ret = get_lock_status (); 00365 00366 if (ret < 0) { 00367 DL((PIDFLOCK,"Failed to retrieve lock status.\n")); 00368 return 1; 00369 } 00370 if (this->l_type == F_UNLCK) { 00371 DL((PIDFLOCK,"Region is not locked.\n")); 00372 return(0); 00373 } 00374 00375 DL((PIDFLOCK,"Region is already locked by PID %d\n", this->l_pid)); 00376 return (this->l_pid); 00377 00378 #endif // !def WIN32 00379 }
int PidFileLock::unlock_region | ( | ) | [private] |
Unlock the entire file.
Definition at line 239 of file PidFileLock.cpp.
References DL, m_fd, ASSA::PIDFLOCK, and trace_with_mask.
Referenced by get_lock_status(), write_pid(), and ~PidFileLock().
00240 { 00241 trace_with_mask ("PidFileLock::unlock_region", PIDFLOCK); 00242 int ret; 00243 00244 #if defined (WIN32) 00245 return 0; 00246 #else 00247 00248 this->l_type = F_UNLCK; 00249 this->l_start = 0; 00250 this->l_whence = SEEK_SET; 00251 this->l_len = 0; 00252 00253 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this)); 00254 00255 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_UNLCK) returned: %d\n", 00256 m_fd, ret)); 00257 00258 return (ret); 00259 00260 #endif // !def WIN32 00261 }
int PidFileLock::write_pid | ( | ) | [private] |
Write our process pid to the lock file.
Cygwin does not have POSIX semantics for locks.
An exclusive lock under Cygwin prevents other processes to even open a file for read-only operations!
Definition at line 132 of file PidFileLock.cpp.
References DL, ASSA::ends(), lock_region(), lock_region_exclusive(), m_fd, ASSA::PIDFLOCK, trace_with_mask, and unlock_region().
Referenced by lock().
00133 { 00134 trace_with_mask ("PidFileLock::write_pid", PIDFLOCK); 00135 00136 #if defined (WIN32) 00137 return 0; 00138 #else 00139 std::ostringstream mypid; 00140 size_t len; 00141 00142 this->l_pid = getpid (); 00143 mypid << this->l_pid << std::ends; 00144 len = strlen (mypid.str ().c_str ()); 00145 00146 #ifdef __CYGWIN__ 00147 00148 unlock_region (); // remove shared (weak) lock 00149 lock_region_exclusive (); 00150 00151 if (write (m_fd, mypid.str ().c_str (), len) != len) { 00152 return -1; 00153 } 00154 DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", l_pid)); 00155 unlock_region (); // give up the exclusive lock 00156 lock_region (); // place shared (weak) lock 00157 00158 #else // POSIX-compliant locks 00159 00160 if (write (m_fd, mypid.str ().c_str (), len) != len) { 00161 return -1; 00162 } 00163 DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", this->l_pid)); 00164 00165 #endif 00166 return 0; 00167 00168 #endif // !def WIN32 00169 }
int ASSA::PidFileLock::m_error [private] |
Last system call error.
Definition at line 126 of file PidFileLock.h.
Referenced by get_error(), lock(), log_error(), and open_pid_file().
string ASSA::PidFileLock::m_error_msg [private] |
int ASSA::PidFileLock::m_fd [private] |
Lock file descriptor.
Definition at line 123 of file PidFileLock.h.
Referenced by dump(), get_lock_status(), lock(), lock_region(), lock_region_exclusive(), open_pid_file(), unlock_region(), write_pid(), and ~PidFileLock().
string ASSA::PidFileLock::m_filename [private] |
Lock file name.
Definition at line 120 of file PidFileLock.h.
Referenced by dump(), lock(), and ~PidFileLock().