We should not use the date in the header when patching, because that
[rsync/rsync-patches.git] / threaded-receiver.diff
CommitLineData
3ca259e2
WD
1This patch changes the receiving side to have the receiving code use a thread
2instead of a forked process. This extra thread does read from the socket, but
3it sends any stdout/stderr messages to the generator (main thread) to output.
4
5** This is very new code. ** Yes, it passes the "make test" testsuite, but
6there may still be some problems, especially in some of the untested features.
7(For one thing, I haven't yet added code to properly handle any keep-alive
8messages that arrive on the receiving side during the --delete-after phase!)
9
10This code just uses pthread.h directly, so configure changes will probably be
11needed to make this compatible with more systems. I have also tested that
12this code works fine using the GNU pth library without any code changes if
13you configured it with --enable-syscall-soft --enable-pthread (you may need
14to twiddle the Makefile options if you didn't install the library, though).
15
4a65fe72
WD
16NOTE: we still need to duplicate the partial_fname static in util.c!
17
3ca259e2
WD
18If you try this out, please send some email to wayned@samba.org or the rsync
19mailing list with your results, build changes, bug reports, etc. Thanks!
20
27e96866 21After applying this patch, run these commands for a successful build:
3ca259e2 22
27e96866
WD
23 ./prepare-source
24 ./configure (optional if already run)
25 make
26
27--- orig/Makefile.in 2006-02-06 05:03:50
3ca259e2
WD
28+++ Makefile.in 2005-12-10 18:35:39
29@@ -6,7 +6,7 @@ exec_prefix=@exec_prefix@
30 bindir=@bindir@
31 mandir=@mandir@
32
33-LIBS=@LIBS@
34+LIBS=@LIBS@ -lpthread
35 CC=@CC@
36 CFLAGS=@CFLAGS@
37 CPPFLAGS=@CPPFLAGS@
8857e5dd
WD
38--- orig/cleanup.c 2006-02-03 20:00:35
39+++ cleanup.c 2006-02-03 20:07:44
bc5988ec
WD
40@@ -26,10 +26,6 @@ extern int keep_partial;
41 extern int log_got_error;
42 extern char *partial_dir;
43
8857e5dd 44-#ifdef HAVE_SIGACTION
bc5988ec
WD
45-static struct sigaction sigact;
46-#endif
47-
48 /**
49 * Close all open sockets and files, allowing a (somewhat) graceful
50 * shutdown() of socket connections. This eliminates the abortive
51@@ -98,9 +94,6 @@ void _exit_cleanup(int code, const char
3ca259e2
WD
52 }
53 inside_cleanup++;
54
bc5988ec
WD
55- SIGACTION(SIGUSR1, SIG_IGN);
56- SIGACTION(SIGUSR2, SIG_IGN);
3ca259e2
WD
57-
58 if (verbose > 3) {
59 rprintf(FINFO,"_exit_cleanup(code=%d, file=%s, line=%d): entered\n",
93ca4d27 60 code, file, line);
bc5988ec 61@@ -132,8 +125,6 @@ void _exit_cleanup(int code, const char
3ca259e2
WD
62 io_flush(FULL_FLUSH);
63 if (cleanup_fname)
64 do_unlink(cleanup_fname);
65- if (code)
66- kill_all(SIGUSR1);
67 if (cleanup_pid && cleanup_pid == getpid()) {
68 char *pidf = lp_pid_file();
69 if (pidf && *pidf)
8a0123e5
WD
70--- orig/errcode.h 2005-12-16 23:48:43
71+++ errcode.h 2005-12-16 23:50:02
72@@ -37,7 +37,6 @@
73 #define RERR_CRASHED 15 /* sibling crashed */
74 #define RERR_TERMINATED 16 /* sibling terminated abnormally */
75
76-#define RERR_SIGNAL1 19 /* status returned when sent SIGUSR1 */
77 #define RERR_SIGNAL 20 /* status returned when sent SIGINT, SIGTERM, SIGHUP */
78 #define RERR_WAITCHILD 21 /* some error returned by waitpid() */
79 #define RERR_MALLOC 22 /* error allocating core memory buffers */
27e96866 80--- orig/generator.c 2006-02-05 06:40:40
3ca259e2 81+++ generator.c 2005-12-08 23:17:08
27e96866 82@@ -67,7 +67,6 @@ extern OFF_T min_size;
3ca259e2
WD
83 extern int io_error;
84 extern int allowed_lull;
85 extern int sock_f_out;
86-extern int ignore_timeout;
87 extern int protocol_version;
88 extern int fuzzy_basis;
89 extern int always_checksum;
27e96866 90@@ -98,6 +97,11 @@ static int deletion_count = 0; /* used t
14824301
WD
91 static int can_link_symlinks = 1; /* start out optimistic */
92 static int can_link_devices = 1;
3ca259e2
WD
93
94+/* These vars are local copies so that the receiver can use the originals. */
95+static int GEN_append_mode;
96+static int GEN_make_backups;
97+static int GEN_csum_length;
98+
99 /* For calling delete_file() */
100 #define DEL_FORCE_RECURSE (1<<1) /* recurse even w/o --force */
101 #define DEL_TERSE (1<<3)
27e96866 102@@ -446,8 +450,8 @@ static void sum_sizes_sqroot(struct sum_
3ca259e2
WD
103 }
104
105 if (protocol_version < 27) {
106- s2length = csum_length;
107- } else if (csum_length == SUM_LENGTH) {
108+ s2length = GEN_csum_length;
109+ } else if (GEN_csum_length == SUM_LENGTH) {
110 s2length = SUM_LENGTH;
111 } else {
112 int32 c;
27e96866 113@@ -457,7 +461,7 @@ static void sum_sizes_sqroot(struct sum_
3ca259e2
WD
114 for (c = blength; c >>= 1 && b; b--) {}
115 /* add a bit, subtract rollsum, round up. */
116 s2length = (b + 1 - 32 + 7) / 8; /* --optimize in compiler-- */
117- s2length = MAX(s2length, csum_length);
118+ s2length = MAX(s2length, GEN_csum_length);
119 s2length = MIN(s2length, SUM_LENGTH);
120 }
121
27e96866 122@@ -491,7 +495,7 @@ static void generate_and_send_sums(int f
3ca259e2
WD
123 sum_sizes_sqroot(&sum, len);
124 write_sum_head(f_out, &sum);
125
126- if (append_mode > 0 && f_copy < 0)
127+ if (GEN_append_mode > 0 && f_copy < 0)
128 return;
129
130 if (len > 0)
27e96866 131@@ -510,7 +514,7 @@ static void generate_and_send_sums(int f
3ca259e2
WD
132
133 if (f_copy >= 0) {
134 full_write(f_copy, map, n1);
135- if (append_mode > 0)
136+ if (GEN_append_mode > 0)
137 continue;
138 }
139
27e96866 140@@ -1140,7 +1144,7 @@ static void recv_generator(char *fname,
3ca259e2
WD
141 return;
142 }
143
144- if (append_mode && st.st_size > file->length)
145+ if (GEN_append_mode && st.st_size > file->length)
146 return;
147
14824301 148 if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
27e96866 149@@ -1195,7 +1199,7 @@ static void recv_generator(char *fname,
3ca259e2
WD
150 goto notify_others;
151 }
152
153- if (inplace && make_backups && fnamecmp_type == FNAMECMP_FNAME) {
154+ if (inplace && GEN_make_backups && fnamecmp_type == FNAMECMP_FNAME) {
155 if (!(backupptr = get_backup_name(fname))) {
156 close(fd);
157 return;
27e96866 158@@ -1284,7 +1288,10 @@ void generate_files(int f_out, struct fi
3ca259e2
WD
159 int save_ignore_existing = ignore_existing;
160 int save_ignore_non_existing = ignore_non_existing;
161 int save_do_progress = do_progress;
162- int save_make_backups = make_backups;
163+ int save_make_backups = GEN_make_backups = make_backups;
164+
165+ GEN_append_mode = append_mode;
166+ GEN_csum_length = csum_length;
167
168 if (protocol_version >= 29) {
169 itemizing = 1;
27e96866 170@@ -1313,7 +1320,7 @@ void generate_files(int f_out, struct fi
3ca259e2
WD
171 do_delete_pass(flist);
172 do_progress = 0;
173
174- if (append_mode || whole_file < 0)
175+ if (GEN_append_mode || whole_file < 0)
176 whole_file = 0;
177 if (verbose >= 2) {
178 rprintf(FINFO, "delta-transmission %s\n",
27e96866 179@@ -1322,12 +1329,6 @@ void generate_files(int f_out, struct fi
3ca259e2
WD
180 : "enabled");
181 }
182
183- /* Since we often fill up the outgoing socket and then just sit around
184- * waiting for the other 2 processes to do their thing, we don't want
185- * to exit on a timeout. If the data stops flowing, the receiver will
186- * notice that and let us know via the redo pipe (or its closing). */
187- ignore_timeout = 1;
188-
189 for (i = 0; i < flist->count; i++) {
190 struct file_struct *file = flist->files[i];
191
27e96866 192@@ -1371,23 +1372,34 @@ void generate_files(int f_out, struct fi
4a65fe72 193 delete_in_dir(NULL, NULL, NULL, NULL);
3ca259e2
WD
194
195 phase++;
196- csum_length = SUM_LENGTH;
197+ GEN_csum_length = SUM_LENGTH; /* csum_length is set by the receiver */
198 max_size = min_size = ignore_existing = ignore_non_existing = 0;
199 update_only = always_checksum = size_only = 0;
200 ignore_times = 1;
201- if (append_mode) /* resend w/o append mode */
202- append_mode = -1; /* ... but only longer files */
203- make_backups = 0; /* avoid a duplicate backup for inplace processing */
204+ if (GEN_append_mode) /* resend w/o append mode */
205+ GEN_append_mode = -1; /* ... but only longer files */
206+ GEN_make_backups = 0; /* avoid a duplicate backup for inplace processing */
207
208 if (verbose > 2)
209 rprintf(FINFO,"generate_files phase=%d\n",phase);
210
211 write_int(f_out, -1);
212+ io_flush(NORMAL_FLUSH);
213
214 /* files can cycle through the system more than once
215 * to catch initial checksum errors */
216- while ((i = get_redo_num(itemizing, code)) != -1) {
217- struct file_struct *file = flist->files[i];
218+ while (1) {
219+ struct file_struct *file;
220+ if (preserve_hard_links)
221+ check_for_finished_hlinks(itemizing, code);
222+ if ((i = get_redo_num()) < 0) {
223+ if (i == -2)
224+ break;
225+ io_flush(NORMAL_FLUSH);
226+ msleep(20);
227+ continue;
228+ }
229+ file = flist->files[i];
230 if (local_name)
231 strlcpy(fbuf, local_name, sizeof fbuf);
232 else
27e96866 233@@ -1399,27 +1411,43 @@ void generate_files(int f_out, struct fi
3ca259e2
WD
234 phase++;
235 ignore_non_existing = save_ignore_non_existing;
236 ignore_existing = save_ignore_existing;
237- make_backups = save_make_backups;
238+ GEN_make_backups = save_make_backups;
239
240 if (verbose > 2)
241 rprintf(FINFO,"generate_files phase=%d\n",phase);
242
243 write_int(f_out, -1);
244+ io_flush(NORMAL_FLUSH);
245+
246 /* Reduce round-trip lag-time for a useless delay-updates phase. */
247- if (protocol_version >= 29 && !delay_updates)
248+ if (protocol_version >= 29 && !delay_updates) {
249 write_int(f_out, -1);
250+ io_flush(NORMAL_FLUSH);
251+ }
252
253- /* Read MSG_DONE for the redo phase (and any prior messages). */
254- get_redo_num(itemizing, code);
255+ /* Read end marker for the redo phase (and any prior messages). */
256+ while (1) {
257+ if (preserve_hard_links)
258+ check_for_finished_hlinks(itemizing, code);
259+ if (get_redo_num() == -2)
260+ break;
261+ io_flush(NORMAL_FLUSH);
262+ msleep(20);
263+ }
264
265 if (protocol_version >= 29) {
266 phase++;
267 if (verbose > 2)
268 rprintf(FINFO, "generate_files phase=%d\n", phase);
269- if (delay_updates)
270+ if (delay_updates) {
271 write_int(f_out, -1);
272- /* Read MSG_DONE for delay-updates phase & prior messages. */
273- get_redo_num(itemizing, code);
274+ io_flush(NORMAL_FLUSH);
275+ }
276+ /* Read end marker for delay-updates phase & prior messages. */
277+ while (get_redo_num() != -2) {
278+ io_flush(NORMAL_FLUSH);
279+ msleep(20);
280+ }
281 }
282
283 do_progress = save_do_progress;
8857e5dd 284--- orig/io.c 2006-02-04 21:53:39
e89d5d9a 285+++ io.c 2006-02-01 19:50:09
3ca259e2
WD
286@@ -47,7 +47,6 @@ extern int allowed_lull;
287 extern int am_server;
288 extern int am_daemon;
289 extern int am_sender;
290-extern int am_generator;
291 extern int eol_nulls;
292 extern int read_batch;
293 extern int csum_length;
294@@ -60,7 +59,6 @@ extern struct stats stats;
295 extern struct file_list *the_file_list;
296
297 const char phase_unknown[] = "unknown";
298-int ignore_timeout = 0;
299 int batch_fd = -1;
300 int batch_gen_fd = -1;
301
302@@ -84,7 +82,6 @@ const char *io_read_phase = phase_unknow
303 int kluge_around_eof = 0;
304
305 int msg_fd_in = -1;
306-int msg_fd_out = -1;
307 int sock_f_in = -1;
308 int sock_f_out = -1;
309
310@@ -109,27 +106,32 @@ static int select_timeout = SELECT_TIMEO
311 static void read_loop(int fd, char *buf, size_t len);
312
313 struct flist_ndx_item {
314- struct flist_ndx_item *next;
315+ volatile struct flist_ndx_item *next;
316 int ndx;
317 };
318
319 struct flist_ndx_list {
320- struct flist_ndx_item *head, *tail;
321+ volatile struct flist_ndx_item *head, *tail;
322+ pthread_mutex_t mutex;
323 };
324
325-static struct flist_ndx_list redo_list, hlink_list;
326+static struct flist_ndx_list redo_list = { NULL, NULL, PTHREAD_MUTEX_INITIALIZER };
327+static struct flist_ndx_list hlink_list = { NULL, NULL, PTHREAD_MUTEX_INITIALIZER };
328
329 struct msg_list_item {
330- struct msg_list_item *next;
331+ volatile struct msg_list_item *next;
332+ pthread_mutex_t mutex;
333 char *buf;
334 int len;
335+ enum msgcode code;
336 };
337
338 struct msg_list {
339- struct msg_list_item *head, *tail;
340+ volatile struct msg_list_item *head, *tail;
341+ pthread_mutex_t mutex;
342 };
343
344-static struct msg_list msg_list;
345+static struct msg_list msg_list = { NULL, NULL, PTHREAD_MUTEX_INITIALIZER };
346
347 static void flist_ndx_push(struct flist_ndx_list *lp, int ndx)
348 {
349@@ -139,27 +141,31 @@ static void flist_ndx_push(struct flist_
350 out_of_memory("flist_ndx_push");
351 item->next = NULL;
352 item->ndx = ndx;
353+ pthread_mutex_lock(&redo_list.mutex);
354 if (lp->tail)
355 lp->tail->next = item;
356 else
357 lp->head = item;
358 lp->tail = item;
359+ pthread_mutex_unlock(&redo_list.mutex);
360 }
361
362 static int flist_ndx_pop(struct flist_ndx_list *lp)
363 {
364- struct flist_ndx_item *next;
365+ struct flist_ndx_item *head, *next;
366 int ndx;
367
368 if (!lp->head)
369 return -1;
370
371- ndx = lp->head->ndx;
372- next = lp->head->next;
373- free(lp->head);
374- lp->head = next;
375- if (!next)
376+ pthread_mutex_lock(&hlink_list.mutex);
377+ head = (struct flist_ndx_item *)lp->head;
378+ next = (struct flist_ndx_item *)head->next;
379+ ndx = head->ndx;
380+ if (!(lp->head = next))
381 lp->tail = NULL;
382+ pthread_mutex_unlock(&hlink_list.mutex);
383+ free(head);
384
385 return ndx;
386 }
387@@ -168,7 +174,7 @@ static void check_timeout(void)
388 {
389 time_t t;
390
391- if (!io_timeout || ignore_timeout)
392+ if (!io_timeout)
393 return;
394
395 if (!last_io_in) {
396@@ -209,45 +215,40 @@ void set_io_timeout(int secs)
397
398 /* Setup the fd used to receive MSG_* messages. Only needed during the
399 * early stages of being a local sender (up through the sending of the
400- * file list) or when we're the generator (to fetch the messages from
401- * the receiver). */
402+ * file list). */
403 void set_msg_fd_in(int fd)
404 {
405 msg_fd_in = fd;
406 }
407
408-/* Setup the fd used to send our MSG_* messages. Only needed when
409- * we're the receiver (to send our messages to the generator). */
410-void set_msg_fd_out(int fd)
411-{
412- msg_fd_out = fd;
413- set_nonblocking(msg_fd_out);
414-}
415-
416 /* Add a message to the pending MSG_* list. */
417 static void msg_list_add(int code, char *buf, int len)
418 {
419 struct msg_list_item *ml;
420
421+ assert(am_receiver());
422 if (!(ml = new(struct msg_list_item)))
423 out_of_memory("msg_list_add");
424 ml->next = NULL;
425- if (!(ml->buf = new_array(char, len+4)))
426+ /* NOTE: the "+ 1" allows rwrite() to use the buf! */
427+ if (!(ml->buf = new_array(char, len + 1)))
428 out_of_memory("msg_list_add");
429- SIVAL(ml->buf, 0, ((code+MPLEX_BASE)<<24) | len);
430- memcpy(ml->buf+4, buf, len);
431- ml->len = len+4;
432+ memcpy(ml->buf, buf, len);
433+ ml->len = len;
434+ ml->code = code;
435+
436+ pthread_mutex_lock(&msg_list.mutex);
437 if (msg_list.tail)
438 msg_list.tail->next = ml;
439 else
440 msg_list.head = ml;
441 msg_list.tail = ml;
442+ pthread_mutex_unlock(&msg_list.mutex);
443 }
444
445-/* Read a message from the MSG_* fd and handle it. This is called either
446+/* Read a message from the MSG_* fd and handle it. This is only called
447 * during the early stages of being a local sender (up through the sending
448- * of the file list) or when we're the generator (to fetch the messages
449- * from the receiver). */
450+ * of the file list). */
451 static void read_msg_fd(void)
452 {
453 char buf[2048];
e89d5d9a 454@@ -266,47 +267,6 @@ static void read_msg_fd(void)
3ca259e2
WD
455 tag = (tag >> 24) - MPLEX_BASE;
456
457 switch (tag) {
458- case MSG_DONE:
459- if (len != 0 || !am_generator) {
460- rprintf(FERROR, "invalid message %d:%d\n", tag, len);
461- exit_cleanup(RERR_STREAMIO);
462- }
463- flist_ndx_push(&redo_list, -1);
464- break;
465- case MSG_REDO:
466- if (len != 4 || !am_generator) {
467- rprintf(FERROR, "invalid message %d:%d\n", tag, len);
468- exit_cleanup(RERR_STREAMIO);
469- }
470- read_loop(fd, buf, 4);
471- flist_ndx_push(&redo_list, IVAL(buf,0));
472- break;
473- case MSG_DELETED:
474- if (len >= (int)sizeof buf || !am_generator) {
475- rprintf(FERROR, "invalid message %d:%d\n", tag, len);
476- exit_cleanup(RERR_STREAMIO);
477- }
478- read_loop(fd, buf, len);
479- io_multiplex_write(MSG_DELETED, buf, len);
480- break;
481- case MSG_SUCCESS:
482- if (len != 4 || !am_generator) {
483- rprintf(FERROR, "invalid message %d:%d\n", tag, len);
484- exit_cleanup(RERR_STREAMIO);
485- }
486- read_loop(fd, buf, len);
487- if (remove_sent_files)
488- io_multiplex_write(MSG_SUCCESS, buf, len);
489- if (preserve_hard_links)
490- flist_ndx_push(&hlink_list, IVAL(buf,0));
491- break;
e89d5d9a
WD
492- case MSG_SOCKERR:
493- if (!am_generator) {
494- rprintf(FERROR, "invalid message %d:%d\n", tag, len);
495- exit_cleanup(RERR_STREAMIO);
496- }
497- close_multiplexing_out();
498- /* FALL THROUGH */
3ca259e2
WD
499 case MSG_INFO:
500 case MSG_ERROR:
501 case MSG_LOG:
e89d5d9a 502@@ -327,71 +287,75 @@ static void read_msg_fd(void)
3ca259e2
WD
503 msg_fd_in = fd;
504 }
505
506-/* Try to push messages off the list onto the wire. If we leave with more
507+/* Try to pop messages off the list onto the wire. If we leave with more
508 * to do, return 0. On error, return -1. If everything flushed, return 1.
509- * This is only active in the receiver. */
510+ * This is only called by the generator. */
511 static int msg_list_flush(int flush_it_all)
512 {
513- static int written = 0;
514- struct timeval tv;
515- fd_set fds;
516-
517- if (msg_fd_out < 0)
518- return -1;
519-
520+ assert(am_generator());
521+ no_flush++;
522 while (msg_list.head) {
523- struct msg_list_item *ml = msg_list.head;
524- int n = write(msg_fd_out, ml->buf + written, ml->len - written);
525- if (n < 0) {
526- if (errno == EINTR)
527- continue;
528- if (errno != EWOULDBLOCK && errno != EAGAIN)
529- return -1;
530- if (!flush_it_all)
531- return 0;
532- FD_ZERO(&fds);
533- FD_SET(msg_fd_out, &fds);
534- tv.tv_sec = select_timeout;
535- tv.tv_usec = 0;
536- if (!select(msg_fd_out+1, NULL, &fds, NULL, &tv))
537- check_timeout();
538- } else if ((written += n) == ml->len) {
539- free(ml->buf);
540- msg_list.head = ml->next;
541- if (!msg_list.head)
542- msg_list.tail = NULL;
543- free(ml);
544- written = 0;
545+ struct msg_list_item *ml = (struct msg_list_item *)msg_list.head;
546+ switch (ml->code) {
e89d5d9a
WD
547+ case MSG_SOCKERR:
548+ close_multiplexing_out();
549+ /* FALL THROUGH */
3ca259e2
WD
550+ case MSG_INFO:
551+ case MSG_ERROR:
552+ case MSG_LOG:
553+ rwrite(ml->code, ml->buf, ml->len);
554+ break;
555+ default:
556+ io_multiplex_write(ml->code, ml->buf, ml->len);
557+ break;
558 }
559+ pthread_mutex_lock(&msg_list.mutex);
560+ if (!(msg_list.head = ml->next))
561+ msg_list.tail = NULL;
562+ pthread_mutex_unlock(&msg_list.mutex);
563+ free(ml->buf);
564+ free(ml);
565+ if (!flush_it_all)
566+ break;
567 }
568+ no_flush--;
569+
570 return 1;
571 }
572
573 void send_msg(enum msgcode code, char *buf, int len)
574 {
575- if (msg_fd_out < 0) {
576+ if (am_receiver())
577+ msg_list_add(code, buf, len);
578+ else
579 io_multiplex_write(code, buf, len);
580- return;
581- }
582- msg_list_add(code, buf, len);
583- msg_list_flush(NORMAL_FLUSH);
584 }
585
586-int get_redo_num(int itemizing, enum logcode code)
587+/* This is only used by the receiver. */
588+void push_redo_num(int ndx)
589 {
590- while (1) {
591- if (hlink_list.head)
592- check_for_finished_hlinks(itemizing, code);
593- if (redo_list.head)
594- break;
595- read_msg_fd();
596- }
597+ assert(am_receiver());
598+ flist_ndx_push(&redo_list, ndx);
599+}
600
601+/* This is only used by the generator. */
602+int get_redo_num(void)
603+{
604+ assert(am_generator());
605 return flist_ndx_pop(&redo_list);
606 }
607
608+/* This is only used by the receiver. */
609+void push_hlink_num(int ndx)
610+{
611+ assert(am_receiver());
612+ flist_ndx_push(&hlink_list, ndx);
613+}
614+
615+/* This is only used by the generator. */
616 int get_hlink_num(void)
617 {
618+ assert(am_generator());
619 return flist_ndx_pop(&hlink_list);
620 }
621
e89d5d9a 622@@ -471,11 +435,6 @@ static int read_timeout(int fd, char *bu
3ca259e2
WD
623 FD_ZERO(&r_fds);
624 FD_ZERO(&w_fds);
625 FD_SET(fd, &r_fds);
626- if (msg_list.head) {
627- FD_SET(msg_fd_out, &w_fds);
628- if (msg_fd_out > maxfd)
629- maxfd = msg_fd_out;
630- }
631 if (io_filesfrom_f_out >= 0) {
632 int new_fd;
633 if (io_filesfrom_buflen == 0) {
e89d5d9a 634@@ -508,9 +467,6 @@ static int read_timeout(int fd, char *bu
3ca259e2
WD
635 continue;
636 }
637
638- if (msg_list.head && FD_ISSET(msg_fd_out, &w_fds))
639- msg_list_flush(NORMAL_FLUSH);
640-
641 if (io_filesfrom_f_out >= 0) {
642 if (io_filesfrom_buflen) {
643 if (FD_ISSET(io_filesfrom_f_out, &w_fds)) {
8857e5dd 644@@ -832,6 +788,8 @@ static void readfd(int fd, char *buffer,
3ca259e2
WD
645 }
646
647 if (fd == write_batch_monitor_in) {
648+ if (am_generator())
649+ rprintf(FINFO, "writing %d bytes to batch file from generator\n", total);
650 if ((size_t)write(batch_fd, buffer, total) != total)
651 exit_cleanup(RERR_FILEIO);
652 }
8857e5dd 653@@ -1087,7 +1045,6 @@ static void writefd_unbuffered(int fd,ch
3ca259e2
WD
654 * to grab any messages they sent before they died. */
655 while (fd == sock_f_out && io_multiplexing_in) {
656 set_io_timeout(30);
657- ignore_timeout = 0;
658 readfd_unbuffered(sock_f_in, io_filesfrom_buf,
659 sizeof io_filesfrom_buf);
660 }
8857e5dd 661@@ -1097,7 +1054,7 @@ static void writefd_unbuffered(int fd,ch
e89d5d9a 662 total += cnt;
3ca259e2
WD
663
664 if (fd == sock_f_out) {
665- if (io_timeout || am_generator)
666+ if (io_timeout || am_generator())
667 last_io_out = time(NULL);
e89d5d9a 668 sleep_for_bwlimit(cnt);
3ca259e2 669 }
8857e5dd 670@@ -1121,7 +1078,7 @@ static void mplex_write(enum msgcode cod
3ca259e2
WD
671 * cause output to occur down the socket. Setting contiguous_write_len
672 * prevents the reading of msg_fd_in once we actually start to write
673 * this sequence of data (though we might read it before the start). */
674- if (am_generator && msg_fd_in >= 0)
675+ if (am_generator() && msg_fd_in >= 0)
676 contiguous_write_len = len + 4;
677
678 if (n > sizeof buffer - 4)
8857e5dd 679@@ -1137,31 +1094,29 @@ static void mplex_write(enum msgcode cod
3ca259e2
WD
680 if (len)
681 writefd_unbuffered(sock_f_out, buf, len);
682
683- if (am_generator && msg_fd_in >= 0)
684+ if (am_generator() && msg_fd_in >= 0)
685 contiguous_write_len = 0;
686 }
687
3ca259e2
WD
688 void io_flush(int flush_it_all)
689 {
690- msg_list_flush(flush_it_all);
691-
692- if (!iobuf_out_cnt || no_flush)
693+ if (no_flush)
694 return;
695
696- if (io_multiplexing_out)
697- mplex_write(MSG_DATA, iobuf_out, iobuf_out_cnt);
698- else
699- writefd_unbuffered(sock_f_out, iobuf_out, iobuf_out_cnt);
700- iobuf_out_cnt = 0;
701+ if (iobuf_out_cnt) {
702+ if (io_multiplexing_out)
703+ mplex_write(MSG_DATA, iobuf_out, iobuf_out_cnt);
704+ else
705+ writefd_unbuffered(sock_f_out, iobuf_out, iobuf_out_cnt);
706+ iobuf_out_cnt = 0;
707+ }
708+
709+ if (am_generator())
710+ msg_list_flush(flush_it_all);
711 }
712
3ca259e2
WD
713 static void writefd(int fd,char *buf,size_t len)
714 {
715- if (fd == msg_fd_out) {
716- rprintf(FERROR, "Internal error: wrong write used in receiver.\n");
717- exit_cleanup(RERR_PROTOCOL);
718- }
719-
720 if (fd == sock_f_out)
721 stats.total_written += len;
722
8857e5dd 723@@ -1374,9 +1329,3 @@ void start_write_batch(int fd)
3ca259e2
WD
724 else
725 write_batch_monitor_in = fd;
726 }
727-
728-void stop_write_batch(void)
729-{
730- write_batch_monitor_out = -1;
731- write_batch_monitor_in = -1;
732-}
8857e5dd 733--- orig/log.c 2006-02-05 04:53:34
8a0123e5 734+++ log.c 2005-12-16 23:49:57
8857e5dd 735@@ -38,7 +38,6 @@ extern int am_sender;
3ca259e2
WD
736 extern int local_server;
737 extern int quiet;
738 extern int module_id;
739-extern int msg_fd_out;
740 extern int protocol_version;
741 extern int preserve_times;
14824301 742 extern int log_format_has_i;
8857e5dd 743@@ -74,7 +73,6 @@ struct {
3ca259e2
WD
744 { RERR_IPC , "error in IPC code" },
745 { RERR_CRASHED , "sibling process crashed" },
746 { RERR_TERMINATED , "sibling process terminated abnormally" },
8a0123e5
WD
747- { RERR_SIGNAL1 , "received SIGUSR1" },
748 { RERR_SIGNAL , "received SIGINT, SIGTERM, or SIGHUP" },
3ca259e2
WD
749 { RERR_WAITCHILD , "waitpid() failed" },
750 { RERR_MALLOC , "error allocating core memory buffers" },
8857e5dd 751@@ -234,8 +232,8 @@ void rwrite(enum logcode code, char *buf
e89d5d9a
WD
752 if (quiet && code == FINFO)
753 return;
3ca259e2
WD
754
755- if (am_server && msg_fd_out >= 0) {
756- /* Pass the message to our sibling. */
757+ if (am_receiver()) {
758+ /* Pass the message to the generator thread. */
759 send_msg((enum msgcode)code, buf, len);
760 return;
761 }
8857e5dd 762--- orig/main.c 2006-02-05 04:53:34
bc5988ec 763+++ main.c 2006-02-02 02:43:44
3ca259e2
WD
764@@ -30,7 +30,6 @@ extern int list_only;
765 extern int am_root;
766 extern int am_server;
767 extern int am_sender;
768-extern int am_generator;
769 extern int am_daemon;
770 extern int blocking_io;
771 extern int remove_sent_files;
8857e5dd 772@@ -84,9 +83,20 @@ struct pid_status {
3ca259e2
WD
773
774 static time_t starttime, endtime;
775 static int64 total_read, total_written;
776+static pthread_t receiver_tid;
777
778 static void show_malloc_stats(void);
779
780+int am_generator()
781+{
782+ return receiver_tid != 0 && pthread_self() != receiver_tid;
783+}
784+
785+int am_receiver()
786+{
787+ return receiver_tid != 0 && pthread_self() == receiver_tid;
788+}
789+
790 /* Works like waitpid(), but if we already harvested the child pid in our
791 * sigchld_handler(), we succeed instead of returning an error. */
792 pid_t wait_process(pid_t pid, int *status_ptr, int flags)
8857e5dd 793@@ -163,7 +173,7 @@ static void handle_stats(int f)
3ca259e2
WD
794 show_flist_stats();
795 }
796
797- if (am_generator)
798+ if (am_generator())
799 return;
800
801 if (am_daemon) {
8857e5dd 802@@ -618,12 +628,30 @@ static void do_server_sender(int f_in, i
3ca259e2
WD
803 exit_cleanup(0);
804 }
805
806+struct thread_args {
807+ struct file_list *flist;
808+ char *local_name;
809+ int f_in;
810+};
811+
812+static void *start_receiver_thread(void *arg)
813+{
814+ static int exit_code;
815+ struct thread_args *ta = (struct thread_args *)arg;
816+
817+ recv_files(ta->f_in, ta->flist, ta->local_name);
818+ handle_stats(ta->f_in);
819+
820+ push_redo_num(-2);
821+
822+ exit_code = log_got_error ? RERR_PARTIAL : 0;
823+ return &exit_code;
824+}
825
826 static int do_recv(int f_in,int f_out,struct file_list *flist,char *local_name)
827 {
828- int pid;
829- int exit_code = 0;
830- int error_pipe[2];
831+ void *value_ptr;
832+ struct thread_args args;
833
834 /* The receiving side mustn't obey this, or an existing symlink that
835 * points to an identical file won't be replaced by the referent. */
8857e5dd 836@@ -632,70 +660,16 @@ static int do_recv(int f_in,int f_out,st
3ca259e2
WD
837 if (preserve_hard_links)
838 init_hard_links();
839
840- if (fd_pair(error_pipe) < 0) {
841- rsyserr(FERROR, errno, "pipe failed in do_recv");
842+ args.f_in = f_in;
843+ args.flist = flist;
844+ args.local_name = local_name;
845+ if (pthread_create(&receiver_tid, NULL, start_receiver_thread, &args) < 0) {
846+ rsyserr(FERROR, errno, "pthread_create failed in do_recv");
847 exit_cleanup(RERR_IPC);
848 }
849
850- io_flush(NORMAL_FLUSH);
851-
852- if ((pid = do_fork()) == -1) {
853- rsyserr(FERROR, errno, "fork failed in do_recv");
854- exit_cleanup(RERR_IPC);
855- }
856-
857- if (pid == 0) {
858- close(error_pipe[0]);
859- if (f_in != f_out)
860- close(f_out);
861-
862- /* we can't let two processes write to the socket at one time */
863- close_multiplexing_out();
864-
865- /* set place to send errors */
866- set_msg_fd_out(error_pipe[1]);
867-
868- recv_files(f_in, flist, local_name);
869- io_flush(FULL_FLUSH);
870- handle_stats(f_in);
871-
872- send_msg(MSG_DONE, "", 0);
873- io_flush(FULL_FLUSH);
874-
875- /* Handle any keep-alive packets from the post-processing work
876- * that the generator does. */
877- if (protocol_version >= 29) {
878- kluge_around_eof = -1;
879-
880- /* This should only get stopped via a USR2 signal. */
881- while (read_int(f_in) == flist->count
882- && read_shortint(f_in) == ITEM_IS_NEW) {}
883-
884- rprintf(FERROR, "Invalid packet at end of run [%s]\n",
885- who_am_i());
886- exit_cleanup(RERR_PROTOCOL);
887- }
888-
889- /* Finally, we go to sleep until our parent kills us with a
890- * USR2 signal. We sleep for a short time, as on some OSes
891- * a signal won't interrupt a sleep! */
892- while (1)
893- msleep(20);
894- }
895-
896- am_generator = 1;
897- close_multiplexing_in();
898- if (write_batch && !am_server)
899- stop_write_batch();
900-
901- close(error_pipe[1]);
902- if (f_in != f_out)
903- close(f_in);
904-
905 io_start_buffering_out();
906
907- set_msg_fd_in(error_pipe[0]);
908-
909 generate_files(f_out, flist, local_name);
910
911 handle_stats(-1);
8857e5dd 912@@ -706,10 +680,13 @@ static int do_recv(int f_in,int f_out,st
3ca259e2
WD
913 }
914 io_flush(FULL_FLUSH);
915
916- set_msg_fd_in(-1);
917- kill(pid, SIGUSR2);
918- wait_process_with_flush(pid, &exit_code);
919- return exit_code;
920+ pthread_join(receiver_tid, &value_ptr);
921+ if (!am_server)
922+ output_summary();
923+
924+ close_all();
925+
926+ return *(int*)value_ptr;
927 }
928
929
8857e5dd 930@@ -1077,22 +1054,6 @@ static int start_client(int argc, char *
3ca259e2
WD
931 return ret;
932 }
933
934-
935-static RETSIGTYPE sigusr1_handler(UNUSED(int val))
936-{
8a0123e5 937- exit_cleanup(RERR_SIGNAL1);
3ca259e2
WD
938-}
939-
940-static RETSIGTYPE sigusr2_handler(UNUSED(int val))
941-{
942- if (!am_server)
943- output_summary();
944- close_all();
945- if (log_got_error)
946- _exit(RERR_PARTIAL);
947- _exit(0);
948-}
949-
950 static RETSIGTYPE sigchld_handler(UNUSED(int val))
951 {
952 #ifdef WNOHANG
8857e5dd
WD
953@@ -1184,8 +1145,6 @@ int main(int argc,char *argv[])
954 # endif
bc5988ec
WD
955 sigact.sa_flags = SA_NOCLDSTOP;
956 #endif
957- SIGACTMASK(SIGUSR1, sigusr1_handler);
958- SIGACTMASK(SIGUSR2, sigusr2_handler);
959 SIGACTMASK(SIGCHLD, sigchld_handler);
3ca259e2 960 #ifdef MAINTAINER_MODE
bc5988ec 961 SIGACTMASK(SIGSEGV, rsync_panic_handler);
3ca259e2
WD
962--- orig/match.c 2005-11-10 16:58:36
963+++ match.c 2005-12-08 23:17:09
964@@ -21,7 +21,7 @@
965
966 extern int verbose;
967 extern int am_server;
968-extern int do_progress;
969+extern int recv_progress;
970 extern int checksum_seed;
971 extern int append_mode;
972
973@@ -133,7 +133,7 @@ static void matched(int f, struct sum_st
974 else
975 last_match = offset;
976
977- if (buf && do_progress)
978+ if (buf && recv_progress)
979 show_progress(last_match, buf->file_size);
980 }
981
982@@ -333,7 +333,7 @@ void match_sums(int f, struct sum_struct
983 if (append_mode) {
984 OFF_T j = 0;
985 for (j = CHUNK_SIZE; j < s->flength; j += CHUNK_SIZE) {
986- if (buf && do_progress)
987+ if (buf && recv_progress)
988 show_progress(last_match, buf->file_size);
989 sum_update(map_ptr(buf, last_match, CHUNK_SIZE),
990 CHUNK_SIZE);
991@@ -341,7 +341,7 @@ void match_sums(int f, struct sum_struct
992 }
993 if (last_match < s->flength) {
994 int32 len = s->flength - last_match;
995- if (buf && do_progress)
996+ if (buf && recv_progress)
997 show_progress(last_match, buf->file_size);
998 sum_update(map_ptr(buf, last_match, len), len);
999 last_match = s->flength;
8857e5dd 1000--- orig/options.c 2006-02-03 23:51:57
3ca259e2 1001+++ options.c 2005-12-08 23:17:09
4a65fe72 1002@@ -73,7 +73,6 @@ int def_compress_level = Z_DEFAULT_COMPR
3ca259e2
WD
1003 int am_root = 0;
1004 int am_server = 0;
1005 int am_sender = 0;
1006-int am_generator = 0;
1007 int am_starting_up = 1;
1008 int orig_umask = 0;
1009 int relative_paths = -1;
4a65fe72 1010@@ -94,6 +93,7 @@ int am_daemon = 0;
3ca259e2
WD
1011 int daemon_over_rsh = 0;
1012 int do_stats = 0;
1013 int do_progress = 0;
1014+int recv_progress = 0;
1015 int keep_partial = 0;
1016 int safe_symlinks = 0;
1017 int copy_unsafe_links = 0;
4a65fe72 1018@@ -1290,6 +1290,7 @@ int parse_arguments(int *argc, const cha
3ca259e2
WD
1019 if ((do_progress || dry_run) && !verbose && !log_before_transfer
1020 && !am_server)
1021 verbose = 1;
1022+ recv_progress = do_progress;
1023
1024 if (dry_run)
1025 do_xfers = 0;
4a65fe72 1026--- orig/pipe.c 2006-01-21 08:03:40
3ca259e2 1027+++ pipe.c 2005-12-08 23:17:09
4a65fe72 1028@@ -56,7 +56,7 @@ pid_t piped_child(char **command, int *f
3ca259e2
WD
1029 exit_cleanup(RERR_IPC);
1030 }
1031
1032- pid = do_fork();
1033+ pid = fork();
1034 if (pid == -1) {
1035 rsyserr(FERROR, errno, "fork");
1036 exit_cleanup(RERR_IPC);
4a65fe72 1037@@ -120,7 +120,7 @@ pid_t local_child(int argc, char **argv,
3ca259e2
WD
1038 exit_cleanup(RERR_IPC);
1039 }
1040
1041- pid = do_fork();
1042+ pid = fork();
1043 if (pid == -1) {
1044 rsyserr(FERROR, errno, "fork");
1045 exit_cleanup(RERR_IPC);
4a65fe72 1046--- orig/receiver.c 2006-01-31 02:30:18
93ca4d27 1047+++ receiver.c 2006-01-14 08:30:29
3ca259e2
WD
1048@@ -24,7 +24,7 @@ extern int verbose;
1049 extern int do_xfers;
1050 extern int am_daemon;
1051 extern int am_server;
1052-extern int do_progress;
1053+extern int recv_progress;
1054 extern int log_before_transfer;
1055 extern int log_format_has_i;
1056 extern int daemon_log_format_has_i;
93ca4d27 1057@@ -219,7 +219,7 @@ static int receive_data(int f_in, char *
3ca259e2
WD
1058 if (sum.remainder)
1059 sum.flength -= sum.blength - sum.remainder;
1060 for (j = CHUNK_SIZE; j < sum.flength; j += CHUNK_SIZE) {
1061- if (do_progress)
1062+ if (recv_progress)
1063 show_progress(offset, total_size);
1064 sum_update(map_ptr(mapbuf, offset, CHUNK_SIZE),
1065 CHUNK_SIZE);
93ca4d27 1066@@ -227,7 +227,7 @@ static int receive_data(int f_in, char *
3ca259e2
WD
1067 }
1068 if (offset < sum.flength) {
1069 int32 len = sum.flength - offset;
1070- if (do_progress)
1071+ if (recv_progress)
1072 show_progress(offset, total_size);
1073 sum_update(map_ptr(mapbuf, offset, len), len);
1074 offset = sum.flength;
93ca4d27 1075@@ -240,7 +240,7 @@ static int receive_data(int f_in, char *
3ca259e2
WD
1076 }
1077
1078 while ((i = recv_token(f_in, &data)) != 0) {
1079- if (do_progress)
1080+ if (recv_progress)
1081 show_progress(offset, total_size);
1082
1083 if (i > 0) {
93ca4d27 1084@@ -308,7 +308,7 @@ static int receive_data(int f_in, char *
3ca259e2
WD
1085 ftruncate(fd, offset);
1086 #endif
1087
1088- if (do_progress)
1089+ if (recv_progress)
1090 end_progress(total_size);
1091
1092 if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
93ca4d27
WD
1093@@ -359,12 +359,12 @@ static void handle_delayed_updates(struc
1094 "rename failed for %s (from %s)",
1095 full_fname(fname), partialptr);
3ca259e2
WD
1096 } else {
1097- if (remove_sent_files
1098- || (preserve_hard_links
1099- && file->link_u.links)) {
1100+ if (remove_sent_files) {
1101 SIVAL(numbuf, 0, i);
1102 send_msg(MSG_SUCCESS,numbuf,4);
1103 }
3ca259e2
WD
1104+ if (preserve_hard_links && file->link_u.links)
1105+ push_hlink_num(i);
93ca4d27 1106 handle_partial_dir(partialptr, PDIR_DELETE);
3ca259e2
WD
1107 }
1108 }
93ca4d27 1109@@ -415,11 +415,6 @@ int recv_files(int f_in, struct file_lis
3ca259e2
WD
1110 if (verbose > 2)
1111 rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
1112
1113- if (flist->hlink_pool) {
1114- pool_destroy(flist->hlink_pool);
1115- flist->hlink_pool = NULL;
1116- }
1117-
1118 if (delay_updates)
1119 init_delayed_bits(flist->count);
1120
93ca4d27 1121@@ -440,7 +435,7 @@ int recv_files(int f_in, struct file_lis
3ca259e2
WD
1122 rprintf(FINFO, "recv_files phase=%d\n", phase);
1123 if (phase == 2 && delay_updates)
1124 handle_delayed_updates(flist, local_name);
1125- send_msg(MSG_DONE, "", 0);
1126+ push_redo_num(-2);
1127 if (keep_partial && !partial_dir)
1128 make_backups = 0; /* prevents double backup */
1129 if (append_mode) {
93ca4d27 1130@@ -662,7 +657,7 @@ int recv_files(int f_in, struct file_lis
3ca259e2
WD
1131 /* log the transfer */
1132 if (log_before_transfer)
1133 log_item(file, &initial_stats, iflags, NULL);
1134- else if (!am_server && verbose && do_progress)
1135+ else if (!am_server && verbose && recv_progress)
93ca4d27 1136 rprintf(FINFO, "%s\n", fname);
3ca259e2
WD
1137
1138 /* recv file data */
4a65fe72 1139@@ -705,11 +700,12 @@ int recv_files(int f_in, struct file_lis
3ca259e2
WD
1140 cleanup_disable();
1141
1142 if (recv_ok > 0) {
1143- if (remove_sent_files
1144- || (preserve_hard_links && file->link_u.links)) {
1145+ if (remove_sent_files) {
1146 SIVAL(numbuf, 0, i);
1147 send_msg(MSG_SUCCESS, numbuf, 4);
1148 }
1149+ if (preserve_hard_links && file->link_u.links)
1150+ push_hlink_num(i);
1151 } else if (!recv_ok) {
1152 int msgtype = phase || read_batch ? FERROR : FINFO;
1153 if (msgtype == FERROR || verbose) {
4a65fe72 1154@@ -731,10 +727,8 @@ int recv_files(int f_in, struct file_lis
93ca4d27
WD
1155 "%s: %s failed verification -- update %s%s.\n",
1156 errstr, fname, keptstr, redostr);
3ca259e2
WD
1157 }
1158- if (!phase) {
1159- SIVAL(numbuf, 0, i);
1160- send_msg(MSG_REDO, numbuf, 4);
1161- }
1162+ if (!phase)
1163+ push_redo_num(i);
1164 }
1165 }
1166 make_backups = save_make_backups;
27e96866 1167--- orig/rsync.c 2006-02-05 15:31:49
3ca259e2 1168+++ rsync.c 2005-12-08 23:17:10
8857e5dd 1169@@ -41,7 +41,6 @@ extern int orig_umask;
3ca259e2
WD
1170 extern int am_root;
1171 extern int am_server;
1172 extern int am_sender;
1173-extern int am_generator;
1174 extern int am_starting_up;
1175 extern int preserve_uid;
1176 extern int preserve_gid;
27e96866 1177@@ -291,5 +290,5 @@ const char *who_am_i(void)
3ca259e2
WD
1178 {
1179 if (am_starting_up)
1180 return am_server ? "server" : "client";
1181- return am_sender ? "sender" : am_generator ? "generator" : "receiver";
1182+ return am_sender ? "sender" : am_generator() ? "generator" : "receiver";
1183 }
8857e5dd 1184--- orig/rsync.h 2006-02-03 20:00:36
79d14d37
WD
1185+++ rsync.h 2006-01-17 02:46:03
1186@@ -166,10 +166,8 @@ enum msgcode {
3ca259e2
WD
1187 MSG_DATA=0, /* raw data on the multiplexed stream */
1188 MSG_ERROR=FERROR, MSG_INFO=FINFO, /* remote logging */
e89d5d9a 1189 MSG_LOG=FLOG, MSG_SOCKERR=FSOCKERR, /* sibling logging */
3ca259e2
WD
1190- MSG_REDO=9, /* reprocess indicated flist index */
1191 MSG_SUCCESS=100,/* successfully updated indicated flist index */
1192 MSG_DELETED=101,/* successfully deleted a file on receiving side */
1193- MSG_DONE=86 /* current phase is done */
1194 };
1195
1196 #include "errcode.h"
79d14d37 1197@@ -320,6 +318,7 @@ enum msgcode {
3ca259e2
WD
1198 #endif
1199
1200 #include <assert.h>
1201+#include <pthread.h>
1202
1203 #include "lib/pool_alloc.h"
1204
8857e5dd 1205--- orig/util.c 2006-02-03 20:00:36
3ca259e2 1206+++ util.c 2005-12-08 23:17:10
4a65fe72 1207@@ -413,51 +413,6 @@ int robust_rename(char *from, char *to,
3ca259e2
WD
1208 return -1;
1209 }
1210
1211-
1212-static pid_t all_pids[10];
1213-static int num_pids;
1214-
1215-/** Fork and record the pid of the child. **/
1216-pid_t do_fork(void)
1217-{
1218- pid_t newpid = fork();
1219-
1220- if (newpid != 0 && newpid != -1) {
1221- all_pids[num_pids++] = newpid;
1222- }
1223- return newpid;
1224-}
1225-
1226-/**
1227- * Kill all children.
1228- *
1229- * @todo It would be kind of nice to make sure that they are actually
1230- * all our children before we kill them, because their pids may have
1231- * been recycled by some other process. Perhaps when we wait for a
1232- * child, we should remove it from this array. Alternatively we could
1233- * perhaps use process groups, but I think that would not work on
1234- * ancient Unix versions that don't support them.
1235- **/
1236-void kill_all(int sig)
1237-{
1238- int i;
1239-
1240- for (i = 0; i < num_pids; i++) {
1241- /* Let's just be a little careful where we
1242- * point that gun, hey? See kill(2) for the
1243- * magic caused by negative values. */
1244- pid_t p = all_pids[i];
1245-
1246- if (p == getpid())
1247- continue;
1248- if (p <= 0)
1249- continue;
1250-
1251- kill(p, sig);
1252- }
1253-}
1254-
1255-
1256 /** Turn a user name into a uid */
1257 int name_to_uid(char *name, uid_t *uid)
1258 {