| 1 | // =========================================================== // |
|---|
| 2 | // // |
|---|
| 3 | // File : arb_sleep.h // |
|---|
| 4 | // Purpose : // |
|---|
| 5 | // // |
|---|
| 6 | // Coded by Ralf Westram (coder@reallysoft.de) in May 2013 // |
|---|
| 7 | // Institute of Microbiology (Technical University Munich) // |
|---|
| 8 | // http://www.arb-home.de/ // |
|---|
| 9 | // // |
|---|
| 10 | // =========================================================== // |
|---|
| 11 | |
|---|
| 12 | #ifndef ARB_SLEEP_H |
|---|
| 13 | #define ARB_SLEEP_H |
|---|
| 14 | |
|---|
| 15 | #ifndef _UNISTD_H |
|---|
| 16 | #include <unistd.h> |
|---|
| 17 | #endif |
|---|
| 18 | #ifndef _GLIBCXX_ALGORITHM |
|---|
| 19 | #include <algorithm> |
|---|
| 20 | #endif |
|---|
| 21 | #ifndef _TIME_H |
|---|
| 22 | #include <time.h> |
|---|
| 23 | #endif |
|---|
| 24 | #ifndef _SYS_TIME_H |
|---|
| 25 | #include <sys/time.h> |
|---|
| 26 | #endif |
|---|
| 27 | |
|---|
| 28 | // #define TRACE_SLEEP |
|---|
| 29 | |
|---|
| 30 | enum TimeUnit { USEC = 1, MS = 1000, SEC = 1000*MS }; |
|---|
| 31 | |
|---|
| 32 | inline void ARB_sleep(int amount, TimeUnit tu) { |
|---|
| 33 | arb_assert(amount>=0); |
|---|
| 34 | arb_assert(amount<1000*1000); // use different TimeUnit |
|---|
| 35 | |
|---|
| 36 | struct timespec t; |
|---|
| 37 | switch (tu) { |
|---|
| 38 | case USEC: |
|---|
| 39 | t.tv_sec = 0; |
|---|
| 40 | t.tv_nsec = amount*1000; |
|---|
| 41 | break; |
|---|
| 42 | case MS: |
|---|
| 43 | t.tv_sec = amount/MS; |
|---|
| 44 | t.tv_nsec = (amount-t.tv_sec*MS)*MS*1000; |
|---|
| 45 | break; |
|---|
| 46 | case SEC: |
|---|
| 47 | t.tv_sec = amount; |
|---|
| 48 | t.tv_nsec = 0; |
|---|
| 49 | break; |
|---|
| 50 | } |
|---|
| 51 | |
|---|
| 52 | arb_assert(t.tv_sec>=0); |
|---|
| 53 | arb_assert(t.tv_nsec>=0 && t.tv_nsec<=999999999); |
|---|
| 54 | |
|---|
| 55 | while (1) { |
|---|
| 56 | struct timespec remain; |
|---|
| 57 | |
|---|
| 58 | int res = nanosleep(&t, &remain); |
|---|
| 59 | if (res == 0) break; |
|---|
| 60 | // nanosleep has been interrupted by signal -> call again |
|---|
| 61 | t = remain; |
|---|
| 62 | } |
|---|
| 63 | } |
|---|
| 64 | |
|---|
| 65 | #if defined(TRACE_SLEEP) |
|---|
| 66 | inline const char *timeUnitAbbr(TimeUnit tu) { |
|---|
| 67 | switch (tu) { |
|---|
| 68 | case USEC: return "usec"; |
|---|
| 69 | case MS: return "ms"; |
|---|
| 70 | case SEC: return "s"; |
|---|
| 71 | } |
|---|
| 72 | arb_assert(0); |
|---|
| 73 | return ""; |
|---|
| 74 | } |
|---|
| 75 | #endif |
|---|
| 76 | |
|---|
| 77 | class ARB_inc_sleep { |
|---|
| 78 | int curr_wait, max_wait, inc; |
|---|
| 79 | TimeUnit unit; |
|---|
| 80 | |
|---|
| 81 | void slowdown() { curr_wait = std::min(max_wait, curr_wait+inc); } |
|---|
| 82 | public: |
|---|
| 83 | ARB_inc_sleep(int min_amount, int max_amount, TimeUnit tu, int increment) |
|---|
| 84 | : curr_wait(min_amount), |
|---|
| 85 | max_wait(max_amount), |
|---|
| 86 | inc(increment), |
|---|
| 87 | unit(tu) |
|---|
| 88 | { |
|---|
| 89 | arb_assert(curr_wait>0); |
|---|
| 90 | arb_assert(max_amount>=curr_wait); |
|---|
| 91 | arb_assert(increment>0); |
|---|
| 92 | } |
|---|
| 93 | |
|---|
| 94 | void sleep() { |
|---|
| 95 | #if defined(TRACE_SLEEP) |
|---|
| 96 | fprintf(stderr, "pid %i waits %i %s\n", getpid(), curr_wait, timeUnitAbbr(unit)); |
|---|
| 97 | #endif |
|---|
| 98 | ARB_sleep(curr_wait, unit); |
|---|
| 99 | slowdown(); |
|---|
| 100 | } |
|---|
| 101 | }; |
|---|
| 102 | |
|---|
| 103 | class ARB_timestamp { |
|---|
| 104 | // timer which can be asked how much time passed since it was initialized |
|---|
| 105 | timeval t1; |
|---|
| 106 | |
|---|
| 107 | public: |
|---|
| 108 | ARB_timestamp() { update(); } |
|---|
| 109 | void update() { gettimeofday(&t1, NULp); } |
|---|
| 110 | |
|---|
| 111 | long usec_since() const { |
|---|
| 112 | timeval t2; |
|---|
| 113 | gettimeofday(&t2, NULp); |
|---|
| 114 | return (t2.tv_sec - t1.tv_sec) * SEC + (t2.tv_usec - t1.tv_usec); |
|---|
| 115 | } |
|---|
| 116 | long ms_since() const { return usec_since()/MS; } |
|---|
| 117 | long sec_since() const { return usec_since()/SEC; } |
|---|
| 118 | }; |
|---|
| 119 | |
|---|
| 120 | class ARB_timeout { |
|---|
| 121 | // short timeout |
|---|
| 122 | ARB_timestamp start; |
|---|
| 123 | long amount_usec; |
|---|
| 124 | public: |
|---|
| 125 | ARB_timeout(int amount, TimeUnit tu) |
|---|
| 126 | : amount_usec(amount*tu) |
|---|
| 127 | {} |
|---|
| 128 | bool passed() const { |
|---|
| 129 | return start.usec_since()>=amount_usec; |
|---|
| 130 | } |
|---|
| 131 | |
|---|
| 132 | void restart(double factor) { |
|---|
| 133 | // restart and multiply timeout by factor |
|---|
| 134 | // (use 1.0 to restart with previous timeout) |
|---|
| 135 | |
|---|
| 136 | start.update(); |
|---|
| 137 | amount_usec = amount_usec * factor + 0.5; |
|---|
| 138 | } |
|---|
| 139 | }; |
|---|
| 140 | |
|---|
| 141 | |
|---|
| 142 | #else |
|---|
| 143 | #error arb_sleep.h included twice |
|---|
| 144 | #endif // ARB_SLEEP_H |
|---|