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