ASSA::PidFileLock Class Reference

#include <PidFileLock.h>

List of all members.

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 33 of file PidFileLock.h.


Constructor & Destructor Documentation

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 }


Member Function Documentation

void PidFileLock::dump  ) 
 

Write the state of the lock to debug file.

m_fd = -1 indicates that lock file is not opened.

Definition at line 343 of file PidFileLock.cpp.

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

Referenced by test_region().

00344 {
00345     trace_with_mask("PidFileLock::dump", PIDFLOCK);
00346 
00347     DL((PIDFLOCK,"m_filename : \"%s\"\n", m_filename.c_str()));
00348     DL((PIDFLOCK,"m_error    : %d\n",     get_error ()));
00349     DL((PIDFLOCK,"m_error_msg: \"%s\"\n", get_error_msg ()));
00350     DL((PIDFLOCK,"m_fd       : %d\n",     m_fd));
00351 
00352     if (m_fd == -1) return;
00353 
00354     test_region ();
00355 
00356     if (this->l_type == F_RDLCK)
00357         DL((PIDFLOCK,"l_type    : F_RDLCK"));
00358 
00359     if (this->l_type == F_WRLCK)
00360         DL((PIDFLOCK,"l_type    : F_WRLCK"));
00361 
00362     if (this->l_type == F_UNLCK)
00363         DL((PIDFLOCK,"l_type    : F_UNLCK"));
00364 
00365     DL((PIDFLOCK,"l_whence  : %s\n",
00366         this->l_whence == SEEK_SET ? "SEEK_SET" :
00367         this->l_whence == SEEK_CUR ? "SEEK_CUR" : "SEEK_END"));
00368 
00369     DL((PIDFLOCK,"l_start   : %d\n",   this->l_start));
00370     DL((PIDFLOCK,"l_len     : %d\n",   this->l_len  ));
00371     DL((PIDFLOCK,"l_pid     : %ld\n",  this->l_pid  ));
00372 }

int ASSA::PidFileLock::get_error  )  const [inline]
 

Return last errno value.

Returns:
0 for success, errno on error

Definition at line 124 of file PidFileLock.h.

References m_error.

Referenced by dump(), and lock().

00125 { 
00126     return m_error; 
00127 }

const char * ASSA::PidFileLock::get_error_msg  )  const [inline]
 

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

Definition at line 131 of file PidFileLock.h.

References m_error_msg.

Referenced by dump(), and ASSA::GenServer::init_internals().

00132 { 
00133     return m_error_msg.c_str (); 
00134 }

int PidFileLock::get_lock_status  )  [private]
 

Retrieve lock status.

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

Definition at line 266 of file PidFileLock.cpp.

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

Referenced by test_region().

00267 {
00268     trace_with_mask ("PidFileLock::get_lock_status", PIDFLOCK);
00269     int ret;
00270 
00271 #ifndef __CYGWIN__              // POSIX-compliant locking
00272 
00273     this->l_type   = F_WRLCK;
00274     this->l_start  = 0;
00275     this->l_whence = SEEK_SET;
00276     this->l_len    = 0;
00277 
00278     ret = ::fcntl (m_fd, F_GETLK, static_cast<struct flock*>(this));
00279 
00280     DL((PIDFLOCK,"fcntl(fd=%d, F_GETLK, %s) returned: %d\n", 
00281         m_fd, 
00282         (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"),
00283         ret));
00284     if (ret < 0) {
00285         EL ((PIDFLOCK,"fcntl() failed. l_pid = %d\n", this->l_pid));
00286     }
00287     return (ret);
00288 
00289 #else  // CYGWIN
00290 
00291     if (lock_region_exclusive () < 0) {             // why exclusive?
00292         if (unlock_region () < 0) {                 // already locked 
00293             char buf[64];
00294             pid_t pid;                              // someone else got it
00295             this->l_type = F_RDLCK;
00296             if (read (m_fd, buf, 64) > 0) {
00297                 if (sscanf (buf, "%d", &pid) == 1) {
00298                     this->l_pid = pid;
00299                 }
00300             }
00301             else {
00302                 this->l_pid = 1;                    // no real PID information
00303             }
00304         }
00305     }
00306     else {
00307         unlock_region ();           // return the lock into its prestine state
00308     }
00309     return (0);
00310     
00311 #endif 
00312 }

bool PidFileLock::lock const string &  filename_  ) 
 

Lock the file.

Returns:
true on success, false on error

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     int val;
00067     int len;
00068     m_filename = Utils::strenv (fname_.c_str ());
00069     val = len = 0;
00070 
00071     DL((PIDFLOCK,"PID lock file: \"%s\"\n", m_filename.c_str ()));
00072     
00073     if (open_pid_file (m_filename) < 0) {
00074         goto done;
00075     }
00076     DL((PIDFLOCK,"PID lock file opened and locked (fd=%d).\n", m_fd));
00077 
00080     if (ftruncate (m_fd, 0) < 0) {
00081         log_error("ftruncate() error");
00082         goto done;
00083     }
00084     DL((PIDFLOCK,"PID lock file truncated.\n"));
00085 
00088     if (write_pid () < 0) {
00089         log_error("write(PID) error");
00090         goto done;
00091     }
00092 
00095     if ((val = ::fcntl(m_fd, F_GETFD, 0)) < 0) {
00096         log_error("fcntl(F_GETFD) error");
00097         goto done;
00098     }
00099     val |= FD_CLOEXEC;
00100     
00101     if (::fcntl (m_fd, F_SETFD, val) < 0) {
00102         log_error("fcntl(F_SETFD) error");
00103         goto done;
00104     }
00105     DL((PIDFLOCK,"CLOSE-ON-EXEC is set on FD.\n"));
00106 
00107  done:
00108     if (get_error () != 0) {
00109         ::close (m_fd);
00110         m_fd = -1;
00111     }
00112     return m_error == 0 ? true : false;
00113 }

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

References DL, ASSA::PIDFLOCK, and trace_with_mask.

Referenced by write_pid().

00169 {
00170     trace_with_mask ("PidFileLock::lock_region", PIDFLOCK);
00171     int ret;
00172 
00173 #ifdef __CYGWIN__
00174     this->l_type   = F_RDLCK;   // shared lock
00175 #else
00176     this->l_type   = F_WRLCK;
00177 #endif
00178 
00179     this->l_start  = 0;
00180     this->l_whence = SEEK_SET;
00181     this->l_len    = 0;
00182 
00183     ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
00184 
00185     DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, %s) returned: %d\n", 
00186         m_fd, 
00187         (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"),
00188         ret));
00189 
00190     return (ret);
00191 }

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

References DL, ASSA::PIDFLOCK, and trace_with_mask.

Referenced by get_lock_status(), and write_pid().

00197 {
00198     trace_with_mask ("PidFileLock::lock_region_exclusive", PIDFLOCK);
00199     int ret = 0;
00200 
00201 #ifdef __CYGWIN__
00202     this->l_type   = F_WRLCK;   // exclusive lock - read would fail
00203     this->l_start  = 0;
00204     this->l_whence = SEEK_SET;
00205     this->l_len    = 0;
00206 
00207     ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
00208 
00209     DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_WRLCK) returned: %d\n", m_fd, ret));
00210 #endif
00211 
00212     return (ret);
00213 }

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

References EL, ASSA::ERROR, and m_error.

Referenced by lock(), and open_pid_file().

00377 {
00378     m_error = errno;
00379     EL((ERROR, "Error: \"Failed to get a lock on PID file - %s\".\n", msg_));
00380 }

pid_t PidFileLock::open_pid_file const std::string &  fname_  )  [private]
 

Open pid file in a cross-platform way.

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

References log_error(), ASSA::PIDFLOCK, and trace_with_mask.

Referenced by lock().

00390 {
00391     trace_with_mask("PidFileLock::open_pid_file", PIDFLOCK);
00392 
00393     m_fd = ::open (fname_.c_str (), O_WRONLY|O_CREAT, 0644);
00394     if (m_fd < 0) {
00395         log_error("open() error.");
00396         return -1;
00397     }
00398 
00403     pid_t owner_pid;
00404     if ((owner_pid = test_region ()) > 0) {
00405         log_error ("PID file is already locked (by someone).");
00406         m_error = EPERM;
00407         return -1;
00408     }
00409 
00412     if (lock_region () < 0) {
00413         if (errno == EACCES || errno == EAGAIN) {
00414             log_error("PID file is locked by another process");
00415         }
00416         else {
00417             log_error("write lock error");
00418         }
00419         return -1;
00420     }
00421 
00422     return 0;
00423 }

pid_t PidFileLock::test_region  )  [private]
 

Test if file is unlocked.

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

Definition at line 320 of file PidFileLock.cpp.

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

Referenced by dump().

00321 {
00322     trace_with_mask ("PidFileLock::test_region", PIDFLOCK);
00323     int ret;
00324 
00325     ret = get_lock_status ();
00326 
00327     if (ret < 0) {
00328         DL((PIDFLOCK,"Failed to retrieve lock status.\n"));
00329         return 1;
00330     }
00331     if (this->l_type == F_UNLCK) {
00332         DL((PIDFLOCK,"Region is not locked.\n"));
00333         return(0);  
00334     }
00335 
00336     DL((PIDFLOCK,"Region is already locked by PID %d\n", this->l_pid));
00337     return (this->l_pid);
00338 }

int PidFileLock::unlock_region  )  [private]
 

Unlock the entire file.

Returns:
-1 on error; 0 on success.

Definition at line 217 of file PidFileLock.cpp.

References DL, ASSA::PIDFLOCK, and trace_with_mask.

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

00218 {
00219     trace_with_mask ("PidFileLock::unlock_region", PIDFLOCK);
00220     int ret;
00221 
00222     this->l_type   = F_UNLCK;
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_UNLCK) returned: %d\n", 
00230         m_fd, ret));
00231 
00232     return (ret);
00233 }

int PidFileLock::write_pid  )  [private]
 

Write our process pid to the lock file.

Returns:
-1 on error; 0 on success.

Definition at line 127 of file PidFileLock.cpp.

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

Referenced by lock().

00128 {
00129     trace_with_mask ("PidFileLock::write_pid", PIDFLOCK);
00130 
00131     std::ostringstream mypid;
00132     size_t len;
00133 
00134     this->l_pid = getpid ();
00135     mypid << this->l_pid << std::ends;
00136     len = strlen (mypid.str ().c_str ());
00137     
00138 #ifdef __CYGWIN__
00139 
00140     unlock_region ();           // remove shared (weak) lock
00141     lock_region_exclusive ();   
00142 
00143     if (write (m_fd, mypid.str ().c_str (), len) != len) {
00144         return -1;
00145     }
00146     DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", l_pid));
00147     unlock_region ();           // give up the exclusive lock
00148     lock_region ();             // place shared (weak) lock 
00149 
00150 #else  // POSIX-compliant locks
00151 
00152     if (write (m_fd, mypid.str ().c_str (), len) != len) {
00153         return -1;
00154     }
00155     DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", this->l_pid));
00156 
00157 #endif
00158     return 0;
00159 }


Member Data Documentation

int ASSA::PidFileLock::m_error [private]
 

Last system call error.

Definition at line 116 of file PidFileLock.h.

Referenced by get_error(), lock(), and log_error().

string ASSA::PidFileLock::m_error_msg [private]
 

Error explanation.

Definition at line 119 of file PidFileLock.h.

Referenced by get_error_msg().

int ASSA::PidFileLock::m_fd [private]
 

Lock file descriptor.

Definition at line 113 of file PidFileLock.h.

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

string ASSA::PidFileLock::m_filename [private]
 

Lock file name.

Definition at line 110 of file PidFileLock.h.

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


The documentation for this class was generated from the following files:
Generated on Mon Dec 19 15:59:02 2005 for libassa by  doxygen 1.4.5