There are two problems here. One (the big problem), I made the mistake
of changing from flock() to lockf() which is badly designed and next to
useless. Two, there is a small window where two clients could race and
both create a server.

So please try this which changes back to flock, fixes the race and adds
some logging.

Index: client.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/client.c,v
retrieving revision 1.80
diff -u -p -r1.80 client.c
--- client.c    29 Apr 2014 22:31:22 -0000      1.80
+++ client.c    24 Jun 2014 22:26:21 -0000
@@ -77,13 +77,18 @@ client_get_lock(char *lockfile)
 
        if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1)
                fatal("open failed");
+       log_debug("lock file is %s", lockfile);
 
-       if (lockf(lockfd, F_TLOCK, 0) == -1 && errno == EAGAIN) {
-               while (lockf(lockfd, F_LOCK, 0) == -1 && errno == EINTR)
+       if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
+               log_debug("flock failed: %s", strerror(errno));
+               if (errno != EAGAIN)
+                       return (lockfd);
+               while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
                        /* nothing */;
                close(lockfd);
                return (-1);
        }
+       log_debug("flock succeeded");
 
        return (lockfd);
 }
@@ -94,8 +99,8 @@ client_connect(char *path, int start_ser
 {
        struct sockaddr_un      sa;
        size_t                  size;
-       int                     fd, lockfd;
-       char                   *lockfile;
+       int                     fd, lockfd = -1, locked = 0;
+       char                   *lockfile = NULL;
 
        memset(&sa, 0, sizeof sa);
        sa.sun_family = AF_UNIX;
@@ -104,29 +109,48 @@ client_connect(char *path, int start_ser
                errno = ENAMETOOLONG;
                return (-1);
        }
+       log_debug("socket is %s", path);
 
 retry:
        if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
                fatal("socket failed");
 
+       log_debug("trying connect");
        if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
+               log_debug("connect failed: %s", strerror(errno));
                if (errno != ECONNREFUSED && errno != ENOENT)
                        goto failed;
                if (!start_server)
                        goto failed;
                close(fd);
 
-               xasprintf(&lockfile, "%s.lock", path);
-               if ((lockfd = client_get_lock(lockfile)) == -1) {
-                       free(lockfile);
+               if (!locked) {
+                       xasprintf(&lockfile, "%s.lock", path);
+                       if ((lockfd = client_get_lock(lockfile)) == -1) {
+                               log_debug("didn't get lock");
+                               free(lockfile);
+                               goto retry;
+                       }
+                       log_debug("got lock");
+
+                       /*
+                        * Always retry at least once, even if we got the lock,
+                        * because another client could have taken the lock,
+                        * started the server and released the lock between our
+                        * connect() and flock().
+                        */
+                       locked = 1;
                        goto retry;
                }
+
                if (unlink(path) != 0 && errno != ENOENT) {
                        free(lockfile);
                        close(lockfd);
                        return (-1);
                }
                fd = server_start(lockfd, lockfile);
+       }
+       if (locked) {
                free(lockfile);
                close(lockfd);
        }
@@ -233,17 +257,17 @@ client_main(int argc, char **argv, int f
                return (1);
        }
 
-       /* Initialise the client socket and start the server. */
+       /* Set process title, log and signals now this is the client. */
+       setproctitle("client (%s)", socket_path);
+       logfile("client");
+
+       /* Initialize the client socket and start the server. */
        fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
        if (fd == -1) {
                fprintf(stderr, "failed to connect to server: %s\n",
                    strerror(errno));
                return (1);
        }
-
-       /* Set process title, log and signals now this is the client. */
-       setproctitle("client (%s)", socket_path);
-       logfile("client");
 
        /* Create imsg. */
        imsg_init(&client_ibuf, fd);
Index: server.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/server.c,v
retrieving revision 1.114
diff -u -p -r1.114 server.c
--- server.c    14 May 2014 06:21:19 -0000      1.114
+++ server.c    24 Jun 2014 21:32:29 -0000
@@ -111,6 +111,7 @@ server_start(int lockfd, char *lockfile)
        /* The first client is special and gets a socketpair; create it. */
        if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
                fatal("socketpair failed");
+       log_debug("starting server");
 
        switch (fork()) {
        case -1:




On Tue, Jun 24, 2014 at 12:29:12AM +0200, Emanuel Berg wrote:
> Nicholas Marriott <nicholas.marri...@gmail.com> writes:
> 
> > Also please run all the tmux with -vvvv without the
> > sleeps and see what is in the tmux-client-* logs that
> > should end up in your home directories.
> 
> I run it twice as first time it worked without the
> sleeps. Then it didn't. Here are the logs for both
> cases:
> 
> http://user.it.uu.se/~embe8573/tmux-logs/
> 
> -- 
> underground experts united:
> http://user.it.uu.se/~embe8573
> 
> ------------------------------------------------------------------------------
> Open source business process management suite built on Java and Eclipse
> Turn processes into business applications with Bonita BPM Community Edition
> Quickly connect people, data, and systems into organized workflows
> Winner of BOSSIE, CODIE, OW2 and Gartner awards
> http://p.sf.net/sfu/Bonitasoft
> _______________________________________________
> tmux-users mailing list
> tmux-users@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/tmux-users

------------------------------------------------------------------------------
Open source business process management suite built on Java and Eclipse
Turn processes into business applications with Bonita BPM Community Edition
Quickly connect people, data, and systems into organized workflows
Winner of BOSSIE, CODIE, OW2 and Gartner awards
http://p.sf.net/sfu/Bonitasoft
_______________________________________________
tmux-users mailing list
tmux-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tmux-users

Reply via email to