/* * %CopyrightBegin% * * Copyright Ericsson AB 1997-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved online at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * %CopyrightEnd% */ /* timeout.c * * todo: use posix timers (timer_create etc) instead of setitimer. * */ #if !defined(__WIN32__) && !defined(VXWORKS) /* FIXME: well, at least I can compile now... */ #include "eidef.h" #include <stdio.h> #include <stdlib.h> #include <setjmp.h> #include <signal.h> #if TIME_WITH_SYS_TIME # include <sys/time.h> # include <time.h> #else # if HAVE_SYS_TIME_H # include <sys/time.h> # else # include <time.h> # endif #endif #include "erl_interface.h" #include "erl_timeout.h" typedef struct jmp_s { jmp_buf jmpbuf; struct itimerval timerinfo; void *siginfo; struct jmp_s *next; } *jmp_t; static jmp_t push(jmp_t j); static jmp_t pop(void); static void timeout_handler(int dummy); jmp_buf *timeout_setup(int ms) { struct itimerval t; jmp_t j; void *s; #ifdef DEBUG fprintf(stderr,"timeout setup\n"); #endif s=signal(SIGALRM,timeout_handler); /* set the timer */ t.it_interval.tv_sec = 0; t.it_interval.tv_usec = 0; t.it_value.tv_sec = ms / 1000; t.it_value.tv_usec = (ms % 1000) * 1000; /* get a jump buffer and save it */ j = erl_malloc(sizeof(*j)); j->siginfo = s; push(j); setitimer(ITIMER_REAL,&t,&(j->timerinfo)); return &(j->jmpbuf); } int timeout_cancel(void) { jmp_t j; #ifdef DEBUG fprintf(stderr,"timeout cancel\n"); #endif /* retrieve the jump buffer */ j=pop(); /* restore the timer and signal disposition */ setitimer(ITIMER_REAL,&(j->timerinfo),NULL); signal(SIGALRM,j->siginfo); free(j); return 0; } void timeout_handler(int dummy) { jmp_t j; #ifdef DEBUG fprintf(stderr,"timeout handler\n"); #endif /* retrieve the jump buffer */ j=pop(); /* restore the timer and signal disposition */ setitimer(ITIMER_REAL,&(j->timerinfo),NULL); signal(SIGALRM,j->siginfo); free(j); longjmp(j->jmpbuf,JMPVAL); return; /* not reached */ } /* a simple stack for saving the jump buffer allows us to pass a * variable between functions that don't call each other, in a way * that will survive the longjmp(). */ /* FIXME problem for threaded ? */ static jmp_t jmp_head=NULL; #ifdef DEBUG static int depth = 0; static int maxdepth = 0; #endif static jmp_t push(jmp_t j) { j->next = jmp_head; jmp_head = j; #ifdef DEBUG depth++; if (depth > maxdepth) maxdepth = depth; #endif return j; } static jmp_t pop(void) { jmp_t j = jmp_head; if (j) jmp_head = j->next; #ifdef DEBUG depth--; #endif return j; } #endif /* platform */