mirror of
https://github.com/tmux/tmux.git
synced 2025-01-12 11:18:48 +00:00
Use a lock file and flock() to serialize server start, avoids problems
when running a bunch of tmux from cron at the same time. Based on a diff from Tim Ruehsen.
This commit is contained in:
parent
18012f5b18
commit
ac9ebc29a2
53
client.c
53
client.c
@ -39,6 +39,7 @@ int client_exitval;
|
|||||||
enum msgtype client_exittype;
|
enum msgtype client_exittype;
|
||||||
int client_attached;
|
int client_attached;
|
||||||
|
|
||||||
|
int client_get_lock(char *);
|
||||||
int client_connect(char *, int);
|
int client_connect(char *, int);
|
||||||
void client_send_identify(int);
|
void client_send_identify(int);
|
||||||
void client_send_environ(void);
|
void client_send_environ(void);
|
||||||
@ -49,13 +50,38 @@ void client_callback(int, short, void *);
|
|||||||
int client_dispatch_attached(void);
|
int client_dispatch_attached(void);
|
||||||
int client_dispatch_wait(void *);
|
int client_dispatch_wait(void *);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get server create lock. If already held then server start is happening in
|
||||||
|
* another client, so block until the lock is released and return -1 to
|
||||||
|
* retry. Ignore other errors - just continue and start the server without the
|
||||||
|
* lock.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
client_get_lock(char *lockfile)
|
||||||
|
{
|
||||||
|
int lockfd;
|
||||||
|
|
||||||
|
if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1)
|
||||||
|
fatal("open failed");
|
||||||
|
|
||||||
|
if (flock(lockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) {
|
||||||
|
while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
|
||||||
|
/* nothing */;
|
||||||
|
close(lockfd);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (lockfd);
|
||||||
|
}
|
||||||
|
|
||||||
/* Connect client to server. */
|
/* Connect client to server. */
|
||||||
int
|
int
|
||||||
client_connect(char *path, int start_server)
|
client_connect(char *path, int start_server)
|
||||||
{
|
{
|
||||||
struct sockaddr_un sa;
|
struct sockaddr_un sa;
|
||||||
size_t size;
|
size_t size;
|
||||||
int fd;
|
int fd, lockfd;
|
||||||
|
char *lockfile;
|
||||||
|
|
||||||
memset(&sa, 0, sizeof sa);
|
memset(&sa, 0, sizeof sa);
|
||||||
sa.sun_family = AF_UNIX;
|
sa.sun_family = AF_UNIX;
|
||||||
@ -65,24 +91,25 @@ client_connect(char *path, int start_server)
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retry:
|
||||||
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||||
fatal("socket failed");
|
fatal("socket failed");
|
||||||
|
|
||||||
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
|
if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
|
||||||
|
if (errno != ECONNREFUSED && errno != ENOENT)
|
||||||
|
goto failed;
|
||||||
if (!start_server)
|
if (!start_server)
|
||||||
goto failed;
|
goto failed;
|
||||||
switch (errno) {
|
close(fd);
|
||||||
case ECONNREFUSED:
|
|
||||||
if (unlink(path) != 0)
|
xasprintf(&lockfile, "%s.lock", path);
|
||||||
goto failed;
|
if ((lockfd = client_get_lock(lockfile)) == -1)
|
||||||
/* FALLTHROUGH */
|
goto retry;
|
||||||
case ENOENT:
|
if (unlink(path) != 0 && errno != ENOENT)
|
||||||
if ((fd = server_start()) == -1)
|
return (-1);
|
||||||
goto failed;
|
fd = server_start(lockfd, lockfile);
|
||||||
break;
|
xfree(lockfile);
|
||||||
default:
|
close(lockfd);
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setblocking(fd, 0);
|
setblocking(fd, 0);
|
||||||
|
6
server.c
6
server.c
@ -104,7 +104,7 @@ server_create_socket(void)
|
|||||||
|
|
||||||
/* Fork new server. */
|
/* Fork new server. */
|
||||||
int
|
int
|
||||||
server_start(void)
|
server_start(int lockfd, char *lockfile)
|
||||||
{
|
{
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
int pair[2];
|
int pair[2];
|
||||||
@ -161,6 +161,10 @@ server_start(void)
|
|||||||
server_fd = server_create_socket();
|
server_fd = server_create_socket();
|
||||||
server_client_create(pair[1]);
|
server_client_create(pair[1]);
|
||||||
|
|
||||||
|
unlink(lockfile);
|
||||||
|
xfree(lockfile);
|
||||||
|
close(lockfd);
|
||||||
|
|
||||||
if (access(SYSTEM_CFG, R_OK) == 0)
|
if (access(SYSTEM_CFG, R_OK) == 0)
|
||||||
load_cfg(SYSTEM_CFG, NULL, &cfg_causes);
|
load_cfg(SYSTEM_CFG, NULL, &cfg_causes);
|
||||||
else if (errno != ENOENT) {
|
else if (errno != ENOENT) {
|
||||||
|
2
tmux.h
2
tmux.h
@ -1687,7 +1687,7 @@ const char *key_string_lookup_key(int);
|
|||||||
extern struct clients clients;
|
extern struct clients clients;
|
||||||
extern struct clients dead_clients;
|
extern struct clients dead_clients;
|
||||||
extern struct paste_stack global_buffers;
|
extern struct paste_stack global_buffers;
|
||||||
int server_start(void);
|
int server_start(int, char *);
|
||||||
void server_update_socket(void);
|
void server_update_socket(void);
|
||||||
|
|
||||||
/* server-client.c */
|
/* server-client.c */
|
||||||
|
Loading…
Reference in New Issue
Block a user