[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [LTP] fatal signal handling




Ok, more analysis of the signal handling issue has induced me to eat my
words.  The top of tst_sig.c has the following:

#ifndef CRAY
#define _BSD_SIGNALS	1	/* Specify that we are using BSD signal interface
*/
#endif

So, on Irix we do get the BSD symantics.  This means there is a
recursion problem.

But, looking at it again, there isn't a problem.  By default for
sigaction() (and signal() also by consequence), the signal being handled
is blocked from being received while in its handler.  A signal raised
while in its own handler isn't received until it exits its own handler. 
Given that our cleanup function eventually leads to an exit(), there is
no recursion.  The fatal flaw in that snippit I sent yesterday is that
there should be an exit() at the end of the handler (in order to mimick
our situation).

It is the case that signals other that the one being handled can cause
another handler instance.  That new handler instance will then most
likely exit.  It will presumably raise its own signal, which will be
blocked until the handler exits.  We know that exit() is called before
it gets a chance to return.

Even though the case of using the default handler and cleanup function
does not require any differentiation between BSD and SYSV semantics,
there is still the case of the alternative handler.  Because the handler
is specified by the test programmer, some expectation of whether BSD or
SYSV semantics are in use is necessary.  For this reason, I've created
my own knock-off of signal()-like function called setup_signal() to be
used by tst_sig().  It uses sigaction() and should be usable on Linux,
Irix, and even FreeBSD without any funny '_BSD_SIGNALS' or
'_XOPEN_SOURCE' definitions.

I also found that def_handler() automatically sets itself to the default
handler (as if using SYSV semantics) with signal().  This must be a
relic of the early days of the Unicos->Irix port.  Yes, there is much
history in this code and that "DATE STARTED" in the header is true.  I
removed this unnecessary code.

Here's the patch:

--- tst_sig.c	2000/08/30 18:43:38	1.2
+++ tst_sig.c	2000/09/06 02:55:30
@@ -67,10 +67,6 @@
 

***************************************************************************/
 
-#ifndef CRAY
-#define _BSD_SIGNALS	1	/* Specify that we are using BSD signal
interface */
-#endif
-
 #include <errno.h>
 #include <string.h>
 #include <signal.h>
@@ -82,6 +78,7 @@
 
 extern int errno;
 static void def_handler();		/* default signal handler */
+static void (*setup_signal( int, void (*)(int)))(int);
 

/****************************************************************************
  * tst_sig() : set-up to catch unexpected signals.  fork_flag is set to
NOFORK
@@ -158,7 +155,7 @@
 		        continue;
 
 	        default:
-		    if (signal(sig, handler) == SIG_ERR) {
+		    if (setup_signal(sig, handler) == SIG_ERR) {
 		        (void) sprintf(mesg,
 			    "signal() failed for signal %d. error:%d %s.",
 			    sig, errno, strerror(errno));
@@ -185,24 +182,11 @@
 static void
 def_handler(int sig)
 {
-	char mesg[MAXMESG];		/* holds tst_res message */
-
-	/* first reset trap for this signal (except SIGCLD - its weird) */
-	if ((sig != SIGCLD) && (sig != SIGSTOP) && (sig != SIGCONT)) {
-		if (signal(sig, def_handler) == SIG_ERR) {
-			(void) sprintf(mesg,
-				"def_handler: signal() failed for signal %d. error:%d %s.",
-				sig, errno, strerror(errno));
-			tst_resm(TWARN, mesg);
-		}
-	}
 
-	(void) sprintf(mesg, "Unexpected signal %d received.", sig);
-
 	/*
          * Break remaining test cases, do any cleanup, then exit
 	 */
-	tst_brkm(TBROK, 0, mesg);
+	tst_brkm(TBROK, 0, "Unexpected signal %d received.", sig);
 
 	/* now cleanup and exit */
 	if (T_cleanup) {
@@ -211,3 +195,25 @@
 
 	tst_exit();
 }
+
+/*
+ * setup_signal - A function like signal(), but we have
+ *                control over its personality.
+ */
+static void (*setup_signal( int sig, void (*handler)(int)))(int)
+{ 
+  struct sigaction my_act,old_act;
+  int ret;
+
+  my_act.sa_handler = handler;
+  my_act.sa_flags = SA_RESTART;
+  sigemptyset(&my_act.sa_mask);
+
+  ret = sigaction(sig, &my_act, &old_act);
+
+  if ( ret == 0 )
+    return( old_act.sa_handler );
+  else
+    return( SIG_ERR );
+}
+

Thoughts?
--aaron

Egor Duda wrote:
> 
> Hi!
> 
>   currently,  tests  in  ltp  can possibly catch fatal signals such as
> SIGSEGV  recursively.  imagine  rmdir()  is faulty and causes SIGSEGV.
> tst_sig  sets  cleanup()  as  handler  for  SIGSEGV, but cleanup calls
> rmdir() itself. possible solutions are
> 
> 1. using sigaction() instead of signal()
> 2. checking "reentering" in handler
> 
> which way is preferable?
> 
> Egor.            mailto:deo@logos-m.ru ICQ 5165414 FidoNet 2:5020/496.19

-- 
Aaron Laffin
Silicon Graphics, Inc. OS Test Development
Email: alaffin@sgi.com Voice: 651-683-5756
USA/MN/CRP/F5233/SSBU