libassa 3.5.0
|
#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.
: m_fd (-1), m_error (0), m_error_msg ("no errors") { trace_with_mask ("PidFileLock::PidFileLock", PIDFLOCK); l_whence = SEEK_SET; l_start = l_len = l_pid = 0; }
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().
{ trace_with_mask ("PidFileLock::~PidFileLock", PIDFLOCK); if (m_fd != -1) { if (unlock_region () == 0) { // if we had a lock DL((PIDFLOCK,"PID file unlocked.\n")); unlink (m_filename.c_str ()); DL((PIDFLOCK,"PID file removed.\n")); } close (m_fd); DL((PIDFLOCK,"PID lock file closed.\n")); } }
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.
{ trace_with_mask("PidFileLock::dump", PIDFLOCK); #if !defined (WIN32) DL((PIDFLOCK,"m_filename : \"%s\"\n", m_filename.c_str())); DL((PIDFLOCK,"m_error : %d\n", get_error ())); DL((PIDFLOCK,"m_error_msg: \"%s\"\n", get_error_msg ())); DL((PIDFLOCK,"m_fd : %d\n", m_fd)); if (m_fd == -1) return; test_region (); if (this->l_type == F_RDLCK) DL((PIDFLOCK,"l_type : F_RDLCK")); if (this->l_type == F_WRLCK) DL((PIDFLOCK,"l_type : F_WRLCK")); if (this->l_type == F_UNLCK) DL((PIDFLOCK,"l_type : F_UNLCK")); DL((PIDFLOCK,"l_whence : %s\n", this->l_whence == SEEK_SET ? "SEEK_SET" : this->l_whence == SEEK_CUR ? "SEEK_CUR" : "SEEK_END")); DL((PIDFLOCK,"l_start : %d\n", this->l_start)); DL((PIDFLOCK,"l_len : %d\n", this->l_len )); DL((PIDFLOCK,"l_pid : %ld\n", this->l_pid )); #endif // !def WIN32 }
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().
{ return m_error_msg.c_str (); }
int PidFileLock::get_lock_status | ( | ) | [private] |
Retrieve lock status.
Read the file descriptor's flags.
On POSIX-compliant systems, on input to fcntl(F_GETLK), the l_type describes a lock we would like to place on the file. If the lock could be placed, fcntl() does not actually place it, but returns F_UNLCK in the l_type and leaves the other fields of the structure unchanged. If, however, one or more incompatable locks would prevent this lock being placed, then fcntl() returns details about one of these locks in the l_type/l_whence/l_start/l_len fields and sets l_pid to be the PID of the process holding that lock. A lock can be removed explicitly with F_UNLCK or released automatically when the process terminates or if it closes any file descriptor referring to a file on which locks are held.
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().
{ trace_with_mask ("PidFileLock::get_lock_status", PIDFLOCK); int ret; #if defined (WIN32) return 0; #else #ifndef __CYGWIN__ // POSIX-compliant locking this->l_type = F_WRLCK; this->l_start = 0; this->l_whence = SEEK_SET; this->l_len = 0; ret = ::fcntl (m_fd, F_GETLK, static_cast<struct flock*>(this)); DL((PIDFLOCK,"fcntl(fd=%d, F_GETLK, %s) returned: %d\n", m_fd, (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"), ret)); if (ret < 0) { EL ((PIDFLOCK,"fcntl() failed. l_pid = %d\n", this->l_pid)); } return (ret); #else // CYGWIN if (lock_region_exclusive () < 0) { // why exclusive? if (unlock_region () < 0) { // already locked char buf[64]; pid_t pid; // someone else got it this->l_type = F_RDLCK; if (read (m_fd, buf, 64) > 0) { if (sscanf (buf, "%d", &pid) == 1) { this->l_pid = pid; } } else { this->l_pid = 1; // no real PID information } } } else { unlock_region (); // return the lock into its prestine state } return (0); #endif // !def CYGWIN #endif // !def WIN32 }
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().
{ trace_with_mask ("PidFileLock::lock", PIDFLOCK); #if defined(WIN32) return true; #else int val; int len; m_filename = Utils::strenv (fname_.c_str ()); val = len = 0; DL((PIDFLOCK,"PID lock file: \"%s\"\n", m_filename.c_str ())); if (open_pid_file (m_filename) < 0) { goto done; } DL((PIDFLOCK,"PID lock file opened and locked (fd=%d).\n", m_fd)); if (ftruncate (m_fd, 0) < 0) { log_error("ftruncate() error"); goto done; } DL((PIDFLOCK,"PID lock file truncated.\n")); if (write_pid () < 0) { log_error("write(PID) error"); goto done; } if ((val = ::fcntl(m_fd, F_GETFD, 0)) < 0) { log_error("fcntl(F_GETFD) error"); goto done; } val |= FD_CLOEXEC; if (::fcntl (m_fd, F_SETFD, val) < 0) { log_error("fcntl(F_SETFD) error"); goto done; } DL((PIDFLOCK,"CLOSE-ON-EXEC is set on FD.\n")); done: if (get_error () != 0) { ::close (m_fd); m_fd = -1; } return m_error == 0 ? true : false; #endif // !def WIN32 }
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().
{ trace_with_mask ("PidFileLock::lock_region", PIDFLOCK); int ret; #if defined (WIN32) return 0; #else #ifdef __CYGWIN__ this->l_type = F_RDLCK; // shared lock #else this->l_type = F_WRLCK; #endif this->l_start = 0; this->l_whence = SEEK_SET; this->l_len = 0; ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this)); DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, %s) returned: %d\n", m_fd, (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"), ret)); return (ret); #endif // !def WIN32 }
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().
{ trace_with_mask ("PidFileLock::lock_region_exclusive", PIDFLOCK); int ret = 0; #if defined (WIN32) return 0; #else #ifdef __CYGWIN__ this->l_type = F_WRLCK; // exclusive lock - read would fail this->l_start = 0; this->l_whence = SEEK_SET; this->l_len = 0; ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this)); DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_WRLCK) returned: %d\n", m_fd, ret)); #endif return (ret); #endif // !def WIN32 }
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().
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().
{ trace_with_mask("PidFileLock::open_pid_file", PIDFLOCK); #if !defined (WIN32) m_fd = ::open (fname_.c_str (), O_WRONLY|O_CREAT, 0644); if (m_fd < 0) { log_error("open() error."); return -1; } pid_t owner_pid; if ((owner_pid = test_region ()) > 0) { log_error ("PID file is already locked (by someone)."); m_error = EPERM; return -1; } if (lock_region () < 0) { if (errno == EACCES || errno == EAGAIN) { log_error("PID file is locked by another process"); } else { log_error("write lock error"); } return -1; } #endif // !def WIN32 return 0; }
pid_t PidFileLock::test_region | ( | ) | [private] |
Test if file is unlocked.
Test to see if file is locked by some other process.
If it is locked by us, return 0. If it is locked by some other process, return lock owner's PID.
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().
{ trace_with_mask ("PidFileLock::test_region", PIDFLOCK); int ret; #if defined (WIN32) return 0; #else ret = get_lock_status (); if (ret < 0) { DL((PIDFLOCK,"Failed to retrieve lock status.\n")); return 1; } if (this->l_type == F_UNLCK) { DL((PIDFLOCK,"Region is not locked.\n")); return(0); } DL((PIDFLOCK,"Region is already locked by PID %d\n", this->l_pid)); return (this->l_pid); #endif // !def WIN32 }
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().
{ trace_with_mask ("PidFileLock::unlock_region", PIDFLOCK); int ret; #if defined (WIN32) return 0; #else this->l_type = F_UNLCK; this->l_start = 0; this->l_whence = SEEK_SET; this->l_len = 0; ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this)); DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_UNLCK) returned: %d\n", m_fd, ret)); return (ret); #endif // !def WIN32 }
int PidFileLock::write_pid | ( | ) | [private] |
Write our process pid to the lock file.
Cygwin does not have POSIX semantics for locks.
We need to remove shared lock and then get an exclusive lock to write our PID. Then remove the exclusive lock and replace it with the shared lock. This leave two chances for another process to steal the lock from us, but this is the best we can do.
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().
{ trace_with_mask ("PidFileLock::write_pid", PIDFLOCK); #if defined (WIN32) return 0; #else std::ostringstream mypid; size_t len; this->l_pid = getpid (); mypid << this->l_pid << std::ends; len = strlen (mypid.str ().c_str ()); #ifdef __CYGWIN__ unlock_region (); // remove shared (weak) lock lock_region_exclusive (); if (write (m_fd, mypid.str ().c_str (), len) != len) { return -1; } DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", l_pid)); unlock_region (); // give up the exclusive lock lock_region (); // place shared (weak) lock #else // POSIX-compliant locks if (write (m_fd, mypid.str ().c_str (), len) != len) { return -1; } DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", this->l_pid)); #endif return 0; #endif // !def WIN32 }
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().