summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libutil/pidfile.34
-rw-r--r--lib/libutil/pidfile.c16
2 files changed, 19 insertions, 1 deletions
diff --git a/lib/libutil/pidfile.3 b/lib/libutil/pidfile.3
index 64f77b0..3eaa7cf 100644
--- a/lib/libutil/pidfile.3
+++ b/lib/libutil/pidfile.3
@@ -168,6 +168,10 @@ 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
diff --git a/lib/libutil/pidfile.c b/lib/libutil/pidfile.c
index 983d103..ecf0fac 100644
--- a/lib/libutil/pidfile.c
+++ b/lib/libutil/pidfile.c
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
+#include <time.h>
#include <err.h>
#include <errno.h>
#include <libutil.h>
@@ -74,6 +75,8 @@ pidfile_read(const char *path, pid_t *pidptr)
close(fd);
if (i == -1)
return (error);
+ else if (i == 0)
+ return (EAGAIN);
buf[i] = '\0';
*pidptr = strtol(buf, &endptr, 10);
@@ -88,7 +91,8 @@ pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
{
struct pidfh *pfh;
struct stat sb;
- int error, fd, len;
+ int error, fd, len, count;
+ struct timespec rqtp;
pfh = malloc(sizeof(*pfh));
if (pfh == NULL)
@@ -115,10 +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;
+ }
+ }
}
free(pfh);
return (NULL);
OpenPOWER on IntegriCloud