]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
time-util: introduce usleep_safe() 27843/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 31 May 2023 23:31:25 +0000 (08:31 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 22 Jun 2023 06:33:56 +0000 (15:33 +0900)
We use usec_t for storing time value, which is 64bit.
However, usleep() takes useconds_t that is (typically?) 32bit.
Also, usleep() may only support the range [0, 1000000].

This introduce usleep_safe() which takes usec_t.

20 files changed:
src/basic/efivars.c
src/basic/terminal-util.c
src/basic/time-util.h
src/cgtop/cgtop.c
src/home/homework.c
src/libsystemd/sd-bus/test-bus-watch-bind.c
src/libsystemd/sd-event/test-event.c
src/resolve/test-resolved-stream.c
src/shared/dissect-image.c
src/shared/loop-util.c
src/test/test-barrier.c
src/test/test-daemon.c
src/test/test-fs-util.c
src/test/test-mempress.c
src/test/test-process-util.c
src/test/test-watchdog.c
src/test/udev-rule-runner.c
src/udev/cdrom_id/cdrom_id.c
src/udev/udev-event.c
src/update-utmp/update-utmp.c

index e7ece805d4cae64471e1cd0872ffb8faf61b7756..77dc2acd8b19df6495d356448af6812dd2daaf1b 100644 (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))
index 796c262acfd1501544aa54ed27cd227bf8dfd8ff..31fed16682bad1721fbc38a364ee816e29f578d3 100644 (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++;
         }
 
index b49137d5c3feb33062faab2ad13c183890396160..e55d23e32dfac1bc5a810f1bfac3e6f90c255603 100644 (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 */
index 987643f661724f63459f76ea8eeeb242671a7cc7..6bbe0445a036dcdf9dc171001ee8c60a1be5d723 100644 (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)
index f8e333bb979030bd00137959522a7169a9b454c6..9773bfa7a329fb464918d866cb89ef0561de8bb6 100644 (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;
index a504437ac50f6249f9d7983f22d58423f1f9a815..d6938a7f095dc994d8cfd1591d8772f389e1bd4c 100644 (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");
 
index 50b6a793ce2088b344aedc305169ead17319cff4..2a69560e52690bb008de391f90b4b12e5bb36998 100644 (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);
index ae851f67f0ca2bc33902ba9ff268d373e09772a1..a52a225624ec86d7d66298549ee7f20bae4b0ad8 100644 (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);
 
index a1e4d333c88c061e67e88a006284ba92abf57c3f..52a1b559803507b82ba27d31a3da28c73f349a12 100644 (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. */
index 3e51c93ede44ecc4c67c406e305cf36a4c543284..09841ae26ae827515c91e665a57838390e45ac30 100644 (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);
                 }
         }
 
index b255dba068235472c67153355966d80dfd1e5cff..0538de9949debb96281feaac35218ed68868ef0f 100644 (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));
index e6dd29a0a7a378c56b69d3ad98d829065da0aead..faf64767785b4956379143d813f57d28f961e9c2 100644 (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;
 }
index 873052e24d4a3be6d9ed859315f0f2969255dc42..1beba916a4d1697e561968b463e9d42c84912d56 100644 (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);
index 510c7327156428b7024673e0ef3a0ca28cabe7cc..e03f9b533b84f9095c33dbe0a0bb1368511564e8 100644 (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);
         }
 }
 
index e915207e8c777d7fc3ef36ef3d103395d00a20d9..c8ab506dc3e9b92b38c9e47a881894cc7d08bc08 100644 (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);
         }
index 2b6d5b5b6195f4e679bf71a8e03cda737d19bc16..a0b3af2aba1b67b57d57ce22defbc5d42a03bbc7 100644 (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)
index f7ba143325a1c4e53d7f0a994088e124d0a606d4..fe854a3d2e6d46c11c03bd0b37ebe7ce9f11ea04 100644 (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);
index 5b5fbd0109aa2b5d8215ca829c556bf67a3d5909..050f858719c2f70f2a0be66c4178afeea09e86bf 100644 (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);
index b3cdb32a63fd10785d74794b65ce615e5b0dc830..296c0e344c1a7fadef7beeb5f4cc1df9e77c9e14 100644 (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);
index 5651ec11dacf9900fcebef702020d91b7e7a3a06..4ee935e0441335914f6fb2c871543c75b7fde718 100644 (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)