libassa 3.5.1
Loading...
Searching...
No Matches
Public Member Functions | Private Member Functions | Private Attributes | List of all members
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 charget_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.

32 :
33 m_fd (-1),
34 m_error (0),
35 m_error_msg ("no errors")
36{
37 trace_with_mask ("PidFileLock::PidFileLock", PIDFLOCK);
38
40 l_start = l_len = l_pid = 0;
41}
#define trace_with_mask(s, m)
trace_with_mask() is used to trace function call chain in C++ program.
Definition Logger.h:437
A wrapper class to provide AutoPtr with reference semantics.
Definition AutoPtr.h:32
int m_error
Last system call error.
string m_error_msg
Error explanation.
int m_fd
Lock file descriptor.
@ PIDFLOCK
Class PidFileLock messages
Definition LogMask.h:35

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

45{
46 trace_with_mask ("PidFileLock::~PidFileLock", PIDFLOCK);
47
48 if (m_fd != -1) {
49 if (unlock_region () == 0) { // if we had a lock
50 DL((PIDFLOCK,"PID file unlocked.\n"));
51
52 unlink (m_filename.c_str ());
53 DL((PIDFLOCK,"PID file removed.\n"));
54 }
55 close (m_fd);
56 DL((PIDFLOCK,"PID lock file closed.\n"));
57 }
58}
#define DL(X)
A macro for writing debug message to the Logger.
Definition Logger.h:273
string m_filename
Lock file name.
int unlock_region()
Unlock the entire file.

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.

385{
386 trace_with_mask("PidFileLock::dump", PIDFLOCK);
387
388#if !defined (WIN32)
389
390 DL((PIDFLOCK,"m_filename : \"%s\"\n", m_filename.c_str()));
391 DL((PIDFLOCK,"m_error : %d\n", get_error ()));
392 DL((PIDFLOCK,"m_error_msg: \"%s\"\n", get_error_msg ()));
393 DL((PIDFLOCK,"m_fd : %d\n", m_fd));
394
395 if (m_fd == -1) return;
396
397 test_region ();
398
399 if (this->l_type == F_RDLCK)
400 DL((PIDFLOCK,"l_type : F_RDLCK"));
401
402 if (this->l_type == F_WRLCK)
403 DL((PIDFLOCK,"l_type : F_WRLCK"));
404
405 if (this->l_type == F_UNLCK)
406 DL((PIDFLOCK,"l_type : F_UNLCK"));
407
408 DL((PIDFLOCK,"l_whence : %s\n",
409 this->l_whence == SEEK_SET ? "SEEK_SET" :
410 this->l_whence == SEEK_CUR ? "SEEK_CUR" : "SEEK_END"));
411
412 DL((PIDFLOCK,"l_start : %d\n", this->l_start));
413 DL((PIDFLOCK,"l_len : %d\n", this->l_len ));
414 DL((PIDFLOCK,"l_pid : %ld\n", this->l_pid ));
415
416#endif // !def WIN32
417}
const char * get_error_msg() const
In case of error, return a verbal description of the last error.
int get_error() const
Return last errno value.
pid_t test_region()
Test if file is unlocked.

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.

135{
136 return m_error;
137}

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.

142{
143 return m_error_msg.c_str ();
144}

References m_error_msg.

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

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

295{
296 trace_with_mask ("PidFileLock::get_lock_status", PIDFLOCK);
297 int ret;
298
299#if defined (WIN32)
300 return 0;
301#else
302
303#ifndef __CYGWIN__ // POSIX-compliant locking
304
305 this->l_type = F_WRLCK;
306 this->l_start = 0;
307 this->l_whence = SEEK_SET;
308 this->l_len = 0;
309
310 ret = ::fcntl (m_fd, F_GETLK, static_cast<struct flock*>(this));
311
312 DL((PIDFLOCK,"fcntl(fd=%d, F_GETLK, %s) returned: %d\n",
313 m_fd,
314 (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"),
315 ret));
316 if (ret < 0) {
317 EL ((PIDFLOCK,"fcntl() failed. l_pid = %d\n", this->l_pid));
318 }
319 return (ret);
320
321#else // CYGWIN
322
323 if (lock_region_exclusive () < 0) { // why exclusive?
324 if (unlock_region () < 0) { // already locked
325 char buf[64];
326 pid_t pid; // someone else got it
327 this->l_type = F_RDLCK;
328 if (read (m_fd, buf, 64) > 0) {
329 if (sscanf (buf, "%d", &pid) == 1) {
330 this->l_pid = pid;
331 }
332 }
333 else {
334 this->l_pid = 1; // no real PID information
335 }
336 }
337 }
338 else {
339 unlock_region (); // return the lock into its prestine state
340 }
341 return (0);
342
343#endif // !def CYGWIN
344
345#endif // !def WIN32
346
347}
#define EL(X)
A macro for writing error message to the Logger.
Definition Logger.h:285
int lock_region_exclusive()
Lock the entire file (only under Cygwin).

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.

63{
64 trace_with_mask ("PidFileLock::lock", PIDFLOCK);
65
66#if defined(WIN32)
67 return true;
68#else
69 int val;
70 int len;
71 m_filename = Utils::strenv (fname_.c_str ());
72 val = len = 0;
73
74 DL((PIDFLOCK,"PID lock file: \"%s\"\n", m_filename.c_str ()));
75
76 if (open_pid_file (m_filename) < 0) {
77 goto done;
78 }
79 DL((PIDFLOCK,"PID lock file opened and locked (fd=%d).\n", m_fd));
80
83 if (ftruncate (m_fd, 0) < 0) {
84 log_error("ftruncate() error");
85 goto done;
86 }
87 DL((PIDFLOCK,"PID lock file truncated.\n"));
88
91 if (write_pid () < 0) {
92 log_error("write(PID) error");
93 goto done;
94 }
95
98 if ((val = ::fcntl(m_fd, F_GETFD, 0)) < 0) {
99 log_error("fcntl(F_GETFD) error");
100 goto done;
101 }
102 val |= FD_CLOEXEC;
103
104 if (::fcntl (m_fd, F_SETFD, val) < 0) {
105 log_error("fcntl(F_SETFD) error");
106 goto done;
107 }
108 DL((PIDFLOCK,"CLOSE-ON-EXEC is set on FD.\n"));
109
110 done:
111 if (get_error () != 0) {
112 ::close (m_fd);
113 m_fd = -1;
114 }
115 return m_error == 0 ? true : false;
116
117#endif // !def WIN32
118}
int write_pid()
Write our process pid to the lock file.
pid_t open_pid_file(const std::string &fname_)
Open pid file in a cross-platform way.
void log_error(const char *msg_)
Log an error message to the log file and set internal error to errno.
std::string strenv(const char *in_)
Expand the passed string in_ by substituting environment variable names for their values.

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

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

179{
180 trace_with_mask ("PidFileLock::lock_region", PIDFLOCK);
181 int ret;
182
183#if defined (WIN32)
184 return 0;
185#else
186
187#ifdef __CYGWIN__
188 this->l_type = F_RDLCK; // shared lock
189#else
190 this->l_type = F_WRLCK;
191#endif
192
193 this->l_start = 0;
194 this->l_whence = SEEK_SET;
195 this->l_len = 0;
196
197 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
198
199 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, %s) returned: %d\n",
200 m_fd,
201 (this->l_type == F_RDLCK ? "F_RDLCK" : "F_WRLCK"),
202 ret));
203
204 return (ret);
205
206#endif // !def WIN32
207}

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.

213{
214 trace_with_mask ("PidFileLock::lock_region_exclusive", PIDFLOCK);
215 int ret = 0;
216
217#if defined (WIN32)
218 return 0;
219#else
220
221#ifdef __CYGWIN__
222 this->l_type = F_WRLCK; // exclusive lock - read would fail
223 this->l_start = 0;
224 this->l_whence = SEEK_SET;
225 this->l_len = 0;
226
227 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
228
229 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_WRLCK) returned: %d\n", m_fd, ret));
230#endif
231
232 return (ret);
233
234#endif // !def WIN32
235}

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.

422{
423 m_error = errno;
424 EL((ASSAERR,
425 "Error: \"Failed to get a lock on PID file - %s\".\n", msg_));
426}
@ 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.

436{
437 trace_with_mask("PidFileLock::open_pid_file", PIDFLOCK);
438
439#if !defined (WIN32)
440
441 m_fd = ::open (fname_.c_str (), O_WRONLY|O_CREAT, 0644);
442 if (m_fd < 0) {
443 log_error("open() error.");
444 return -1;
445 }
446
452 if ((owner_pid = test_region ()) > 0) {
453 log_error ("PID file is already locked (by someone).");
454 m_error = EPERM;
455 return -1;
456 }
457
460 if (lock_region () < 0) {
461 if (errno == EACCES || errno == EAGAIN) {
462 log_error("PID file is locked by another process");
463 }
464 else {
465 log_error("write lock error");
466 }
467 return -1;
468 }
469
470#endif // !def WIN32
471
472 return 0;
473}
int lock_region()
Lock the entire file.

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.

356{
357 trace_with_mask ("PidFileLock::test_region", PIDFLOCK);
358 int ret;
359
360#if defined (WIN32)
361 return 0;
362#else
363
364 ret = get_lock_status ();
365
366 if (ret < 0) {
367 DL((PIDFLOCK,"Failed to retrieve lock status.\n"));
368 return 1;
369 }
370 if (this->l_type == F_UNLCK) {
371 DL((PIDFLOCK,"Region is not locked.\n"));
372 return(0);
373 }
374
375 DL((PIDFLOCK,"Region is already locked by PID %d\n", this->l_pid));
376 return (this->l_pid);
377
378#endif // !def WIN32
379}
int get_lock_status()
Retrieve lock status.

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.

240{
241 trace_with_mask ("PidFileLock::unlock_region", PIDFLOCK);
242 int ret;
243
244#if defined (WIN32)
245 return 0;
246#else
247
248 this->l_type = F_UNLCK;
249 this->l_start = 0;
250 this->l_whence = SEEK_SET;
251 this->l_len = 0;
252
253 ret = ::fcntl (m_fd, F_SETLK, static_cast<struct flock*>(this));
254
255 DL((PIDFLOCK,"fcntl(fd=%d, F_SETLK, F_UNLCK) returned: %d\n",
256 m_fd, ret));
257
258 return (ret);
259
260#endif // !def WIN32
261}

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.

133{
134 trace_with_mask ("PidFileLock::write_pid", PIDFLOCK);
135
136#if defined (WIN32)
137 return 0;
138#else
139 std::ostringstream mypid;
140 size_t len;
141
142 this->l_pid = getpid ();
143 mypid << this->l_pid << std::ends;
144 len = strlen (mypid.str ().c_str ());
145
146#ifdef __CYGWIN__
147
148 unlock_region (); // remove shared (weak) lock
150
151 if (write (m_fd, mypid.str ().c_str (), len) != len) {
152 return -1;
153 }
154 DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", l_pid));
155 unlock_region (); // give up the exclusive lock
156 lock_region (); // place shared (weak) lock
157
158#else // POSIX-compliant locks
159
160 if (write (m_fd, mypid.str ().c_str (), len) != len) {
161 return -1;
162 }
163 DL((PIDFLOCK,"Wrote PID=%d to the lock file.\n", this->l_pid));
164
165#endif
166 return 0;
167
168#endif // !def WIN32
169}

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

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

◆ m_fd

int ASSA::PidFileLock::m_fd
private

◆ 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: