From: <enl...@li...> - 2006-02-05 09:27:13
|
Enlightenment CVS committal Author : kwo Project : e16 Module : epplets Dir : e16/epplets/api Modified Files: epplet.c Log Message: Fix epplet instance counting in cases where a leftover lock file exists which contains the pid of a running process that is not the epplet that created it. For the fix to work it is required that the lock file can be locked using fcntl. If it cannot be locked (e.g. home dir on NFS mount) the code falls back to the old behavior. =================================================================== RCS file: /cvsroot/enlightenment/e16/epplets/api/epplet.c,v retrieving revision 1.131 retrieving revision 1.132 diff -u -3 -r1.131 -r1.132 --- epplet.c 11 Feb 2005 04:29:17 -0000 1.131 +++ epplet.c 5 Feb 2006 09:27:03 -0000 1.132 @@ -1,6 +1,7 @@ #include "config.h" #include "epplet.h" #include <errno.h> +#include <fcntl.h> #include <sys/utsname.h> #include <signal.h> #include <sys/wait.h> @@ -5495,8 +5496,9 @@ Epplet_find_instance(char *name) { struct stat st; + struct flock fl; char s[1024], *tmpdir; - int i = 0, fd; + int i, fd, err, exists, locked; pid_t pid; /* Find E dir */ @@ -5552,51 +5554,76 @@ /* Pick our instance number. 255 is the max to avoid infinite loops, which could be caused by * lack of insert permissions in the config directory. */ + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = fl.l_len = 0; + locked = 0; + for (i = 1; i < 256; i++) { Esnprintf(s, sizeof(s), "%s/.lock_%i", conf_dir, i); - if (stat(s, &st) >= 0) + + exists = stat(s, &st) == 0; + + if (exists) + fd = open(s, (O_RDWR | O_CREAT), 0600); + else + fd = open(s, (O_WRONLY | O_EXCL | O_CREAT), 0600); + if (fd < 0) + continue; + for (;;) { - /* Lock file exists. Read from it. */ - if ((fd = open(s, O_RDONLY)) < 0) - { - /* Either it's there and we can't read it, or it's gone now. Next! */ - fprintf(stderr, "Unable to read lock file %s -- %s\n", s, - strerror(errno)); - continue; - } - if ((read(fd, &pid, sizeof(pid_t))) < ((int)sizeof(pid_t))) - { - /* We didn't get enough bytes. Next! */ - fprintf(stderr, + err = fcntl(fd, F_SETLK, &fl); + if (err != EINTR) + break; + } + if (err == 0) + { + /* Locking succeeded, file is open for writing */ + locked = 1; + break; + } + + if (!exists) + { + /* Locking failed, but file was successfully created with O_EXCL */ + break; + } + + /* Check pid */ + if ((read(fd, &pid, sizeof(pid_t))) < ((int)sizeof(pid_t))) + { + /* We didn't get enough bytes. Next! */ + fprintf(stderr, "Read attempt for lock file %s failed -- %s\n", s, strerror(errno)); - continue; - } close(fd); - if (pid <= 0) - { - /* We got a bogus process ID. Next! */ - fprintf(stderr, - "Lock file %s contained a bogus process ID (%lu)\n", - s, (unsigned long)pid); - continue; - } - if ((kill(pid, 0) == 0) || (errno != ESRCH)) - { - /* The process exists. Next! */ - continue; - } - /* Okay, looks like a stale lockfile at this point. Remove it. */ - if ((unlink(s)) != 0) - { - /* Removal failed. Next! */ - fprintf(stderr, - "Unable to remove stale lock file %s -- %s. Please remove it manually.\n", - s, strerror(errno)); - continue; - } + continue; + } + close(fd); + if (pid <= 0) + { + /* We got a bogus process ID. Next! */ + fprintf(stderr, + "Lock file %s contained a bogus process ID (%lu)\n", + s, (unsigned long)pid); + continue; + } + if ((kill(pid, 0) == 0) || (errno != ESRCH)) + { + /* The process exists. Next! */ + continue; + } + /* Okay, looks like a stale lockfile at this point. Remove it. */ + if ((unlink(s)) != 0) + { + /* Removal failed. Next! */ + fprintf(stderr, + "Unable to remove stale lock file %s -- %s. Please remove it manually.\n", + s, strerror(errno)); + continue; } + srand(getpid()); usleep((rand() & 0xfffff)); if ((fd = open(s, (O_WRONLY | O_EXCL | O_CREAT), 0600)) < 0) @@ -5604,16 +5631,20 @@ /* Apparently another process just came in under us and created it. Next! */ continue; } - pid = getpid(); - write(fd, &pid, sizeof(pid_t)); /* Not sure how best to deal with write errors here */ - close(fd); - /* If we made it here, we've just written the lock file and saved it. We have our instance + /* If we made it here, we've just created the lock file. We have our instance * number, so exit the loop. */ break; } - /* Anything this high is probably an error. */ - if (i >= 255) + if (i < 256) + { + pid = getpid(); + write(fd, &pid, sizeof(pid_t)); /* Not sure how best to deal with write errors here */ + /* If locked do not close fd, otherwise lock is lost */ + if (!locked) + close(fd); + } + else { i = 1; } |