1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Timeout API for single-threaded programs that use blocking 3 * syscalls (read/write/send/recv/connect/accept). 4 * 5 * Copyright (C) 2017 Red Hat, Inc. 6 * 7 * Author: Stefan Hajnoczi <stefanha@redhat.com> 8 */ 9 10 /* Use the following pattern: 11 * 12 * timeout_begin(TIMEOUT); 13 * do { 14 * ret = accept(...); 15 * timeout_check("accept"); 16 * } while (ret < 0 && ret == EINTR); 17 * timeout_end(); 18 */ 19 20 #include <stdlib.h> 21 #include <stdbool.h> 22 #include <unistd.h> 23 #include <stdio.h> 24 #include <time.h> 25 #include "timeout.h" 26 27 static volatile bool timeout; 28 29 /* SIGALRM handler function. Do not use sleep(2), alarm(2), or 30 * setitimer(2) while using this API - they may interfere with each 31 * other. 32 * 33 * If you need to sleep, please use timeout_sleep() provided by this API. 34 */ 35 void sigalrm(int signo) 36 { 37 timeout = true; 38 } 39 40 /* Start a timeout. Call timeout_check() to verify that the timeout hasn't 41 * expired. timeout_end() must be called to stop the timeout. Timeouts cannot 42 * be nested. 43 */ 44 void timeout_begin(unsigned int seconds) 45 { 46 alarm(seconds); 47 } 48 49 /* Exit with an error message if the timeout has expired */ 50 void timeout_check(const char *operation) 51 { 52 if (timeout) { 53 fprintf(stderr, "%s timed out\n", operation); 54 exit(EXIT_FAILURE); 55 } 56 } 57 58 /* Stop a timeout */ 59 void timeout_end(void) 60 { 61 alarm(0); 62 timeout = false; 63 } 64 65 /* Sleep in a timeout section. 66 * 67 * nanosleep(2) can be used with this API since POSIX.1 explicitly 68 * specifies that it does not interact with signals. 69 */ 70 int timeout_usleep(useconds_t usec) 71 { 72 struct timespec ts = { 73 .tv_sec = usec / 1000000, 74 .tv_nsec = (usec % 1000000) * 1000, 75 }; 76 77 return nanosleep(&ts, NULL); 78 } 79