]> git.gag.com Git - fw/sdcc/commitdiff
timeout for uCsim
authorbernhardheld <bernhardheld@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Tue, 16 Oct 2001 20:02:06 +0000 (20:02 +0000)
committerbernhardheld <bernhardheld@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Tue, 16 Oct 2001 20:02:06 +0000 (20:02 +0000)
git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@1411 4a8a32a2-be11-0410-ad9d-d568d2c75423

ChangeLog
support/regression/ports/mcs51/spec.mk
support/regression/ports/mcs51/timeout.c [new file with mode: 0644]

index c2d57d24729f0dc38a8ab5f080457b0218955b98..865e94e7320ff2fd647fe234b39145d25a536fbb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2001-10-16  Bernhard Held  <bernhard@bernhardheld.de>
+
+       * 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  <michaelh@juju.net.nz>
 
        * src/SDCCmain.c (linkEdit): Added support for passing a legacy command line through the processor.
index 8485e3ecde76c631e90f83479b42fb8c0c976ae4..1c76314e3951983709024c90cd8480920ca3856f 100644 (file)
@@ -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 (file)
index 0000000..4b6b5e2
--- /dev/null
@@ -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 <signal.h>
+#include <stdio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+/* 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 */
+        }
+    }
+}