/* Arrange for SIGALRM to be delivered in TIMEOUT seconds. This uses
setitimer where available, alarm otherwise.
TIMEOUT should be non-zero. If the timeout value is so small that
it would be rounded to zero, it is rounded to the least legal value
instead (1us for setitimer, 1s for alarm). That ensures that
SIGALRM will be delivered in all cases. */
static void
alarm_set (double timeout)
{
/* Use the old alarm() interface. */
int secs = (int) timeout;
if (secs == 0)
/* Round TIMEOUTs smaller than 1 to 1, not to zero. This is
because alarm(0) means "never deliver the alarm", i.e. "wait
forever", which is not what someone who specifies a 0.5s
timeout would expect. */
secs = 1;
alarm (secs);
}
/* Cancel the alarm set with alarm_set. */
static void
alarm_cancel (void)
{
alarm (0);
}
/* Call FUN(ARG), but don't allow it to run for more than TIMEOUT
seconds. Returns non-zero if the function was interrupted with a
timeout, zero otherwise.
This works by setting up SIGALRM to be delivered in TIMEOUT seconds
using setitimer() or alarm(). The timeout is enforced by
longjumping out of the SIGALRM handler. This has several
advantages compared to the traditional approach of relying on
signals causing system calls to exit with EINTR:
* The callback function is *forcibly* interrupted after the
timeout expires, (almost) regardless of what it was doing and
whether it was in a syscall. For example, a calculation that
takes a long time is interrupted as reliably as an IO
operation.
* It works with both SYSV and BSD signals because it doesn't
depend on the default setting of SA_RESTART.
* It doesn't require special handler setup beyond a simple call
to signal(). (It does use sigsetjmp/siglongjmp, but they're
optional.)
The only downside is that, if FUN allocates internal resources that
are normally freed prior to exit from the functions, they will be
lost in case of timeout. */
/*控制函数指针fun所指向的函数fun(void* arg)运行的时间timeout*/
int
run_with_timeout (double timeout, void (*fun) (void *), void *arg)
{
int saved_errno;
if (timeout == 0)
{
fun (arg);
return 0;
}
signal (SIGALRM, abort_run_with_timeout);
if (SETJMP (run_with_timeout_env) != 0)
{
/* Longjumped out of FUN with a timeout. */
signal (SIGALRM, SIG_IGN);
return 1;
}
alarm_set (timeout); /*set alarm. */
fun (arg);
/* Preserve errno in case alarm() or signal() modifies it. */
saved_errno = errno;
alarm_cancel (); /*don't timed out, fun() has been over. then destroy the alarm. */
signal (SIGALRM, SIG_IGN);
errno = saved_errno;
return 0;
}
void
myfun (void *arg)
{
sleep (10);
}
int
main ()
{
run_with_timeout (10.0, myfun, NULL);
}