diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2014-05-02 11:05:03 +0400 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2014-05-02 11:05:03 +0400 |
commit | 528808fa7b0778931fb624e95c38cf8cbc2fff90 (patch) | |
tree | d66730c8a6cdbff37c69bd88a511bb486ed55d71 | |
parent | fe33683c8bad841a1b5e947fcc6a502b85ca53cf (diff) |
libbb: make rtc_xopen try harder on EBUSY
function old new delta
rtc_xopen 77 139 +62
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | libbb/rtc.c | 52 |
1 files changed, 42 insertions, 10 deletions
diff --git a/libbb/rtc.c b/libbb/rtc.c index 97455e86a..f84da09bb 100644 --- a/libbb/rtc.c +++ b/libbb/rtc.c @@ -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) |