Loading...
Searching...
No Matches
ASSA::PidFileLock Class Reference

`#include <PidFileLock.h>`

Inheritance diagram for ASSA::PidFileLock:

## 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.

## Detailed Description

Definition at line 43 of file PidFileLock.h.

## Constructor & Destructor Documentation

## PidFileLock()

PidFileLock::PidFileLock | ( |  | ) |

Constructor.

Definition at line 31 of file PidFileLock.cpp.

:
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;
}
trace_with_mask
#define trace_with_mask(s, m)
trace_with_mask() is used to trace function call chain in C++ program.
Definition Logger.h:437
ASSA::PidFileLock::m_error
int m_error
Last system call error.
Definition PidFileLock.h:126
ASSA::PidFileLock::m_error_msg
string m_error_msg
Error explanation.
Definition PidFileLock.h:129
ASSA::PidFileLock::m_fd
int m_fd
Lock file descriptor.
Definition PidFileLock.h:123
ASSA::PIDFLOCK
@ PIDFLOCK
Class PidFileLock messages.
Definition LogMask.h:35

References m_error, m_error_msg, m_fd, ASSA::PIDFLOCK, and trace_with_mask.

## ~PidFileLock()

PidFileLock::~PidFileLock | ( |  | ) |

Destructor.

If process is holds the lock on the file, file is removed from the file system.

Definition at line 43 of file PidFileLock.cpp.

{
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"));
}
}
DL
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
ASSA::PidFileLock::m_filename
string m_filename
Lock file name.
Definition PidFileLock.h:120
ASSA::PidFileLock::unlock_region
int unlock_region()
Unlock the entire file.
Definition PidFileLock.cpp:239

References DL, m_fd, m_filename, ASSA::PIDFLOCK, trace_with_mask, and unlock_region().

## Member Function Documentation

## dump()

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 383 of file PidFileLock.cpp.

{
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
}
ASSA::PidFileLock::get_error_msg
const char * get_error_msg() const
In case of error, return a verbal description of the last error.
Definition PidFileLock.h:141
ASSA::PidFileLock::get_error
int get_error() const
Return last errno value.
Definition PidFileLock.h:134
ASSA::PidFileLock::test_region
pid_t test_region()
Test if file is unlocked.
Definition PidFileLock.cpp:355

References DL, get_error(), get_error_msg(), m_fd, m_filename, ASSA::PIDFLOCK, test_region(), and trace_with_mask.

## get_error()

int ASSA::PidFileLock::get_error | ( |  | ) | const

inline

Return last errno value.

Returns
  0 for success, errno on error

Definition at line 133 of file PidFileLock.h.

{
return m_error;
}

References m_error.

Referenced by dump(), and lock().

## get_error_msg()

const char * ASSA::PidFileLock::get_error_msg | ( |  | ) | const

inline

In case of error, return a verbal description of the last error.

Definition at line 140 of file PidFileLock.h.

{
return m_error_msg.c_str ();
}

References m_error_msg.

Referenced by dump().

## get_lock_status()

int PidFileLock::get_lock_status | ( |  | ) |

private

Retrieve lock status.

Read the file descriptor's flags.

Returns
  -1 on error if failed, 0 on success.

    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 293 of file PidFileLock.cpp.

{
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
}
EL
#define EL(X)
A macro for writing error message to the Logger.
Definition Logger.h:285
ASSA::PidFileLock::lock_region_exclusive
int lock_region_exclusive()
Lock the entire file (only under Cygwin).
Definition PidFileLock.cpp:212

References DL, EL, lock_region_exclusive(), m_fd, ASSA::PIDFLOCK, trace_with_mask, and unlock_region().

Referenced by test_region().

## lock()

bool PidFileLock::lock | ( | const string & | filename_ | ) |

Lock the file.

Returns
  true on success, false on error

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 61 of file PidFileLock.cpp.

{
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
}
ASSA::PidFileLock::write_pid
int write_pid()
Write our process pid to the lock file.
Definition PidFileLock.cpp:132
ASSA::PidFileLock::open_pid_file
pid_t open_pid_file(const std::string &fname_)
Open pid file in a cross-platform way.
Definition PidFileLock.cpp:435
ASSA::PidFileLock::log_error
void log_error(const char *msg_)
Log an error message to the log file and set internal error to errno.
Definition PidFileLock.cpp:421
ASSA::Utils::strenv
std::string strenv(const char *in_)
Expand the passed string in_ by substituting environment variable names for their values.
Definition CommonUtils.cpp:123

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().

## lock_region()

int PidFileLock::lock_region | ( |  | ) |

private

Lock the entire file.

Returns
  -1 on error and if file is locked by some other process, errno is set to EAGAIN or EACCES; 0 on success.

Definition at line 177 of file PidFileLock.cpp.

{
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
}

References DL, m_fd, ASSA::PIDFLOCK, and trace_with_mask.

Referenced by open_pid_file(), and write_pid().

## lock_region_exclusive()

int PidFileLock::lock_region_exclusive | ( |  | ) |

private

Lock the entire file (only under Cygwin).

Returns
  -1 on error and if file is locked by some other process, errno is set to EAGAIN or EACCES; 0 on success.

Definition at line 211 of file PidFileLock.cpp.

{
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
}

References DL, m_fd, ASSA::PIDFLOCK, and trace_with_mask.

Referenced by get_lock_status(), and write_pid().

## log_error()

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 420 of file PidFileLock.cpp.

{
m_error = errno;
EL((ASSAERR,
"Error: \"Failed to get a lock on PID file - %s\".\n", msg_));
}
ASSA::ASSAERR
@ ASSAERR
ASSA and system errors.
Definition LogMask.h:34

References ASSA::ASSAERR, EL, and m_error.

Referenced by lock(), and open_pid_file().

## 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 434 of file PidFileLock.cpp.

{
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;
}
ASSA::PidFileLock::lock_region
int lock_region()
Lock the entire file.
Definition PidFileLock.cpp:178

References lock_region(), log_error(), m_error, m_fd, ASSA::PIDFLOCK, test_region(), and trace_with_mask.

Referenced by lock().

## test_region()

pid_t PidFileLock::test_region | ( |  | ) |

private

Test if file is unlocked.

Test to see if file is locked by some other process.

Returns
  0 if file is unlocked or the pid of the process that holds the lock otherwise.

If it is locked by us, return 0. If it is locked by some other process, return lock owner's PID.

Definition at line 354 of file PidFileLock.cpp.

{
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
}
ASSA::PidFileLock::get_lock_status
int get_lock_status()
Retrieve lock status.
Definition PidFileLock.cpp:294

References DL, get_lock_status(), ASSA::PIDFLOCK, and trace_with_mask.

Referenced by dump(), and open_pid_file().

## unlock_region()

int PidFileLock::unlock_region | ( |  | ) |

private

Unlock the entire file.

Returns
  -1 on error; 0 on success.

Definition at line 238 of file PidFileLock.cpp.

{
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
}

References DL, m_fd, ASSA::PIDFLOCK, and trace_with_mask.

Referenced by get_lock_status(), write_pid(), and ~PidFileLock().

## write_pid()

int PidFileLock::write_pid | ( |  | ) |

private

Write our process pid to the lock file.

Cygwin does not have POSIX semantics for locks.

Returns
  -1 on error; 0 on success.

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 131 of file PidFileLock.cpp.

{
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
}

References DL, lock_region(), lock_region_exclusive(), m_fd, ASSA::PIDFLOCK, trace_with_mask, and unlock_region().

Referenced by lock().

## Member Data Documentation

## m_error

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(), open_pid_file(), and PidFileLock().

## m_error_msg

string ASSA::PidFileLock::m_error_msg

private

Error explanation.

Definition at line 129 of file PidFileLock.h.

Referenced by get_error_msg(), and PidFileLock().

## m_fd

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(), PidFileLock(), unlock_region(), write_pid(), and ~PidFileLock().

## m_filename

string ASSA::PidFileLock::m_filename

private

Lock file name.

Definition at line 120 of file PidFileLock.h.

Referenced by dump(), lock(), and ~PidFileLock().

The documentation for this class was generated from the following files:

- PidFileLock.h
- PidFileLock.cpp