libbb: make rtc_xopen try harder on EBUSY
No binary (build failed)
—
(log yok)
| @@ -33,23 +33,55 @@ int FAST_FUNC rtc_adjtime_is_utc(void) | |
| return utc; | |
| } | |
| + | /* rtc opens are exclusive. |
| + | * Try to run two "hwclock -w" at the same time to see it. |
| + | * Users wouldn't expect that to fail merely because /dev/rtc |
| + | * was momentarily busy, let's try a bit harder on errno == EBUSY. |
| + | */ |
| + | static int open_loop_on_busy(const char *name, int flags) |
| + | { |
| + | int rtc; |
| + | /* |
| + | * Tested with two parallel "hwclock -w" loops. |
| + | * With try = 10, no failures with 2x1000000 loop iterations. |
| + | */ |
| + | int try = 1000 / 20; |
| + | again: |
| + | errno = 0; |
| + | rtc = open(name, flags); |
| + | if (errno == EBUSY) { |
| + | usleep(20 * 1000); |
| + | if (--try != 0) |
| + | goto again; |
| + | /* EBUSY. Last try, exit on error instead of returning -1 */ |
| + | return xopen(name, flags); |
| + | } |
| + | return rtc; |
| + | } |
| + | |
| + | /* Never fails */ |
| int FAST_FUNC rtc_xopen(const char **default_rtc, int flags) | |
| { | |
| int rtc; | |
| + | const char *name = |
| + | "/dev/rtc""\0" |
| + | "/dev/rtc0""\0" |
| + | "/dev/misc/rtc""\0"; |
| - | if (!*default_rtc) { |
| - | *default_rtc = "/dev/rtc"; |
| - | rtc = open(*default_rtc, flags); |
| - | if (rtc >= 0) |
| - | return rtc; |
| - | *default_rtc = "/dev/rtc0"; |
| - | rtc = open(*default_rtc, flags); |
| + | if (!*default_rtc) |
| + | goto try_name; |
| + | name = ""; /*else: we have rtc name, don't try other names */ |
| + | |
| + | for (;;) { |
| + | rtc = open_loop_on_busy(*default_rtc, flags); |
| if (rtc >= 0) | |
| return rtc; | |
| - | *default_rtc = "/dev/misc/rtc"; |
| + | name += strlen(name) + 1; |
| + | if (!name[0]) |
| + | return xopen(*default_rtc, flags); |
| + | try_name: |
| + | *default_rtc = name; |
| } | |
| - | |
| - | return xopen(*default_rtc, flags); |
| } | |
| void FAST_FUNC rtc_read_tm(struct tm *ptm, int fd) | |