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  */
sigalrm(int signo)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  */
timeout_begin(unsigned int seconds)41 void timeout_begin(unsigned int seconds)
42 {
43 	alarm(seconds);
44 }
45 
46 /* Exit with an error message if the timeout has expired */
timeout_check(const char * operation)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 */
timeout_end(void)56 void timeout_end(void)
57 {
58 	alarm(0);
59 	timeout = false;
60 }
61