// SPDX-License-Identifier: GPL-2.0-only1/* Timeout API for single-threaded programs that use blocking2* syscalls (read/write/send/recv/connect/accept).3*4* Copyright (C) 2017 Red Hat, Inc.5*6* Author: Stefan Hajnoczi <[email protected]>7*/89/* Use the following pattern:10*11* timeout_begin(TIMEOUT);12* do {13* ret = accept(...);14* timeout_check("accept");15* } while (ret < 0 && ret == EINTR);16* timeout_end();17*/1819#include <stdlib.h>20#include <stdbool.h>21#include <unistd.h>22#include <stdio.h>23#include <time.h>24#include "timeout.h"2526static volatile bool timeout;2728/* SIGALRM handler function. Do not use sleep(2), alarm(2), or29* setitimer(2) while using this API - they may interfere with each30* other.31*32* If you need to sleep, please use timeout_sleep() provided by this API.33*/34void sigalrm(int signo)35{36timeout = true;37}3839/* Start a timeout. Call timeout_check() to verify that the timeout hasn't40* expired. timeout_end() must be called to stop the timeout. Timeouts cannot41* be nested.42*/43void timeout_begin(unsigned int seconds)44{45alarm(seconds);46}4748/* Exit with an error message if the timeout has expired */49void timeout_check(const char *operation)50{51if (timeout) {52fprintf(stderr, "%s timed out\n", operation);53exit(EXIT_FAILURE);54}55}5657/* Stop a timeout */58void timeout_end(void)59{60alarm(0);61timeout = false;62}6364/* Sleep in a timeout section.65*66* nanosleep(2) can be used with this API since POSIX.1 explicitly67* specifies that it does not interact with signals.68*/69int timeout_usleep(useconds_t usec)70{71struct timespec ts = {72.tv_sec = usec / 1000000,73.tv_nsec = (usec % 1000000) * 1000,74};7576return nanosleep(&ts, NULL);77}787980