Merge pull request #27843 from yuwata/usleep_safe

time-util: introduce usleep_safe()
This commit is contained in:
Lennart Poettering 2023-06-23 23:03:15 +02:00 committed by GitHub
commit 031d21bc45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 80 additions and 60 deletions

View file

@ -533,8 +533,8 @@ conf.set10('HAVE_WSTRINGOP_TRUNCATION', has_wstringop_truncation)
conf.set('SIZEOF_DEV_T', cc.sizeof('dev_t', prefix : '#include <sys/types.h>'))
conf.set('SIZEOF_INO_T', cc.sizeof('ino_t', prefix : '#include <sys/types.h>'))
conf.set('SIZEOF_TIME_T', cc.sizeof('time_t', prefix : '#include <sys/time.h>'))
conf.set('SIZEOF_RLIM_T', cc.sizeof('rlim_t', prefix : '#include <sys/resource.h>'))
conf.set('SIZEOF_TIME_T', cc.sizeof('time_t', prefix : '#include <sys/time.h>'))
conf.set('SIZEOF_TIMEX_MEMBER', cc.sizeof('typeof(((struct timex *)0)->freq)', prefix : '#include <sys/timex.h>'))
long_max = cc.compute_int(

View file

@ -93,7 +93,7 @@ int efi_get_variable(
return -EBUSY;
if (try >= EFI_N_RETRIES_NO_DELAY)
(void) usleep(EFI_RETRY_DELAY);
(void) usleep_safe(EFI_RETRY_DELAY);
}
if (n != sizeof(a))

View file

@ -341,7 +341,7 @@ int open_terminal(const char *name, int mode) {
if (c >= 20)
return -errno;
(void) usleep(50 * USEC_PER_MSEC);
(void) usleep_safe(50 * USEC_PER_MSEC);
c++;
}

View file

@ -211,6 +211,14 @@ static inline usec_t usec_sub_signed(usec_t timestamp, int64_t delta) {
return usec_sub_unsigned(timestamp, (usec_t) delta);
}
static inline int usleep_safe(usec_t usec) {
/* usleep() takes useconds_t that is (typically?) uint32_t. Also, usleep() may only support the
* range [0, 1000000]. See usleep(3). Let's override usleep() with nanosleep(). */
// FIXME: use RET_NERRNO() macro here. Currently, this header cannot include errno-util.h.
return nanosleep(TIMESPEC_STORE(usec), NULL) < 0 ? -errno : 0;
}
/* The last second we can format is 31. Dec 9999, 1s before midnight, because otherwise we'd enter 5 digit
* year territory. However, since we want to stay away from this in all timezones we take one day off. */
#define USEC_TIMESTAMP_FORMATTABLE_MAX_64BIT ((usec_t) 253402214399000000) /* Thu 9999-12-30 23:59:59 UTC */

View file

@ -953,7 +953,7 @@ static int loop(const char *root) {
fflush(stdout);
if (arg_batch)
(void) usleep(usec_add(usec_sub_unsigned(last_refresh, t), arg_delay));
(void) usleep_safe(usec_add(usec_sub_unsigned(last_refresh, t), arg_delay));
else {
r = read_one_char(stdin, &key, usec_add(usec_sub_unsigned(last_refresh, t), arg_delay), NULL);
if (r == -ETIMEDOUT)

View file

@ -1962,7 +1962,7 @@ static int run(int argc, char *argv[]) {
end = start + BAD_PASSWORD_DELAY_USEC;
if (n < end)
(void) usleep(usec_sub_unsigned(end, n));
(void) usleep_safe(usec_sub_unsigned(end, n));
}
if (r < 0)
return r;

View file

@ -48,22 +48,22 @@ static void* thread_server(void *p) {
log_debug("Initializing server");
/* Let's play some games, by slowly creating the socket directory, and renaming it in the middle */
(void) usleep(100 * USEC_PER_MSEC);
usleep_safe(100 * USEC_PER_MSEC);
assert_se(mkdir_parents(path, 0755) >= 0);
(void) usleep(100 * USEC_PER_MSEC);
usleep_safe(100 * USEC_PER_MSEC);
assert_se(path_extract_directory(path, &d) >= 0);
assert_se(asprintf(&suffixed, "%s.%" PRIx64, d, random_u64()) >= 0);
assert_se(rename(d, suffixed) >= 0);
(void) usleep(100 * USEC_PER_MSEC);
usleep_safe(100 * USEC_PER_MSEC);
assert_se(asprintf(&suffixed2, "%s.%" PRIx64, d, random_u64()) >= 0);
assert_se(symlink(suffixed2, d) >= 0);
(void) usleep(100 * USEC_PER_MSEC);
usleep_safe(100 * USEC_PER_MSEC);
assert_se(symlink(basename(suffixed), suffixed2) >= 0);
(void) usleep(100 * USEC_PER_MSEC);
usleep_safe(100 * USEC_PER_MSEC);
socklen_t sa_len;
r = sockaddr_un_set_path(&u.un, path);
@ -74,13 +74,13 @@ static void* thread_server(void *p) {
assert_se(fd >= 0);
assert_se(bind(fd, &u.sa, sa_len) >= 0);
usleep(100 * USEC_PER_MSEC);
usleep_safe(100 * USEC_PER_MSEC);
assert_se(listen(fd, SOMAXCONN_DELUXE) >= 0);
usleep(100 * USEC_PER_MSEC);
usleep_safe(100 * USEC_PER_MSEC);
assert_se(touch(path) >= 0);
usleep(100 * USEC_PER_MSEC);
usleep_safe(100 * USEC_PER_MSEC);
log_debug("Initialized server");

View file

@ -650,7 +650,7 @@ TEST(ratelimit) {
for (unsigned i = 0; i < 10; i++) {
log_debug("slow loop iteration %u", i);
assert_se(sd_event_run(e, UINT64_MAX) >= 0);
assert_se(usleep(250 * USEC_PER_MSEC) >= 0);
assert_se(usleep_safe(250 * USEC_PER_MSEC) >= 0);
}
assert_se(sd_event_source_is_ratelimited(s) == 0);
@ -664,7 +664,7 @@ TEST(ratelimit) {
for (unsigned i = 0; i < 10; i++) {
log_debug("fast event loop iteration %u", i);
assert_se(sd_event_run(e, UINT64_MAX) >= 0);
assert_se(usleep(10) >= 0);
assert_se(usleep_safe(10) >= 0);
}
log_info("ratelimit_io_handler: called %u times, event source got ratelimited", count);
assert_se(count < 10);

View file

@ -249,7 +249,7 @@ static void test_dns_stream(bool tls) {
r = connect(clientfd, &server_address.sa, SOCKADDR_LEN(server_address));
if (r >= 0)
break;
usleep(EVENT_TIMEOUT_USEC / 100);
usleep_safe(EVENT_TIMEOUT_USEC / 100);
}
assert_se(r >= 0);

View file

@ -2766,7 +2766,7 @@ static int verity_partition(
try_again:
/* Device is being removed by another process. Let's wait for a while. */
(void) usleep(2 * USEC_PER_MSEC);
(void) usleep_safe(2 * USEC_PER_MSEC);
}
/* All trials failed or a conflicting verity device exists. Let's try to activate with a unique name. */

View file

@ -203,7 +203,7 @@ static int loop_configure_fallback(int fd, const struct loop_config *c) {
/* Sleep some random time, but at least 10ms, at most 250ms. Increase the delay the more
* failed attempts we see */
(void) usleep(UINT64_C(10) * USEC_PER_MSEC +
(void) usleep_safe(UINT64_C(10) * USEC_PER_MSEC +
random_u64_range(UINT64_C(240) * USEC_PER_MSEC * n_attempts/64));
}
@ -595,7 +595,7 @@ static int loop_device_make_internal(
usec = random_u64_range(UINT64_C(10) * USEC_PER_MSEC +
UINT64_C(240) * USEC_PER_MSEC * n_attempts/64);
log_debug("Trying again after %s.", FORMAT_TIMESPAN(usec, USEC_PER_MSEC));
(void) usleep(usec);
(void) usleep_safe(usec);
}
d->backing_file = TAKE_PTR(backing_file);
@ -833,7 +833,7 @@ static LoopDevice* loop_device_free(LoopDevice *d) {
delay *= 2;
}
(void) usleep(delay);
(void) usleep_safe(delay);
}
}

View file

@ -33,12 +33,6 @@ static void set_alarm(usec_t usecs) {
assert_se(setitimer(ITIMER_REAL, &v, NULL) >= 0);
}
static void sleep_for(usec_t usecs) {
/* stupid usleep() might fail if >1000000 */
assert_se(usecs < USEC_PER_SEC);
usleep(usecs);
}
#define TEST_BARRIER(_FUNCTION, _CHILD_CODE, _WAIT_CHILD, _PARENT_CODE, _WAIT_PARENT) \
TEST(_FUNCTION) { \
Barrier b = BARRIER_NULL; \
@ -94,9 +88,9 @@ static void sleep_for(usec_t usecs) {
/*
* Test basic sync points
* This places a barrier in both processes and waits synchronously for them.
* The timeout makes sure the sync works as expected. The sleep_for() on one side
* The timeout makes sure the sync works as expected. The usleep_safe() on one side
* makes sure the exit of the parent does not overwrite previous barriers. Due
* to the sleep_for(), we know that the parent already exited, thus there's a
* to the usleep_safe(), we know that the parent already exited, thus there's a
* pending HUP on the pipe. However, the barrier_sync() prefers reads on the
* eventfd, thus we can safely wait on the barrier.
*/
@ -104,7 +98,7 @@ TEST_BARRIER(barrier_sync,
({
set_alarm(BASE_TIME * 10);
assert_se(barrier_place(&b));
sleep_for(BASE_TIME * 2);
usleep_safe(BASE_TIME * 2);
assert_se(barrier_sync(&b));
}),
TEST_BARRIER_WAIT_SUCCESS(pid1),
@ -124,7 +118,7 @@ TEST_BARRIER(barrier_sync,
*/
TEST_BARRIER(barrier_wait_next,
({
sleep_for(BASE_TIME);
usleep_safe(BASE_TIME);
set_alarm(BASE_TIME * 10);
assert_se(barrier_wait_next(&b));
assert_se(barrier_place(&b));
@ -150,7 +144,7 @@ TEST_BARRIER(barrier_wait_next,
*/
TEST_BARRIER(barrier_wait_next_twice,
({
sleep_for(BASE_TIME);
usleep_safe(BASE_TIME);
set_alarm(BASE_TIME);
assert_se(barrier_wait_next(&b));
assert_se(barrier_wait_next(&b));
@ -161,7 +155,7 @@ TEST_BARRIER(barrier_wait_next_twice,
set_alarm(BASE_TIME * 10);
assert_se(barrier_place(&b));
assert_se(barrier_place(&b));
sleep_for(BASE_TIME * 4);
usleep_safe(BASE_TIME * 4);
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
@ -173,7 +167,7 @@ TEST_BARRIER(barrier_wait_next_twice,
*/
TEST_BARRIER(barrier_wait_next_twice_local,
({
sleep_for(BASE_TIME);
usleep_safe(BASE_TIME);
set_alarm(BASE_TIME);
assert_se(barrier_wait_next(&b));
assert_se(barrier_place(&b));
@ -186,7 +180,7 @@ TEST_BARRIER(barrier_wait_next_twice_local,
set_alarm(BASE_TIME * 10);
assert_se(barrier_place(&b));
assert_se(barrier_place(&b));
sleep_for(BASE_TIME * 4);
usleep_safe(BASE_TIME * 4);
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
@ -198,7 +192,7 @@ TEST_BARRIER(barrier_wait_next_twice_local,
*/
TEST_BARRIER(barrier_wait_next_twice_sync,
({
sleep_for(BASE_TIME);
usleep_safe(BASE_TIME);
set_alarm(BASE_TIME);
assert_se(barrier_wait_next(&b));
assert_se(barrier_sync_next(&b));
@ -219,7 +213,7 @@ TEST_BARRIER(barrier_wait_next_twice_sync,
*/
TEST_BARRIER(barrier_wait_next_twice_local_sync,
({
sleep_for(BASE_TIME);
usleep_safe(BASE_TIME);
set_alarm(BASE_TIME);
assert_se(barrier_wait_next(&b));
assert_se(barrier_place(&b));
@ -253,7 +247,7 @@ TEST_BARRIER(barrier_sync_next,
TEST_BARRIER_WAIT_SUCCESS(pid1),
({
set_alarm(BASE_TIME * 10);
sleep_for(BASE_TIME);
usleep_safe(BASE_TIME);
assert_se(barrier_place(&b));
assert_se(barrier_place(&b));
assert_se(barrier_sync(&b));
@ -274,7 +268,7 @@ TEST_BARRIER(barrier_sync_next_local,
}),
TEST_BARRIER_WAIT_ALARM(pid1),
({
sleep_for(BASE_TIME * 2);
usleep_safe(BASE_TIME * 2);
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
@ -323,7 +317,7 @@ TEST_BARRIER(barrier_wait_abortion_unmatched,
}),
TEST_BARRIER_WAIT_ALARM(pid1),
({
sleep_for(BASE_TIME * 2);
usleep_safe(BASE_TIME * 2);
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
@ -356,7 +350,7 @@ TEST_BARRIER(barrier_wait_abortion_local_unmatched,
}),
TEST_BARRIER_WAIT_ALARM(pid1),
({
sleep_for(BASE_TIME * 2);
usleep_safe(BASE_TIME * 2);
}),
TEST_BARRIER_WAIT_SUCCESS(pid2));
@ -379,12 +373,12 @@ TEST_BARRIER(barrier_exit,
/*
* Test child exit with sleep
* Same as test_barrier_exit but verifies the test really works due to the
* child-exit. We add a usleep() which triggers the alarm in the parent and
* child-exit. We add a usleep_safe() which triggers the alarm in the parent and
* causes the test to time out.
*/
TEST_BARRIER(barrier_no_exit,
({
sleep_for(BASE_TIME * 2);
usleep_safe(BASE_TIME * 2);
}),
TEST_BARRIER_WAIT_SUCCESS(pid1),
({
@ -407,7 +401,7 @@ TEST_BARRIER(barrier_no_exit,
TEST_BARRIER(barrier_pending_exit,
({
set_alarm(BASE_TIME * 4);
sleep_for(BASE_TIME * 2);
usleep_safe(BASE_TIME * 2);
assert_se(barrier_wait_next(&b));
assert_se(barrier_sync_next(&b));
assert_se(barrier_place(&b));

View file

@ -31,27 +31,27 @@ int main(int argc, char *argv[]) {
sd_notify(0,
"STATUS=Starting up");
usleep(duration);
usleep_safe(duration);
sd_notify(0,
"STATUS=Running\n"
"READY=1");
usleep(duration);
usleep_safe(duration);
sd_notify(0,
"STATUS=Reloading\n"
"RELOADING=1");
usleep(duration);
usleep_safe(duration);
sd_notify(0,
"STATUS=Running\n"
"READY=1");
usleep(duration);
usleep_safe(duration);
sd_notify(0,
"STATUS=Quitting\n"
"STOPPING=1");
usleep(duration);
usleep_safe(duration);
return EXIT_SUCCESS;
}

View file

@ -740,7 +740,7 @@ TEST(xopenat_lock) {
* little and assume that's enough time for the child process to get along far enough. It doesn't
* matter if it doesn't get far enough, in that case we just won't trigger the fallback logic in
* xopenat_lock(), but the test will still succeed. */
assert_se(usleep(20 * USEC_PER_MSEC) >= 0);
assert_se(usleep_safe(20 * USEC_PER_MSEC) >= 0);
assert_se(unlinkat(tfd, "abc", AT_REMOVEDIR) >= 0);
fd = safe_close(fd);

View file

@ -30,11 +30,11 @@ static void *fake_pressure_thread(void *p) {
_cleanup_free_ struct fake_pressure_context *c = ASSERT_PTR(p);
_cleanup_close_ int cfd = -EBADF;
usleep(150);
usleep_safe(150);
assert_se(write(c->fifo_fd, &(const char) { 'x' }, 1) == 1);
usleep(150);
usleep_safe(150);
cfd = accept4(c->socket_fd, NULL, NULL, SOCK_CLOEXEC);
assert_se(cfd >= 0);
@ -164,7 +164,7 @@ _noreturn_ static void real_pressure_eat_memory(int pipe_fd) {
log_info("Ate %s in total.", FORMAT_BYTES(ate));
usleep(50 * USEC_PER_MSEC);
usleep_safe(50 * USEC_PER_MSEC);
}
}

View file

@ -638,7 +638,7 @@ TEST(safe_fork) {
if (r == 0) {
/* child */
usleep(100 * USEC_PER_MSEC);
usleep_safe(100 * USEC_PER_MSEC);
_exit(88);
}

View file

@ -3,8 +3,9 @@
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/types.h>
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <float.h>
@ -28,6 +29,18 @@ DISABLE_WARNING_TYPE_LIMITS;
(t)-1 < (t)0 ? ", signed" : ", unsigned", \
alignof(t))
#define check_no_sign(t, size) \
do { \
info_no_sign(t); \
assert_se(sizeof(t) == size); \
} while (false)
#define check(t, size) \
do { \
info(t); \
assert_se(sizeof(t) == size); \
} while (false)
enum Enum {
enum_value,
};
@ -44,6 +57,12 @@ enum BigEnum2 {
int main(void) {
int (*function_pointer)(void);
check_no_sign(dev_t, SIZEOF_DEV_T);
check_no_sign(ino_t, SIZEOF_INO_T);
check_no_sign(rlim_t, SIZEOF_RLIM_T);
check(time_t, SIZEOF_TIME_T);
check(typeof(((struct timex *)0)->freq), SIZEOF_TIMEX_MEMBER);
info_no_sign(typeof(function_pointer));
info_no_sign(void*);
info(char*);
@ -76,7 +95,6 @@ int main(void) {
info(size_t);
info(ssize_t);
info(time_t);
info(usec_t);
#ifdef __GLIBC__
info(__time_t);

View file

@ -29,7 +29,7 @@ int main(int argc, char *argv[]) {
for (i = 0; i < count; i++) {
t = watchdog_runtime_wait();
log_info("Sleeping " USEC_FMT " microseconds...", t);
usleep(t);
usleep_safe(t);
log_info("Pinging...");
r = watchdog_ping();
if (r < 0)

View file

@ -130,7 +130,7 @@ static int run(int argc, char *argv[]) {
r = safe_atou(argv[3], &us);
if (r < 0)
return log_error_errno(r, "Invalid delay '%s': %m", argv[3]);
usleep(us);
usleep_safe(us);
}
assert_se(udev_rules_load(&rules, RESOLVE_NAME_EARLY) == 0);

View file

@ -750,7 +750,7 @@ static int open_drive(Context *c) {
if (++cnt >= 20 || errno != EBUSY)
return log_debug_errno(errno, "Unable to open '%s': %m", arg_node);
(void) usleep(100 * USEC_PER_MSEC + random_u64_range(100 * USEC_PER_MSEC));
(void) usleep_safe(100 * USEC_PER_MSEC + random_u64_range(100 * USEC_PER_MSEC));
}
log_debug("probing: '%s'", arg_node);

View file

@ -1223,7 +1223,7 @@ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_s
if (event->exec_delay_usec > 0) {
log_device_debug(event->dev, "Delaying execution of \"%s\" for %s.",
command, FORMAT_TIMESPAN(event->exec_delay_usec, USEC_PER_SEC));
(void) usleep(event->exec_delay_usec);
(void) usleep_safe(event->exec_delay_usec);
}
log_device_debug(event->dev, "Running command \"%s\"", command);

View file

@ -112,7 +112,7 @@ static int get_current_runlevel(Context *c) {
UINT64_C(240) * USEC_PER_MSEC * n_attempts/64);
log_debug_errno(r, "Failed to get state of %s, retrying after %s: %s",
e->special, FORMAT_TIMESPAN(usec, USEC_PER_MSEC), bus_error_message(&error, r));
(void) usleep(usec);
(void) usleep_safe(usec);
goto reconnect;
}
if (r < 0)