From: Wayne Davison Date: Sun, 26 May 2013 21:52:50 +0000 (-0700) Subject: Avoid I/O via signal-handler thread. X-Git-Tag: v3.1.0pre1~24 X-Git-Url: http://git.samba.org/samba.git/?p=rsync.git;a=commitdiff_plain;h=d4070db6312c4b38980ad165732d6beaaa0c06b3 Avoid I/O via signal-handler thread. The cleanup code will try to flush the output buffer in some circumstances, which is not valid if we're handling an async signal (since it might have interrupted some partial I/O in the main thread). These signals now set a flag and try to let the main I/O handler take care of the exit strategy. Fixes a protocol error that could happen when trying to exit after a kill signal. --- diff --git a/cleanup.c b/cleanup.c index 9de6eab8..971154ce 100644 --- a/cleanup.c +++ b/cleanup.c @@ -34,6 +34,7 @@ extern char *partial_dir; extern char *logfile_name; BOOL shutting_down = False; +BOOL flush_ok_after_signal = False; #ifdef HAVE_SIGACTION static struct sigaction sigact; @@ -182,7 +183,12 @@ NORETURN void _exit_cleanup(int code, const char *file, int line) #include "case_N.h" switch_step++; - if (!code || am_server || am_receiver) + if (flush_ok_after_signal) { + flush_ok_after_signal = False; + if (code == RERR_SIGNAL) + io_flush(FULL_FLUSH); + } + if (!code) io_flush(FULL_FLUSH); /* FALLTHROUGH */ diff --git a/io.c b/io.c index 096225fa..771fc0fc 100644 --- a/io.c +++ b/io.c @@ -57,6 +57,7 @@ extern int protocol_version; extern int remove_source_files; extern int preserve_hard_links; extern BOOL extra_flist_sending_enabled; +extern BOOL flush_ok_after_signal; extern struct stats stats; extern struct file_list *cur_flist; #ifdef ICONV_OPTION @@ -73,6 +74,7 @@ BOOL flist_receiving_enabled = False; /* Ignore an EOF error if non-zero. See whine_about_eof(). */ int kluge_around_eof = 0; +int got_kill_signal = -1; /* is set to 0 only after multiplexed I/O starts */ int sock_f_in = -1; int sock_f_out = -1; @@ -852,6 +854,12 @@ static char *perform_io(size_t needed, int flags) } } + if (got_kill_signal > 0) { + got_kill_signal = -1; + flush_ok_after_signal = True; + exit_cleanup(RERR_SIGNAL); + } + /* We need to help prevent deadlock by doing what reading * we can whenever we are here trying to write. */ if (IN_MULTIPLEXED_AND_READY && !(flags & PIO_NEED_INPUT)) { @@ -2282,6 +2290,7 @@ void io_start_multiplex_out(int fd) iobuf.out_empty_len = 4; /* See also OUT_MULTIPLEXED */ io_start_buffering_out(fd); + got_kill_signal = 0; iobuf.raw_data_header_pos = iobuf.out.pos + iobuf.out.len; iobuf.out.len += 4; @@ -2329,6 +2338,9 @@ int io_end_multiplex_out(int mode) iobuf.out.len = 0; iobuf.out_empty_len = 0; + if (got_kill_signal > 0) /* Just in case... */ + exit_cleanup(RERR_SIGNAL); + got_kill_signal = -1; return ret; } diff --git a/rsync.c b/rsync.c index cf210099..1f9b0297 100644 --- a/rsync.c +++ b/rsync.c @@ -42,6 +42,7 @@ extern int am_generator; extern int am_starting_up; extern int allow_8bit_chars; extern int protocol_version; +extern int got_kill_signal; extern int inc_recurse; extern int inplace; extern int flist_eof; @@ -599,6 +600,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp, return updated; } +/* This is only called for SIGINT, SIGHUP, and SIGTERM. */ RETSIGTYPE sig_int(int sig_num) { /* KLUGE: if the user hits Ctrl-C while ssh is prompting @@ -610,10 +612,23 @@ RETSIGTYPE sig_int(int sig_num) * not ssh waiting for a password, then this tiny delay * shouldn't hurt anything. */ msleep(400); + /* If we're an rsync daemon listener (not a daemon server), * we'll exit with status 0 if we received SIGTERM. */ if (am_daemon && !am_server && sig_num == SIGTERM) exit_cleanup(0); + + /* If the signal arrived on the server side (or for the receiver + * process on the client), we want to try to do a controlled shutdown + * that lets the client side (generator process) know what happened. + * To do this, we set a flag and let the normal process handle the + * shutdown. We only attempt this if multiplexed IO is in effect and + * we didn't already set the flag. */ + if (!got_kill_signal && (am_server || am_receiver)) { + got_kill_signal = sig_num; + return; + } + exit_cleanup(RERR_SIGNAL); }