Loading...
Searching...
No Matches
PidFileLock.cpp
Go to the documentation of this file.
// -*- c++ -*-
//------------------------------------------------------------------------------
// PidFileLock.cpp
//------------------------------------------------------------------------------
// Copyright (c) 2001,2005 by Vladislav Grinchenko
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//------------------------------------------------------------------------------
//System Includes
#include <errno.h> // errno
#include <string.h> // strerror(3)
#include <unistd.h>
#include <fcntl.h>
#include <sstream>
#include <stdio.h>
//Local Includes
#include "assa/CommonUtils.h"
#include "assa/PidFileLock.h"
using namespace ASSA;
//------------------------------------------------------------------------------
// External Events
//------------------------------------------------------------------------------
PidFileLock::
PidFileLock () :
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 ()
{
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"));
}
}
␌
bool
PidFileLock::
lock (const string& fname_)
{
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::
write_pid ()
{
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
}
␌
//------------------------------------------------------------------------------
// Utility functions
//------------------------------------------------------------------------------
int
PidFileLock::
lock_region ()
{
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 ()
{
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
}
int
PidFileLock::
unlock_region ()
{
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::
get_lock_status ()
{
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
}
␌
pid_t
PidFileLock::
test_region ()
{
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
}
␌
void
PidFileLock::
dump (void)
{
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
}
void
PidFileLock::
log_error (const char* msg_)
{
m_error = errno;
EL((ASSAERR,
"Error: \"Failed to get a lock on PID file - %s\".\n", msg_));
}
␌
pid_t
PidFileLock::
open_pid_file (const std::string& fname_)
{
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;
}
CommonUtils.h
EL
#define EL(X)
A macro for writing error message to the Logger.
Definition Logger.h:285
DL
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
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
PidFileLock.h
A utility class for creating and managing process PID lock file.
ASSA::AutoPtrRef
A wrapper class to provide AutoPtr with reference semantics.
Definition AutoPtr.h:32
ASSA::PidFileLock::get_lock_status
int get_lock_status()
Retrieve lock status.
Definition PidFileLock.cpp:294
ASSA::PidFileLock::~PidFileLock
~PidFileLock()
Destructor.
Definition PidFileLock.cpp:44
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::m_error
int m_error
Last system call error.
Definition PidFileLock.h:126
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::PidFileLock
PidFileLock()
Constructor.
Definition PidFileLock.cpp:32
ASSA::PidFileLock::get_error
int get_error() const
Return last errno value.
Definition PidFileLock.h:134
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::PidFileLock::test_region
pid_t test_region()
Test if file is unlocked.
Definition PidFileLock.cpp:355
ASSA::PidFileLock::m_filename
string m_filename
Lock file name.
Definition PidFileLock.h:120
ASSA::PidFileLock::m_fd
int m_fd
Lock file descriptor.
Definition PidFileLock.h:123
ASSA::PidFileLock::dump
void dump()
Write the state of the lock to debug file.
Definition PidFileLock.cpp:384
ASSA::PidFileLock::lock
bool lock(const string &filename_)
Lock the file.
Definition PidFileLock.cpp:62
ASSA::PidFileLock::lock_region
int lock_region()
Lock the entire file.
Definition PidFileLock.cpp:178
ASSA::PidFileLock::lock_region_exclusive
int lock_region_exclusive()
Lock the entire file (only under Cygwin).
Definition PidFileLock.cpp:212
ASSA::PidFileLock::unlock_region
int unlock_region()
Unlock the entire file.
Definition PidFileLock.cpp:239
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
ASSA
Definition Acceptor.h:40
ASSA::ASSAERR
@ ASSAERR
ASSA and system errors
Definition LogMask.h:34
ASSA::PIDFLOCK
@ PIDFLOCK
Class PidFileLock messages
Definition LogMask.h:35