I came up with a new way of avoiding the error handling lockup bug in

rsync. It isn't pretty, but it does work and should completely avoid
that class of lockup.
This commit is contained in:
Andrew Tridgell
2001-03-21 13:12:44 +00:00
parent 8ee3d639b2
commit 90ba34e27c
2 changed files with 68 additions and 10 deletions

18
io.c
View File

@@ -48,6 +48,8 @@ static void check_timeout(void)
{
extern int am_server, am_daemon;
time_t t;
err_list_push();
if (!io_timeout) return;
@@ -339,6 +341,8 @@ static void writefd_unbuffered(int fd,char *buf,int len)
int fd_count, count;
struct timeval tv;
err_list_push();
no_flush++;
while (total < len) {
@@ -462,6 +466,9 @@ static void mplex_write(int fd, enum logcode code, char *buf, int len)
void io_flush(void)
{
int fd = multiplex_out_fd;
err_list_push();
if (!io_buffer_count || no_flush) return;
if (io_multiplexing_out) {
@@ -487,6 +494,7 @@ void io_end_buffering(int fd)
a socket to be flushed. Do an explicit shutdown to try to prevent this */
void io_shutdown(void)
{
err_list_push();
if (multiplex_out_fd != -1) close(multiplex_out_fd);
if (io_error_fd != -1) close(io_error_fd);
multiplex_out_fd = -1;
@@ -498,6 +506,8 @@ static void writefd(int fd,char *buf,int len)
{
stats.total_written += len;
err_list_push();
if (!io_buffer || fd != multiplex_out_fd) {
writefd_unbuffered(fd, buf, len);
return;
@@ -635,14 +645,6 @@ int io_multiplex_write(enum logcode code, char *buf, int len)
return 1;
}
/* write a message to the special error fd */
int io_error_write(int f, enum logcode code, char *buf, int len)
{
if (f == -1) return 0;
mplex_write(f, code, buf, len);
return 1;
}
/* stop output multiplexing */
void io_multiplexing_close(void)
{

60
log.c
View File

@@ -67,6 +67,59 @@ static char const *rerr_name(int code)
return NULL;
}
struct err_list {
struct err_list *next;
char *buf;
int len;
int written; /* how many bytes we have written so far */
};
static struct err_list *err_list_head;
static struct err_list *err_list_tail;
/* add an error message to the pending error list */
static void err_list_add(int code, char *buf, int len)
{
struct err_list *el;
el = (struct err_list *)malloc(sizeof(*el));
if (!el) exit_cleanup(RERR_MALLOC);
el->next = NULL;
el->buf = malloc(len+4);
if (!el->buf) exit_cleanup(RERR_MALLOC);
memcpy(el->buf+4, buf, len);
SIVAL(el->buf, 0, ((code+MPLEX_BASE)<<24) | len);
el->len = len+4;
el->written = 0;
if (err_list_tail) {
err_list_tail->next = el;
} else {
err_list_head = el;
}
err_list_tail = el;
}
/* try to push errors off the error list onto the wire */
void err_list_push(void)
{
if (log_error_fd == -1) return;
while (err_list_head) {
struct err_list *el = err_list_head;
int n = write(log_error_fd, el->buf+el->written, el->len - el->written);
if (n == -1) break;
if (n > 0) {
el->written += n;
}
if (el->written == el->len) {
free(el->buf);
err_list_head = el->next;
if (!err_list_head) err_list_tail = NULL;
free(el);
}
}
}
static void logit(int priority, char *buf)
{
@@ -144,6 +197,7 @@ void log_close()
void set_error_fd(int fd)
{
log_error_fd = fd;
set_nonblocking(log_error_fd);
}
/* this is the underlying (unformatted) rsync debugging function. Call
@@ -167,8 +221,10 @@ void rwrite(enum logcode code, char *buf, int len)
return;
}
/* first try to pass it off the our sibling */
if (am_server && io_error_write(log_error_fd, code, buf, len)) {
/* first try to pass it off to our sibling */
if (am_server && log_error_fd != -1) {
err_list_add(code, buf, len);
err_list_push();
return;
}