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 "timeout.h" 25 26 static volatile bool timeout; 27 28 /* SIGALRM handler function. Do not use sleep(2), alarm(2), or 29 * setitimer(2) while using this API - they may interfere with each 30 * other. 31 */ 32 void sigalrm(int signo) 33 { 34 timeout = true; 35 } 36 37 /* Start a timeout. Call timeout_check() to verify that the timeout hasn't 38 * expired. timeout_end() must be called to stop the timeout. Timeouts cannot 39 * be nested. 40 */ 41 void timeout_begin(unsigned int seconds) 42 { 43 alarm(seconds); 44 } 45 46 /* Exit with an error message if the timeout has expired */ 47 void timeout_check(const char *operation) 48 { 49 if (timeout) { 50 fprintf(stderr, "%s timed out\n", operation); 51 exit(EXIT_FAILURE); 52 } 53 } 54 55 /* Stop a timeout */ 56 void timeout_end(void) 57 { 58 alarm(0); 59 timeout = false; 60 } 61