version 1.143, 2015/10/23 16:07:29 |
version 1.144, 2015/10/27 13:23:24 |
|
|
|
|
struct clients clients; |
struct clients clients; |
|
|
|
struct tmuxproc *server_proc; |
int server_fd; |
int server_fd; |
int server_exit; |
int server_exit; |
struct event server_ev_accept; |
struct event server_ev_accept; |
|
|
struct layout_cell *marked_layout_cell; |
struct layout_cell *marked_layout_cell; |
|
|
int server_create_socket(void); |
int server_create_socket(void); |
void server_loop(void); |
int server_loop(void); |
int server_should_exit(void); |
int server_should_exit(void); |
void server_send_exit(void); |
void server_send_exit(void); |
void server_accept_callback(int, short, void *); |
void server_accept(int, short, void *); |
void server_signal_callback(int, short, void *); |
void server_signal(int); |
void server_child_signal(void); |
void server_child_signal(void); |
void server_child_exited(pid_t, int); |
void server_child_exited(pid_t, int); |
void server_child_stopped(pid_t, int); |
void server_child_stopped(pid_t, int); |
|
|
{ |
{ |
int pair[2]; |
int pair[2]; |
|
|
/* The first client is special and gets a socketpair; create it. */ |
|
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) |
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) |
fatal("socketpair failed"); |
fatal("socketpair failed"); |
log_debug("starting server"); |
|
|
|
switch (fork()) { |
server_proc = proc_start("server", base, 1, server_signal); |
case -1: |
if (server_proc == NULL) { |
fatal("fork failed"); |
|
case 0: |
|
break; |
|
default: |
|
close(pair[1]); |
close(pair[1]); |
return (pair[0]); |
return (pair[0]); |
} |
} |
|
|
"ps", NULL) != 0) |
"ps", NULL) != 0) |
fatal("pledge failed"); |
fatal("pledge failed"); |
|
|
/* |
|
* Must daemonise before loading configuration as the PID changes so |
|
* $TMUX would be wrong for sessions created in the config file. |
|
*/ |
|
if (daemon(1, 0) != 0) |
|
fatal("daemon failed"); |
|
|
|
/* event_init() was called in our parent, need to reinit. */ |
|
clear_signals(0); |
|
if (event_reinit(base) != 0) |
|
fatal("event_reinit failed"); |
|
|
|
logfile("server"); |
|
log_debug("server started, pid %ld", (long) getpid()); |
|
|
|
RB_INIT(&windows); |
RB_INIT(&windows); |
RB_INIT(&all_window_panes); |
RB_INIT(&all_window_panes); |
TAILQ_INIT(&clients); |
TAILQ_INIT(&clients); |
|
|
utf8_build(); |
utf8_build(); |
|
|
start_time = time(NULL); |
start_time = time(NULL); |
log_debug("socket path %s", socket_path); |
|
setproctitle("server (%s)", socket_path); |
|
|
|
server_fd = server_create_socket(); |
server_fd = server_create_socket(); |
if (server_fd == -1) |
if (server_fd == -1) |
|
|
|
|
server_add_accept(0); |
server_add_accept(0); |
|
|
set_signals(server_signal_callback); |
proc_loop(server_proc, server_loop); |
server_loop(); |
|
status_prompt_save_history(); |
status_prompt_save_history(); |
exit(0); |
exit(0); |
} |
} |
|
|
/* Main server loop. */ |
/* Server loop callback. */ |
void |
int |
server_loop(void) |
server_loop(void) |
{ |
{ |
while (!server_should_exit()) { |
|
log_debug("event dispatch enter"); |
|
event_loop(EVLOOP_ONCE); |
|
log_debug("event dispatch exit"); |
|
|
|
server_client_loop(); |
|
} |
|
} |
|
|
|
/* Check if the server should exit (no more clients or sessions). */ |
|
int |
|
server_should_exit(void) |
|
{ |
|
struct client *c; |
struct client *c; |
|
|
|
server_client_loop(); |
|
|
if (!options_get_number(&global_options, "exit-unattached")) { |
if (!options_get_number(&global_options, "exit-unattached")) { |
if (!RB_EMPTY(&sessions)) |
if (!RB_EMPTY(&sessions)) |
return (0); |
return (0); |
|
|
cmd_wait_for_flush(); |
cmd_wait_for_flush(); |
|
|
TAILQ_FOREACH_SAFE(c, &clients, entry, c1) { |
TAILQ_FOREACH_SAFE(c, &clients, entry, c1) { |
if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED)) |
if (c->flags & CLIENT_SUSPENDED) |
server_client_lost(c); |
server_client_lost(c); |
else |
else |
server_write_client(c, MSG_SHUTDOWN, NULL, 0); |
proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0); |
c->session = NULL; |
c->session = NULL; |
} |
} |
|
|
|
|
|
|
/* Callback for server socket. */ |
/* Callback for server socket. */ |
void |
void |
server_accept_callback(int fd, short events, unused void *data) |
server_accept(int fd, short events, unused void *data) |
{ |
{ |
struct sockaddr_storage sa; |
struct sockaddr_storage sa; |
socklen_t slen = sizeof sa; |
socklen_t slen = sizeof sa; |
|
|
event_del(&server_ev_accept); |
event_del(&server_ev_accept); |
|
|
if (timeout == 0) { |
if (timeout == 0) { |
event_set(&server_ev_accept, |
event_set(&server_ev_accept, server_fd, EV_READ, server_accept, |
server_fd, EV_READ, server_accept_callback, NULL); |
NULL); |
event_add(&server_ev_accept, NULL); |
event_add(&server_ev_accept, NULL); |
} else { |
} else { |
event_set(&server_ev_accept, |
event_set(&server_ev_accept, server_fd, EV_TIMEOUT, |
server_fd, EV_TIMEOUT, server_accept_callback, NULL); |
server_accept, NULL); |
event_add(&server_ev_accept, &tv); |
event_add(&server_ev_accept, &tv); |
} |
} |
} |
} |
|
|
/* Signal handler. */ |
/* Signal handler. */ |
void |
void |
server_signal_callback(int sig, unused short events, unused void *data) |
server_signal(int sig) |
{ |
{ |
int fd; |
int fd; |
|
|