Serenity Operating System
at master 71 lines 1.9 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2022, Alex Major 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <LibCore/ArgsParser.h> 9#include <LibCore/System.h> 10#include <LibMain/Main.h> 11#include <errno.h> 12#include <signal.h> 13#include <stdio.h> 14#include <string.h> 15#include <time.h> 16#include <unistd.h> 17 18static bool volatile g_interrupted; 19static void handle_sigint(int) 20{ 21 g_interrupted = true; 22} 23 24ErrorOr<int> serenity_main(Main::Arguments arguments) 25{ 26 double secs; 27 28 Core::ArgsParser args_parser; 29 args_parser.add_positional_argument(secs, "Number of seconds to sleep for", "num-seconds"); 30 args_parser.parse(arguments); 31 32 struct sigaction sa; 33 memset(&sa, 0, sizeof(struct sigaction)); 34 sa.sa_handler = handle_sigint; 35 sigaction(SIGINT, &sa, nullptr); 36 37 TRY(Core::System::pledge("stdio sigaction")); 38 39 double whole_seconds = static_cast<time_t>(secs); 40 double fraction = secs - whole_seconds; 41 42 timespec requested_sleep { 43 .tv_sec = static_cast<time_t>(whole_seconds), 44 .tv_nsec = static_cast<long>(fraction * (double)1000000000), 45 }; 46 47 timespec remaining_sleep {}; 48 49sleep_again: 50 if (clock_nanosleep(CLOCK_MONOTONIC, 0, &requested_sleep, &remaining_sleep) < 0) { 51 if (errno != EINTR) { 52 perror("clock_nanosleep"); 53 return 1; 54 } 55 } 56 57 if (remaining_sleep.tv_sec || remaining_sleep.tv_nsec) { 58 if (!g_interrupted) { 59 // If not interrupted with SIGINT, just go back to sleep. 60 requested_sleep = remaining_sleep; 61 goto sleep_again; 62 } 63 outln("Sleep interrupted with {}.{} seconds remaining.", remaining_sleep.tv_sec, remaining_sleep.tv_nsec); 64 } 65 66 TRY(Core::System::signal(SIGINT, SIG_DFL)); 67 if (g_interrupted) 68 raise(SIGINT); 69 70 return 0; 71}