In pidfile_open(), if the pidfile is locked, but empty (PID is not stored yet)

and the caller requested other process' PID by passing non-NULL pidptr
argument, we will wait at most 100ms for the PID to show up in the file and if
it won't, we will store -1 in *pidptr.

From now on, pidfile_open() function never sets errno to EAGAIN on failure.

In collaboration with:	des
MFC after:		1 week
This commit is contained in:
Pawel Jakub Dawidek 2011-10-16 21:30:15 +00:00
parent b6faf3cfdb
commit e8cc80c0a0
2 changed files with 27 additions and 22 deletions

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd October 20, 2008
.Dd October 16, 2011
.Dt PIDFILE 3
.Os
.Sh NAME
@ -59,11 +59,14 @@ The
function opens (or creates) a file specified by the
.Fa path
argument and locks it.
If a file can not be locked, a PID of an already running daemon is returned in
the
If
.Fa pidptr
argument (if it is not
.Dv NULL ) .
argument is not
.Dv NULL
and file can not be locked, the function will use it to store a PID of an
already running daemon or
.Li -1
in case daemon did not write its PID yet.
The function does not write process' PID into the file here, so it can be
used before
.Fn fork Ns ing
@ -162,16 +165,18 @@ function will fail if:
.It Bq Er EEXIST
Some process already holds the lock on the given pidfile, meaning that a
daemon is already running.
If
.Fa pidptr
argument is not
.Dv NULL
the function will use it to store a PID of an already running daemon or
.Li -1
in case daemon did not write its PID yet.
.It Bq Er ENAMETOOLONG
Specified pidfile's name is too long.
.It Bq Er EINVAL
Some process already holds the lock on the given pidfile, but PID read
from there is invalid.
.It Bq Er EAGAIN
Some process already holds the lock on the given pidfile, but the file
is truncated.
Most likely, the existing daemon is writing new PID into
the file.
.El
.Pp
The

View File

@ -119,20 +119,20 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
fd = flopen(pfh->pf_path,
O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode);
if (fd == -1) {
count = 0;
rqtp.tv_sec = 0;
rqtp.tv_nsec = 5000000;
if (errno == EWOULDBLOCK && pidptr != NULL) {
again:
errno = pidfile_read(pfh->pf_path, pidptr);
if (errno == 0)
errno = EEXIST;
else if (errno == EAGAIN) {
if (++count <= 3) {
nanosleep(&rqtp, 0);
goto again;
}
count = 20;
rqtp.tv_sec = 0;
rqtp.tv_nsec = 5000000;
for (;;) {
errno = pidfile_read(pfh->pf_path, pidptr);
if (errno != EAGAIN || --count == 0)
break;
nanosleep(&rqtp, 0);
}
if (errno == EAGAIN)
*pidptr = -1;
if (errno == 0 || errno == EAGAIN)
errno = EEXIST;
}
free(pfh);
return (NULL);