2828#include <poll.h>
2929#include <sys/uio.h>
3030#include <ctype.h>
31+ #include <time.h>
3132
3233#include "config.h"
3334
5051static struct option long_options [] =
5152{
5253 {"delay" , required_argument , NULL , 'd' },
54+ {"jitter" , required_argument , NULL , 'j' },
5355 {"message" , required_argument , NULL , 'm' },
5456 {"until" , required_argument , NULL , 'u' },
5557 {"while" , required_argument , NULL , 'w' },
@@ -116,6 +118,10 @@ static int help(const char *name, const char *msg, int code)
116118 " delays allow subsequent delays to be different,\n"
117119 " with the last delay repeated.\n"
118120 "\n"
121+ " -j seconds, --jitter=seconds The number of seconds of jitter\n"
122+ " to add to each delay attempt. A random number of nanoseconds between\n"
123+ " zero and this number will be added to the delay.\n"
124+ "\n"
119125 " -m message, --message=message A message to include in the notification\n"
120126 " when repeat has backed off. Defaults to the\n"
121127 " command name.\n"
@@ -185,7 +191,7 @@ static int help(const char *name, const char *msg, int code)
185191 "\n"
186192 " In this example, we try three times before giving up.\n"
187193 "\n"
188- "\t~$ retry --times=3 -- false\n"
194+ "\t~$ retry --times=3 -- false\n"
189195 "\tretry: false returned 1, backing off for 10 seconds and trying again...\n"
190196 "\tretry: false returned 1, backing off for 10 seconds and trying again...\n"
191197 "\tretry: false returned 1, giving up.\n"
@@ -405,19 +411,52 @@ static int pump(const char *name, pump_t *pumps)
405411 return 0 ;
406412}
407413
414+ void seed_jitter ()
415+ {
416+ struct timespec ts ;
417+
418+ /*
419+ * Seed the random number generator with the number of
420+ * nanoseconds returned by the system clock.
421+ *
422+ * Two retries should be unlikely to return the same
423+ * number of nanoseconds.
424+ */
425+
426+ clock_gettime (CLOCK_REALTIME , & ts );
427+
428+ srand ((unsigned int )ts .tv_nsec );
429+
430+ return ;
431+ }
432+
433+ void add_jitter (long int j , struct timespec * ts )
434+ {
435+ /*
436+ * We assume that sampling bias is not a big enough
437+ * problem for jitter.
438+ *
439+ * The nanoseconds should smear a thundering herd.
440+ */
441+ ts -> tv_sec += rand () % (j );
442+ ts -> tv_nsec += rand () % (1000000000 );
443+ }
444+
408445int main (int argc , char * * argv )
409446{
410447 const char * name = argv [0 ];
411448 const char * repeat_until = "success" ;
412449 const char * repeat_while = NULL ;
413450 const char * message = NULL ;
414451 char * delay = DEFAULT_DELAY ;
452+ struct timespec ts ;
415453 pump_t pumps [PUMPS ] = { 0 };
416454 int c , status = 0 , i ;
417455 long int d = 0 ;
456+ long int j = 0 ;
418457 long int times = DEFAULT_TIMES ;
419458
420- while ((c = getopt_long (argc , argv , "+d:m:t:u:w:hv" , long_options , NULL )) != -1 ) {
459+ while ((c = getopt_long (argc , argv , "+d:j: m:t:u:w:hv" , long_options , NULL )) != -1 ) {
421460
422461 switch (c )
423462 {
@@ -435,6 +474,16 @@ int main (int argc, char **argv)
435474
436475 } while (optarg ++ [0 ] == ',' );
437476
477+ break ;
478+ case 'j' :
479+ errno = 0 ;
480+
481+ j = strtol (optarg , & optarg , 10 );
482+
483+ if (errno || optarg [0 ] || j < 0 ) {
484+ return help (name , "Jitter must be bigger or equal to 0.\n" , EXIT_FAILURE );
485+ }
486+
438487 break ;
439488 case 'm' :
440489 message = optarg ;
@@ -482,6 +531,8 @@ int main (int argc, char **argv)
482531 return help (name , "No command specified.\n" , EXIT_FAILURE );
483532 }
484533
534+ seed_jitter ();
535+
485536 while (times ) {
486537 pid_t w , f ;
487538 int inpair [2 ], outpair [2 ];
@@ -617,13 +668,20 @@ int main (int argc, char **argv)
617668 delay ++ ;
618669 }
619670
620- if (d ) {
671+ ts .tv_sec = d ;
672+ ts .tv_nsec = 0 ;
673+
674+ if (j ) {
675+ add_jitter (j , & ts );
676+ }
677+
678+ if (ts .tv_sec && ts .tv_nsec ) {
621679 fprintf (stderr ,
622680 "%s: %s returned %d, backing off for %ld second%s and trying again...\n" ,
623681 name , message ? message : argv [optind ], status ,
624- d , d > 1 ? "s" : "" );
682+ ( long ) ts . tv_sec , ts . tv_sec != 1 ? "s" : "" );
625683
626- sleep ( d );
684+ nanosleep ( & ts , NULL );
627685 }
628686 else {
629687 fprintf (stderr ,
0 commit comments