This patch will make sure that the signal handlers that are saved in the
system call are restored even if the thread got cancelled. Since
spawn_guts uses waitpid when mode is _P_WAIT spawn_guts is a cancellation
point.
Attached is the patch and a new test case.
2003-01-15 Thomas Paff <[EMAIL PROTECTED]>
* syscalls.cc (struct system_cleanup_args): New struct.
(system_cleanup): New function.
(system): Use pthread_cleanup_push and _pop to save and restore
signal handlers and sigprocmask.
diff -urp src.old/winsup/cygwin/syscalls.cc src/winsup/cygwin/syscalls.cc
--- src.old/winsup/cygwin/syscalls.cc 2003-01-14 11:35:51.000000000 +0100
+++ src/winsup/cygwin/syscalls.cc 2003-01-15 09:42:04.000000000 +0100
@@ -1371,6 +1371,21 @@ done:
return res;
}
+struct system_cleanup_args
+{
+ _sig_func_ptr oldint, oldquit;
+ sigset_t old_mask;
+};
+
+static void system_cleanup (void *args)
+{
+ struct system_cleanup_args *cleanup_args = (struct system_cleanup_args *) args;
+
+ signal (SIGINT, cleanup_args->oldint);
+ signal (SIGQUIT, cleanup_args->oldquit);
+ (void) sigprocmask (SIG_SETMASK, &cleanup_args->old_mask, 0);
+}
+
extern "C" int
system (const char *cmdstring)
{
@@ -1382,23 +1397,25 @@ system (const char *cmdstring)
sigframe thisframe (mainthread);
int res;
const char* command[4];
- _sig_func_ptr oldint, oldquit;
- sigset_t child_block, old_mask;
+ struct system_cleanup_args cleanup_args;
+ sigset_t child_block;
if (cmdstring == (const char *) NULL)
return 1;
- oldint = signal (SIGINT, SIG_IGN);
- oldquit = signal (SIGQUIT, SIG_IGN);
+ cleanup_args.oldint = signal (SIGINT, SIG_IGN);
+ cleanup_args.oldquit = signal (SIGQUIT, SIG_IGN);
sigemptyset (&child_block);
sigaddset (&child_block, SIGCHLD);
- (void) sigprocmask (SIG_BLOCK, &child_block, &old_mask);
+ (void) sigprocmask (SIG_BLOCK, &child_block, &cleanup_args.old_mask);
command[0] = "sh";
command[1] = "-c";
command[2] = cmdstring;
command[3] = (const char *) NULL;
+ pthread_cleanup_push (system_cleanup, (void *) &cleanup_args);
+
if ((res = spawnvp (_P_WAIT, "sh", command)) == -1)
{
// when exec fails, return value should be as if shell
@@ -1406,9 +1423,8 @@ system (const char *cmdstring)
res = 127;
}
- signal (SIGINT, oldint);
- signal (SIGQUIT, oldquit);
- (void) sigprocmask (SIG_SETMASK, &old_mask, 0);
+ pthread_cleanup_pop (1);
+
return res;
}
/*
* File: cancel11.c
*
* Test Synopsis: Test if system is a cancellation point.
*
* Test Method (Validation or Falsification):
* -
*
* Requirements Tested:
* -
*
* Features Tested:
* -
*
* Cases Tested:
* -
*
* Description:
* -
*
* Environment:
* -
*
* Input:
* - None.
*
* Output:
* - File name, Line number, and failed expression on failure.
* - No output on success.
*
* Assumptions:
* - have working pthread_create, pthread_cancel, pthread_setcancelstate
* pthread_join
*
* Pass Criteria:
* - Process returns zero exit status.
*
* Fail Criteria:
* - Process returns non-zero exit status.
*/
#include "test.h"
static void *Thread(void *punused)
{
system ("sleep 10");
return NULL;
}
int main (void)
{
void * result;
pthread_t t;
assert (pthread_create (&t, NULL, Thread, NULL) == 0);
sleep (5);
assert (pthread_cancel (t) == 0);
assert (pthread_join (t, &result) == 0);
assert (result == PTHREAD_CANCELED);
return 0;
}