xref: /linux/tools/testing/vsock/timeout.c (revision be709d48329a500621d2a05835283150ae137b45)
1 /* Timeout API for single-threaded programs that use blocking
2  * syscalls (read/write/send/recv/connect/accept).
3  *
4  * Copyright (C) 2017 Red Hat, Inc.
5  *
6  * Author: Stefan Hajnoczi <stefanha@redhat.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; version 2
11  * of the License.
12  */
13 
14 /* Use the following pattern:
15  *
16  *   timeout_begin(TIMEOUT);
17  *   do {
18  *       ret = accept(...);
19  *       timeout_check("accept");
20  *   } while (ret < 0 && ret == EINTR);
21  *   timeout_end();
22  */
23 
24 #include <stdlib.h>
25 #include <stdbool.h>
26 #include <unistd.h>
27 #include <stdio.h>
28 #include "timeout.h"
29 
30 static volatile bool timeout;
31 
32 /* SIGALRM handler function.  Do not use sleep(2), alarm(2), or
33  * setitimer(2) while using this API - they may interfere with each
34  * other.
35  */
36 void sigalrm(int signo)
37 {
38 	timeout = true;
39 }
40 
41 /* Start a timeout.  Call timeout_check() to verify that the timeout hasn't
42  * expired.  timeout_end() must be called to stop the timeout.  Timeouts cannot
43  * be nested.
44  */
45 void timeout_begin(unsigned int seconds)
46 {
47 	alarm(seconds);
48 }
49 
50 /* Exit with an error message if the timeout has expired */
51 void timeout_check(const char *operation)
52 {
53 	if (timeout) {
54 		fprintf(stderr, "%s timed out\n", operation);
55 		exit(EXIT_FAILURE);
56 	}
57 }
58 
59 /* Stop a timeout */
60 void timeout_end(void)
61 {
62 	alarm(0);
63 	timeout = false;
64 }
65