From: bernhardheld Date: Tue, 16 Oct 2001 20:02:06 +0000 (+0000) Subject: timeout for uCsim X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=812f282b8a8564f80dfcb25fa1fc9bb29a0b7f73;p=fw%2Fsdcc timeout for uCsim git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@1411 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- diff --git a/ChangeLog b/ChangeLog index c2d57d24..865e94e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2001-10-16 Bernhard Held + + * support/regression/port/mcs51/spec.mk: add timeout for uCsim + + * support/regression/port/mcs51/timeout.c: add timeout for uCsim + 2001-10-13 Michael Hope * src/SDCCmain.c (linkEdit): Added support for passing a legacy command line through the processor. diff --git a/support/regression/ports/mcs51/spec.mk b/support/regression/ports/mcs51/spec.mk index 8485e3ec..1c76314e 100644 --- a/support/regression/ports/mcs51/spec.mk +++ b/support/regression/ports/mcs51/spec.mk @@ -1,5 +1,6 @@ # Port specification for the mcs51 port running with uCsim +# path to uCsim S51 = ../../sim/ucsim/s51.src/s51 SDCCFLAGS += --lesspedantic -DREENTRANT=reentrant --stack-after-data @@ -7,7 +8,6 @@ SDCCFLAGS += --lesspedantic -DREENTRANT=reentrant --stack-after-data OBJEXT = .rel EXEEXT = .ihx -# Needs parts of gbdk-lib, namely the internal mul/div/mod functions. EXTRAS = fwk/lib/testfwk$(OBJEXT) ports/$(PORT)/support$(OBJEXT) # Rule to link into .ihx @@ -19,8 +19,10 @@ EXTRAS = fwk/lib/testfwk$(OBJEXT) ports/$(PORT)/support$(OBJEXT) %$(OBJEXT): %.c $(SDCC) $(SDCCFLAGS) -c $< -# PENDING: Path to sdcc-extra -%.out: %$(EXEEXT) +# run simulator with 5 seconds timeout +%.out: %$(EXEEXT) ports/$(PORT)/timeout mkdir -p `dirname $@` - $(S51) -t32 -S in=$(shell tty),out=$@ $< < ports/mcs51/uCsim.cmd >/dev/null 2>&1 + -ports/$(PORT)/timeout 5 $(S51) -t32 -S in=/dev/null,out=$@ $< < ports/mcs51/uCsim.cmd >/dev/null 2>&1 || \ + echo -e --- FAIL: \"timeout, simulation killed\" in $(<:.ihx=.c)"\n"--- Summary: 1/1/1: timeout >> $@ -grep -n FAIL $@ /dev/null || true + diff --git a/support/regression/ports/mcs51/timeout.c b/support/regression/ports/mcs51/timeout.c new file mode 100644 index 00000000..4b6b5e25 --- /dev/null +++ b/support/regression/ports/mcs51/timeout.c @@ -0,0 +1,140 @@ +/*------------------------------------------------------------------------- + timeout.c - source file for running ucSim within the regression tests + + Written By - Bernhard Held . bernhard@bernhardheld.de (2001) + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + In other words, you are welcome to use, share and improve this program. + You are forbidden to forbid anyone else to use, share and improve + what you give them. Help stamp out software-hoarding! +-------------------------------------------------------------------------*/ + +#define PROGNAME "timeout" + +#define USAGE PROGNAME " : 1.00\n" \ + "Usage : " PROGNAME " timeout_in_seconds filename [arguments]\n" \ + " ´filename´ is executed, the arguments are passed to ´filename´.\n" \ + " When ´filename´exits before the timeout expires, the\n" \ + " exit-status of ´filename´ is returned.\n" \ + " When the timeout expires before ´filename´ exits, ´filename´\n" \ + " will be killed and an exit-status of 1 is returned.\n" + +/* First the program tries to limit the maximum CPU-time to the timeout-value. + Then the child is run with execvp(). + + It's not possible to limit the CPU-time under Cygwin (V1.3.3). If setrlimit (RLIMIT_CPU, rlp) + fails, the program will fork() and run the child with execvp(). The fork/exec pair is slow on + Cygwin, but what else can we do? The parent sleeps until: + - a signal shows the child´s exitus + The exit status of the child is returned. + - the timeout elapses + The child will be killed. +*/ + +#include +#include +#include +#include +#include + +/* Get the status from all child processes that have terminated, without ever waiting. + This function is designed to be a handler for SIGCHLD, the signal that indicates + that at least one child process has terminated. + http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_23.html#SEC401 +*/ + +#ifndef WAIT_ANY + #define WAIT_ANY -1 +#endif + +void +sigchld_handler (int signum) +{ + int pid; + int status; + int exit_status = 0; + struct rlimit rl; + + /* remove limitation for CPU time */ + if (getrlimit (RLIMIT_CPU, &rl) == 0) + { + rl.rlim_cur = rl.rlim_max; + setrlimit (RLIMIT_CPU, &rl); + } + + while (1) + { + pid = waitpid (WAIT_ANY, &status, WNOHANG); + if (WEXITSTATUS (status)) + exit_status = 1; // WEXITSTATUS(status); + /* pid == -1: no children */ + /* pid == 0: no children to be noticed */ + if (pid <= 0) + break; + } + exit (exit_status); +} + +int +main (int argc, char * const *argv) +{ + /* if getrlimit() / setrlimit() succeed, then no fork is neeeded */ + int flagNoFork = 0; + long timeout; + pid_t pid_child; + struct rlimit rl; + + if (argc < 3) + { + fprintf (stderr, USAGE); + return 1; + } + timeout = atol (argv[1]); + if (timeout == 0) + { + fprintf (stderr, "Error parameter " PROGNAME ": must be a non-zero dezimal value\n"); + return 1; + } + + /* try to use getrlimit() / setrlimit() for RLIMIT_CPU */ + /* to limit the CPU-time */ + if (getrlimit (RLIMIT_CPU, &rl) == 0) + { + rl.rlim_cur = timeout; + if (setrlimit (RLIMIT_CPU, &rl) == 0) + flagNoFork = 1; + } + + if (flagNoFork) + /* the CPU-time is limited: simple execvp */ + return execvp (argv[2], argv + 2); + else + { + /* do it the hard way: fork/exec */ + signal (SIGCHLD, sigchld_handler); + pid_child = fork(); + if (pid_child == 0) + return execvp (argv[2], argv + 2); + else + { + /* this timeout is hopefully aborted by a SIGCHLD */ + sleep (timeout); + fprintf (stderr, PROGNAME ": timeout, killing child %s\n", argv[2]); + kill (pid_child, SIGTERM); + return 1; /* Error */ + } + } +}