This is the mail archive of the libc-alpha@sourceware.cygnus.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

test/demo patch for pthread manager


Hello

This is a test/demo patch to glibc-linuxthreads-2.1.3. It requires
kernel 2.3.99
- particularly for (CLONE_PARENT and (2) prctl).

1. It makes manager a parent of all threads including main.
    This is achieved through clone2 (see further)

2. Thread creation and deletion is performed by the thread
who calls pthread_create/join thus the request is not transferred to
manager

3. Manager distributes signals across all threads (including main), so
the manager pid
serves as the pid of the process.

4. The original manager is preserved for backward compatibility.
   The decision whether to use new manager is done currently in
init_rtsigs() (assumption
that if the RT signals are present then CLONE_PARENT and (2) prctl is
also supported).


Possible enhancements that are not implemented:
1. The fork() in pthread lib. should do CLONE_PARENT, so the new process
will become a child of
the thread manager, and not the child of the thread who calls fork() -
thus preserve
parent/child relationship across processes (because the manager pid
serves as process pid).

2. exec could be transferred to thread manager and executed there after
killing all threads.
This way the parent-child relationship (for example shell - pthread
program that execs)
will be preserved.

3. The meaning of getpid() is the pid of manager and getppid() is the
parent of the manager
for all threads.


about clone2
----------
The clone2 is standard clone except that it switches stacks (in user
space, no kernel
patches required). It is currently implemented only for i386
architecture. For example:

void main()
{
    clone2(f, stack, flags, NULL);
}

The main with its original stack will run in child process after
executing clone2.
The f() will run with supplied stack in parent process (the process that
calls main).


Any ideas, comments or feedback would be appreciated.

regards
Pavel

diff -ruN linuxthreads.orig/Makefile linuxthreads/Makefile
--- linuxthreads.orig/Makefile	Wed Nov  3 01:09:36 1999
+++ linuxthreads/Makefile	Mon Mar 20 09:41:00 2000
@@ -35,7 +35,7 @@
 libpthread-routines := attr cancel condvar join manager mutex ptfork \
 		       ptlongjmp pthread signals specific errno lockfile \
 		       semaphore spinlock wrapsyscall rwlock pt-machine \
-		       oldsemaphore events
+		       oldsemaphore events clone2
 
 vpath %.c Examples
 tests = ex1 ex2 ex3 ex4 ex5 ex6
diff -ruN linuxthreads.orig/clone2.S linuxthreads/clone2.S
--- linuxthreads.orig/clone2.S	Thu Jan  1 01:00:00 1970
+++ linuxthreads/clone2.S	Sun Mar 26 16:33:51 2000
@@ -0,0 +1,99 @@
+/* Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Richard Henderson (rth@tamu.edu)
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* clone2() is even more special than clone() as it mucks with stacks
+   and invokes a function in the right context after its all over.  */
+/*
+ * The main difference between clone and clone2 is that the function and
+ * supplied stack is run in parent thread and the parent function
+ * (main()) with original stack is moved to the child process.
+ */
+#include <sysdep.h>
+#define _ERRNO_H	1
+#include <bits/errno.h>
+#include <asm-syntax.h>
+
+/* int clone2(int (*fn)(void *arg), void *child_stack, int flags, void *arg); */
+
+        .text
+ENTRY(__clone2)
+	/* Sanity check arguments.  */
+	movl	$-EINVAL,%eax
+	movl	4(%esp),%ecx		/* no NULL function pointers */
+#ifdef PIC
+	jecxz	SYSCALL_ERROR_LABEL
+#else
+	testl	%ecx,%ecx
+	jz	SYSCALL_ERROR_LABEL
+#endif
+	movl	8(%esp),%ecx		/* no NULL stack pointers */
+#ifdef PIC
+	jecxz	SYSCALL_ERROR_LABEL
+#else
+	testl	%ecx,%ecx
+	jz	SYSCALL_ERROR_LABEL
+#endif
+
+	/* Insert the argument onto the new stack.  */
+	subl	$8,%ecx
+	movl	16(%esp),%eax		/* no negative argument counts */
+	movl	%eax,4(%ecx)
+
+	/* Save the function pointer as the zeroth argument.
+	   It will be popped off in the child in the ebx frobbing below.  */
+	movl	4(%esp),%eax
+	movl	%eax,0(%ecx)
+
+	/* Do the system call */
+	pushl	%ebx
+	movl	16(%esp),%ebx
+	movl	$SYS_ify(clone),%eax
+	/* switch stacks */
+	movl	%ecx, %edx
+	movl	%esp, %ecx
+	movl	%edx, %esp
+	/* call clone */
+	int	$0x80
+	popl	%ebx
+
+	test	%eax,%eax
+	jl	SYSCALL_ERROR_LABEL
+	jnz	thread_start
+	
+L(pseudo_end):
+	ret
+
+thread_start:
+	subl	%ebp,%ebp	/* terminate the stack frame */
+#if 0
+	pushl	%eax		/* push child pid to the stack */
+#endif
+	call	*%ebx
+#ifdef PIC
+	call	L(here)
+L(here):
+	popl	%ebx
+	addl	$_GLOBAL_OFFSET_TABLE_+[.-L(here)], %ebx
+#endif
+	pushl	%eax
+	call	JUMPTARGET (_exit)
+	
+PSEUDO_END (__clone2)
+
+weak_alias (__clone2, clone2)
diff -ruN linuxthreads.orig/internals.h linuxthreads/internals.h
--- linuxthreads.orig/internals.h	Fri Jan 21 02:40:19 2000
+++ linuxthreads/internals.h	Sun Mar 26 16:27:53 2000
@@ -42,6 +42,10 @@
 # define THREAD_SETMEM_NC(descr, member, value) descr->member = (value)
 #endif
 
+#ifndef CLONE_PARENT
+#define CLONE_PARENT	0x00008000
+#endif
+
 /* Arguments passed to thread creation routine */
 
 struct pthread_start_args {
@@ -163,6 +167,8 @@
   pthread_readlock_info *p_readlock_list;  /* List of readlock info structs */
   pthread_readlock_info *p_readlock_free;  /* Free list of structs */
   int p_untracked_readlock_count;	/* Readlocks not tracked by list */
+	
+  sigset_t p_sigmask;
   /* New elements must be added at the end.  */
 } __attribute__ ((aligned(32))); /* We need to align the structure so that
 				    doubles are aligned properly.  This is 8
@@ -240,6 +246,23 @@
 
 extern char *__pthread_initial_thread_bos;
 
+/*
+ * To avoid deadlock the locks must be taken with this order:
+ * 
+ * 1. __sigmask_lock
+ * 2. __thrlive_lock
+ * 3. handle/descriptor thread lock p_lock
+ */
+
+/* lock used to protect pending signals */
+extern struct _pthread_fastlock __sigmask_lock;
+
+/* lock used to protect live threads list */
+extern struct _pthread_fastlock __thrlive_lock;
+
+/* manager is parent of all threads including main */
+extern int __pthread_new_manager;
+
 /* Indicate whether at least one thread has a user-defined stack (if 1),
    or all threads have stacks supplied by LinuxThreads (if 0). */
 
@@ -263,6 +286,9 @@
 
 extern int __pthread_exit_requested, __pthread_exit_code;
 
+/* installs manager sighandlers that distribute and record signals */
+extern void install_manager_sighandlers(void);
+
 /* Set to 1 by gdb if we're debugging */
 
 extern volatile int __pthread_threads_debug;
@@ -390,6 +416,7 @@
 void __fresetlockfiles(void);
 void __pthread_manager_adjust_prio(int thread_prio);
 void __pthread_set_own_extricate_if(pthread_descr self, pthread_extricate_if *peif);
+void __pthread_free(pthread_descr th);
 
 extern int __pthread_attr_setguardsize __P ((pthread_attr_t *__attr,
 					     size_t __guardsize));
diff -ruN linuxthreads.orig/join.c linuxthreads/join.c
--- linuxthreads.orig/join.c	Thu Jan  6 02:45:15 2000
+++ linuxthreads/join.c	Sun Mar 26 18:09:46 2000
@@ -28,6 +28,10 @@
   pthread_descr joining;
   struct pthread_request request;
 
+  /* no more signals from thread manager */
+  __pthread_lock(&__sigmask_lock, self);
+  sigfillset(&self->p_sigmask);
+  __pthread_unlock(&__sigmask_lock);
   /* Reset the cancellation flag to avoid looping if the cleanup handlers
      contain cancellation points */
   THREAD_SETMEM(self, p_canceled, 0);
@@ -67,8 +71,10 @@
   if (joining != NULL) restart(joining);
   /* If this is the initial thread, block until all threads have terminated.
      If another thread calls exit, we'll be terminated from our signal
-     handler. */
-  if (self == __pthread_main_thread && __pthread_manager_request >= 0) {
+     handler. 
+     new manager handles initial thread the same way as other threads
+   */
+  if (!__pthread_new_manager && self == __pthread_main_thread && __pthread_manager_request >= 0) {
     request.req_thread = self;
     request.req_kind = REQ_MAIN_THREAD_EXIT;
     __libc_write(__pthread_manager_request, (char *)&request, sizeof(request));
@@ -130,11 +136,12 @@
   if (! th->p_terminated) {
     /* Register extrication interface */
     __pthread_set_own_extricate_if(self, &extr); 
-    if (!(THREAD_GETMEM(self, p_canceled)
+    if ((THREAD_GETMEM(self, p_canceled)
 	&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
-      th->p_joining = self;
-    else
       already_canceled = 1;
+    else
+      th->p_joining = self;
+	  
     __pthread_unlock(&handle->h_lock);
 
     if (already_canceled) {
@@ -153,9 +160,23 @@
       pthread_exit(PTHREAD_CANCELED);
     }
     __pthread_lock(&handle->h_lock, self);
+    if (invalid_handle(handle, thread_id)) {
+      __pthread_unlock(&handle->h_lock);
+      return ESRCH;
+    }
   }
   /* Get return value */
   if (thread_return != NULL) *thread_return = th->p_retval;
+	
+  if (__pthread_new_manager) {
+    if (th->p_exited) {
+      __pthread_free(th);
+    } else {
+      th->p_detached = 1;
+      __pthread_unlock(&handle->h_lock);
+    }
+    return 0;
+  }
   __pthread_unlock(&handle->h_lock);
   /* Send notification to thread manager */
   if (__pthread_manager_request >= 0) {
@@ -193,6 +214,14 @@
   }
   /* Mark as detached */
   th->p_detached = 1;
+	
+  if (__pthread_new_manager) {
+    if (th->p_terminated && th->p_exited)
+      __pthread_free(th);
+    else
+      __pthread_unlock(&handle->h_lock);
+    return 0;
+  }
   terminated = th->p_terminated;
   __pthread_unlock(&handle->h_lock);
   /* If already terminated, notify thread manager to reclaim resources */
diff -ruN linuxthreads.orig/manager.c linuxthreads/manager.c
--- linuxthreads.orig/manager.c	Fri Jan 21 02:40:19 2000
+++ linuxthreads/manager.c	Tue Mar 28 10:10:12 2000
@@ -26,6 +26,7 @@
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/wait.h>           /* for waitpid macros */
+#include <sys/prctl.h>
 
 #include "pthread.h"
 #include "internals.h"
@@ -33,7 +34,10 @@
 #include "restart.h"
 #include "semaphore.h"
 
+
 /* Array of active threads. Entry 0 is reserved for the initial thread. */
+/* all locks in the array must be initialized - LOCK_INITIALIZER is {0,0}
+   so it is done */
 struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] =
 { { LOCK_INITIALIZER, &__pthread_initial_thread, 0},
   { LOCK_INITIALIZER, &__pthread_manager_thread, 0}, /* All NULLs */ };
@@ -45,7 +49,17 @@
    or if all threads have stacks supplied by LinuxThreads (if 0). */
 int __pthread_nonstandard_stacks;
 
-/* Number of active entries in __pthread_handles (used by gdb) */
+/* lock used to protect pthread_threads_counter and __pthread_handles_num */
+static struct _pthread_fastlock __pthread_counters_lock = LOCK_INITIALIZER;
+
+/* Counter used to generate unique thread identifier.
+   Thread identifier is pthread_threads_counter + segment. 
+   protected by __pthread_counters_lock */
+
+static pthread_t pthread_threads_counter = 0;
+
+/* Number of active entries in __pthread_handles (used by gdb) 
+   protected by __pthread_counters_lock */
 volatile int __pthread_handles_num = 2;
 
 /* Whether to use debugger additional actions for thread creation
@@ -58,6 +72,9 @@
 /* Pointer to thread descriptor with last event.  */
 volatile pthread_descr __pthread_last_event;
 
+/* lock used to protect live threads list */
+struct _pthread_fastlock __thrlive_lock = LOCK_INITIALIZER;
+
 /* Mapping from stack segment to thread descriptor. */
 /* Stack segment numbers are also indices into the __pthread_handles array. */
 /* Stack segment number 0 is reserved for the initial thread. */
@@ -77,16 +94,12 @@
 
 static int main_thread_exiting = 0;
 
-/* Counter used to generate unique thread identifier.
-   Thread identifier is pthread_threads_counter + segment. */
-
-static pthread_t pthread_threads_counter = 0;
 
 /* Forward declarations */
-
 static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
-                                 void * (*start_routine)(void *), void *arg,
-                                 sigset_t *mask, int father_pid,
+				 void * (*start_routine)(void *), void *arg,
+				 sigset_t * mask, int father_pid,
+				 pthread_descr self,
 				 int report_events,
 				 td_thr_events_t *event_maskp);
 static void pthread_handle_free(pthread_t th_id);
@@ -100,7 +113,7 @@
 {
   int reqfd = (int) (long int) arg;
   struct pollfd ufd;
-  sigset_t mask;
+  sigset_t mask, sig_empty_mask, old_mask;
   int n;
   struct pthread_request request;
 
@@ -115,23 +128,37 @@
   sigfillset(&mask);
   sigdelset(&mask, __pthread_sig_cancel); /* for thread termination */
   sigdelset(&mask, SIGTRAP);            /* for debugging purposes */
+  /* block all signals except cancel/debugging now */
   sigprocmask(SIG_SETMASK, &mask, NULL);
+  if (__pthread_new_manager) {
+    /* sigmask used when waiting for event/signal */
+    sigemptyset(&sig_empty_mask);
+    install_manager_sighandlers(); /* install handlers that will distribute signals to threads */
+  }
   /* Raise our priority to match that of main thread */
   __pthread_manager_adjust_prio(__pthread_main_thread->p_priority);
   /* Synchronize debugging of the thread manager */
-  n = __libc_read(reqfd, (char *)&request, sizeof(request));
-  ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG);
+  if (__pthread_threads_debug) {
+    n = __libc_read(reqfd, (char *)&request, sizeof(request));
+    ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG);
+  }
   ufd.fd = reqfd;
   ufd.events = POLLIN;
   /* Enter server loop */
   while(1) {
+    if (__pthread_new_manager)
+      sigprocmask(SIG_SETMASK, &sig_empty_mask, &old_mask);
     n = __poll(&ufd, 1, 2000);
-
-    /* Check for termination of the main thread */
-    if (getppid() == 1) {
-      pthread_kill_all_threads(SIGKILL, 0);
-      _exit(0);
+    if (__pthread_new_manager)
+      sigprocmask(SIG_SETMASK, &old_mask, NULL);
+    else {
+      /* Check for termination of the main thread */
+      if (getppid() == 1) {
+        pthread_kill_all_threads(SIGKILL, 0);
+        _exit(0);
+      }
     }
+	  
     /* Check for dead children */
     if (terminated_children) {
       terminated_children = 0;
@@ -142,7 +169,9 @@
       n = __libc_read(reqfd, (char *)&request, sizeof(request));
       ASSERT(n == sizeof(request));
       switch(request.req_kind) {
+      /* old manager only */
       case REQ_CREATE:
+	ASSERT(!__pthread_new_manager);
         request.req_thread->p_retcode =
           pthread_handle_create((pthread_t *) &request.req_thread->p_retval,
                                 request.req_args.create.attr,
@@ -150,18 +179,23 @@
                                 request.req_args.create.arg,
                                 &request.req_args.create.mask,
                                 request.req_thread->p_pid,
+				&__pthread_manager_thread,
 				request.req_thread->p_report_events,
 				&request.req_thread->p_eventbuf.eventmask);
         restart(request.req_thread);
         break;
+      /* old manager only */
       case REQ_FREE:
+	ASSERT(!__pthread_new_manager);
 	pthread_handle_free(request.req_args.free.thread_id);
         break;
       case REQ_PROCESS_EXIT:
         pthread_handle_exit(request.req_thread,
                             request.req_args.exit.code);
         break;
+      /* old manager only */
       case REQ_MAIN_THREAD_EXIT:
+	ASSERT(!__pthread_new_manager);
         main_thread_exiting = 1;
         if (__pthread_main_thread->p_nextlive == __pthread_main_thread) {
           restart(__pthread_main_thread);
@@ -177,6 +211,8 @@
 	if (__pthread_threads_debug && __pthread_sig_debug > 0)
 	  raise(__pthread_sig_debug);
         break;
+      default:
+	ASSERT(0);      
       }
     }
   }
@@ -211,16 +247,22 @@
   /* Make sure our pid field is initialized, just in case we get there
      before our father has initialized it. */
   THREAD_SETMEM(self, p_pid, __getpid());
-  /* Initial signal mask is that of the creating thread. (Otherwise,
-     we'd just inherit the mask of the thread manager.) */
-  sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL);
+  if (__pthread_new_manager) {
+    prctl(PR_SET_PDEATHSIG, SIGKILL);
+    if (getppid() == 1)
+  	kill(__getpid(), SIGKILL);
+  } else {
+    /* Initial signal mask is that of the creating thread. (Otherwise,
+       we'd just inherit the mask of the thread manager.) */
+    sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL);
+  }
   /* Set the scheduling policy and priority for the new thread, if needed */
-  if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0)
+  if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0) {
     /* Explicit scheduling attributes were provided: apply them */
     __sched_setscheduler(THREAD_GETMEM(self, p_pid),
 			 THREAD_GETMEM(self, p_start_args.schedpolicy),
                          &self->p_start_args.schedparam);
-  else if (__pthread_manager_thread.p_priority > 0)
+  } else if (!__pthread_new_manager && __pthread_manager_thread.p_priority > 0)
     /* Default scheduling required, but thread manager runs in realtime
        scheduling: switch new thread to SCHED_OTHER policy */
     {
@@ -335,20 +377,24 @@
   return 0;
 }
 
+/* mask and father_pid sets only old manager */
 static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
 				 void * (*start_routine)(void *), void *arg,
 				 sigset_t * mask, int father_pid,
+				 pthread_descr self,
 				 int report_events,
 				 td_thr_events_t *event_maskp)
 {
   size_t sseg;
   int pid;
+  pthread_handle ha;
   pthread_descr new_thread;
   char * new_thread_bottom;
   pthread_t new_thread_id;
   char *guardaddr = NULL;
   size_t guardsize = 0;
   int pagesize = __getpagesize();
+  int clone_ex_flags = 0;
 
   /* First check whether we have to change the policy and if yes, whether
      we can  do this.  Normally this should be done by examining the
@@ -363,14 +409,26 @@
 	return EAGAIN;
       if (__pthread_handles[sseg].h_descr != NULL)
 	continue;
-      if (pthread_allocate_stack(attr, thread_segment(sseg), pagesize,
+      ha = &__pthread_handles[sseg];
+      if (__pthread_trylock(&ha->h_lock) == 0) {
+        if (ha->h_descr == NULL && pthread_allocate_stack(attr, thread_segment(sseg), pagesize,
                                  &new_thread, &new_thread_bottom,
-                                 &guardaddr, &guardsize) == 0)
-        break;
+                                 &guardaddr, &guardsize) == 0) {
+	  /* set the descriptor to -1L in order to prevent seeing NULL */
+	  ha->h_descr = (pthread_descr) -1L;
+	  /* now the descriptor is locked */
+          break;
+	}
+        __pthread_unlock(&ha->h_lock);
+      }
     }
+  /* the handle is locked */
+  __pthread_lock(&__pthread_counters_lock, self);
   __pthread_handles_num++;
   /* Allocate new thread identifier */
   pthread_threads_counter += PTHREAD_THREADS_MAX;
+  __pthread_unlock(&__pthread_counters_lock);
+	
   new_thread_id = sseg + pthread_threads_counter;
   /* Initialize the thread descriptor.  Elements which have to be
      initialized to zero already have this value.  */
@@ -384,8 +442,10 @@
   new_thread->p_guardsize = guardsize;
   new_thread->p_self = new_thread;
   new_thread->p_nr = sseg;
+  new_thread->p_pid = 0;
+  new_thread->p_sigmask = self->p_sigmask;
   /* Initialize the thread handle */
-  __pthread_init_lock(&__pthread_handles[sseg].h_lock);
+  /* the h_lock member is globaly initialized */
   __pthread_handles[sseg].h_descr = new_thread;
   __pthread_handles[sseg].h_bottom = new_thread_bottom;
   /* Determine scheduling parameters for the thread */
@@ -399,23 +459,45 @@
       new_thread->p_start_args.schedpolicy = attr->__schedpolicy;
       memcpy (&new_thread->p_start_args.schedparam, &attr->__schedparam,
 	      sizeof (struct sched_param));
+      new_thread->p_priority =
+        new_thread->p_start_args.schedparam.sched_priority;
       break;
     case PTHREAD_INHERIT_SCHED:
-      new_thread->p_start_args.schedpolicy = __sched_getscheduler(father_pid);
-      __sched_getparam(father_pid, &new_thread->p_start_args.schedparam);
+      if (__pthread_new_manager)
+        new_thread->p_priority = self->p_priority;
+      else {
+        new_thread->p_start_args.schedpolicy = __sched_getscheduler(father_pid);
+       __sched_getparam(father_pid, &new_thread->p_start_args.schedparam);
+       new_thread->p_priority = new_thread->p_start_args.schedparam.sched_priority;
+      }
       break;
     }
-    new_thread->p_priority =
-      new_thread->p_start_args.schedparam.sched_priority;
   }
   /* Finish setting up arguments to pthread_start_thread */
   new_thread->p_start_args.start_routine = start_routine;
   new_thread->p_start_args.arg = arg;
-  new_thread->p_start_args.mask = *mask;
+  if (mask) 
+    new_thread->p_start_args.mask = *mask;
+  /* now unlock the handle */
+  __pthread_unlock(&ha->h_lock);
+	
   /* Raise priority of thread manager if needed */
   __pthread_manager_adjust_prio(new_thread->p_priority);
   /* Do the cloning.  We have to use two different functions depending
      on whether we are debugging or not.  */
+	
+  /* Insert new thread in doubly linked list of active threads
+     the p_pid in descriptor is 0 currently */
+  __pthread_lock(&__thrlive_lock, self);
+  new_thread->p_prevlive = __pthread_main_thread;
+  new_thread->p_nextlive = __pthread_main_thread->p_nextlive;
+  __pthread_main_thread->p_nextlive->p_prevlive = new_thread;
+  __pthread_main_thread->p_nextlive = new_thread;
+  __pthread_unlock(&__thrlive_lock);
+
+  if (__pthread_new_manager)
+    clone_ex_flags = CLONE_PARENT;
+	
   pid = 0;     /* Note that the thread never can have PID zero.  */
   if (report_events)
     {
@@ -432,7 +514,7 @@
 
 	  /* We have to report this event.  */
 	  pid = __clone(pthread_start_thread_event, (void **) new_thread,
-		        CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+		        CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | clone_ex_flags |
 		        __pthread_sig_cancel, new_thread);
 	  if (pid != -1)
 	    {
@@ -459,10 +541,15 @@
     }
   if (pid == 0)
     pid = __clone(pthread_start_thread, (void **) new_thread,
-		  CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+		  CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | clone_ex_flags |
 		  __pthread_sig_cancel, new_thread);
   /* Check if cloning succeeded */
   if (pid == -1) {
+    /* remove from list of active threads */
+    __pthread_lock(&__thrlive_lock, self);
+    new_thread->p_nextlive->p_prevlive = new_thread->p_prevlive;
+    new_thread->p_prevlive->p_nextlive = new_thread->p_nextlive;
+    __pthread_unlock(&__thrlive_lock);
     /* Free the stack if we allocated it */
     if (attr == NULL || !attr->__stackaddr_set)
       {
@@ -471,29 +558,91 @@
 	munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
 	       INITIAL_STACK_SIZE);
       }
+    __pthread_lock(&__pthread_handles[sseg].h_lock, self);
     __pthread_handles[sseg].h_descr = NULL;
     __pthread_handles[sseg].h_bottom = NULL;
+    __pthread_unlock(&__pthread_handles[sseg].h_lock);
+    __pthread_lock(&__pthread_counters_lock, self);
     __pthread_handles_num--;
+    __pthread_unlock(&__pthread_counters_lock);
     return errno;
   }
-  /* Insert new thread in doubly linked list of active threads */
-  new_thread->p_prevlive = __pthread_main_thread;
-  new_thread->p_nextlive = __pthread_main_thread->p_nextlive;
-  __pthread_main_thread->p_nextlive->p_prevlive = new_thread;
-  __pthread_main_thread->p_nextlive = new_thread;
   /* Set pid field of the new thread, in case we get there before the
      child starts. */
-  new_thread->p_pid = pid;
+  THREAD_SETMEM(new_thread, p_pid, pid);
   /* We're all set */
   *thread = new_thread_id;
   return 0;
 }
 
+/* Thread creation */
+
+int __pthread_create_2_1(pthread_t *thread, const pthread_attr_t *attr,
+			 void * (*start_routine)(void *), void *arg)
+{
+  pthread_descr self = thread_self();
+  struct pthread_request request;
+
+  if (__pthread_manager_request < 0) {
+    if (__pthread_initialize_manager() < 0) return EAGAIN;
+  }
+  if (__pthread_new_manager)
+	  return pthread_handle_create(thread, attr, start_routine, arg, NULL, 0, self,
+				       self->p_report_events, &self->p_eventbuf.eventmask);
+  else {
+    request.req_thread = self;
+    request.req_kind = REQ_CREATE;
+    request.req_args.create.attr = attr;
+    request.req_args.create.fn = start_routine;
+    request.req_args.create.arg = arg;
+    sigprocmask(SIG_SETMASK, (const sigset_t *) NULL,
+                &request.req_args.create.mask);
+    __libc_write(__pthread_manager_request, (char *) &request, sizeof(request));
+    suspend(self);
+    if (THREAD_GETMEM(self, p_retcode) == 0)
+      *thread = (pthread_t) THREAD_GETMEM(self, p_retval);
+    return THREAD_GETMEM(self, p_retcode);
+  }
+}
+
+#if defined HAVE_ELF && defined PIC && defined DO_VERSIONING
+default_symbol_version (__pthread_create_2_1, pthread_create, GLIBC_2.1);
+
+int __pthread_create_2_0(pthread_t *thread, const pthread_attr_t *attr,
+			 void * (*start_routine)(void *), void *arg)
+{
+  /* The ATTR attribute is not really of type `pthread_attr_t *'.  It has
+     the old size and access to the new members might crash the program.
+     We convert the struct now.  */
+  pthread_attr_t new_attr;
+
+  if (attr != NULL)
+    {
+      size_t ps = __getpagesize ();
+
+      memcpy (&new_attr, attr,
+	      (size_t) &(((pthread_attr_t*)NULL)->__guardsize));
+      new_attr.__guardsize = ps;
+      new_attr.__stackaddr_set = 0;
+      new_attr.__stackaddr = NULL;
+      new_attr.__stacksize = STACK_SIZE - ps;
+      attr = &new_attr;
+    }
+  return __pthread_create_2_1 (thread, attr, start_routine, arg);
+}
+symbol_version (__pthread_create_2_0, pthread_create, GLIBC_2.0);
+#else
+strong_alias (__pthread_create_2_1, pthread_create)
+#endif
 
 /* Try to free the resources of a thread when requested by pthread_join
    or pthread_detach on a terminated thread. */
 
-static void pthread_free(pthread_descr th)
+/*
+ * the handle must be locked when calling this function for new manager
+ * the function will unlock it
+ */
+void __pthread_free(pthread_descr th)
 {
   pthread_handle handle;
   pthread_readlock_info *iter, *next;
@@ -501,7 +650,8 @@
   ASSERT(th->p_exited);
   /* Make the handle invalid */
   handle =  thread_handle(th->p_tid);
-  __pthread_lock(&handle->h_lock, NULL);
+  if (!__pthread_new_manager)
+    __pthread_lock(&handle->h_lock, NULL);
   handle->h_descr = NULL;
   handle->h_bottom = (char *)(-1L);
   __pthread_unlock(&handle->h_lock);
@@ -509,7 +659,9 @@
   FREE_THREAD_SELF(th, th->p_nr);
 #endif
   /* One fewer threads in __pthread_handles */
+  __pthread_lock(&__pthread_counters_lock, NULL);
   __pthread_handles_num--;
+  __pthread_unlock(&__pthread_counters_lock);
 
   /* Destroy read lock list, and list of free read lock structures.
      If the former is not empty, it means the thread exited while
@@ -528,7 +680,10 @@
     }
 
   /* If initial thread, nothing to free */
-  if (th == &__pthread_initial_thread) return;
+  if (th == &__pthread_initial_thread) {
+	  th->p_pid = 0;
+	  return;
+  }
   if (!th->p_userstack)
     {
       /* Free the stack and thread descriptor area */
@@ -542,9 +697,12 @@
 
 static void pthread_exited(pid_t pid)
 {
+  static int main_thread_exited = 0;	
   pthread_descr th;
   int detached;
+  int found = 0;
   /* Find thread with that pid */
+  __pthread_lock(&__thrlive_lock, NULL);
   for (th = __pthread_main_thread->p_nextlive;
        th != __pthread_main_thread;
        th = th->p_nextlive) {
@@ -552,6 +710,8 @@
       /* Remove thread from list of active threads */
       th->p_nextlive->p_prevlive = th->p_prevlive;
       th->p_prevlive->p_nextlive = th->p_nextlive;
+      __pthread_unlock(&__thrlive_lock);
+      found = 1;
       /* Mark thread as exited, and if detached, free its resources */
       __pthread_lock(th->p_lock, NULL);
       th->p_exited = 1;
@@ -574,33 +734,72 @@
 	      __linuxthreads_reap_event();
 	    }
 	}
-      detached = th->p_detached;
-      __pthread_unlock(th->p_lock);
-      if (detached)
-	pthread_free(th);
+      if (__pthread_new_manager) {
+        if (th->p_detached) {
+  	  __pthread_free(th);
+        } else
+          __pthread_unlock(th->p_lock);
+      } else {
+        detached = th->p_detached;
+        __pthread_unlock(th->p_lock);
+        if (detached)
+  	  __pthread_free(th);
+      }
       break;
     }
   }
+  if (!found)
+	__pthread_unlock(&__thrlive_lock);
+
+  if (__pthread_new_manager) {
+    /* ok, special handling for main */
+    if (__pthread_main_thread->p_pid == pid) {
+      __pthread_lock(__pthread_main_thread->p_lock, NULL);
+        if (th->p_detached)
+	  __pthread_free(th);
+        else
+          __pthread_unlock(th->p_lock);
+      main_thread_exited = 1;
+    }
+    /* If all threads have exited then terminate ourselves. */
+    if (main_thread_exited &&
+        __pthread_main_thread->p_nextlive == __pthread_main_thread) {
+      _exit(0);
+    }
+  } else {
   /* If all threads have exited and the main thread is pending on a
      pthread_exit, wake up the main thread and terminate ourselves. */
-  if (main_thread_exiting &&
-      __pthread_main_thread->p_nextlive == __pthread_main_thread) {
-    restart(__pthread_main_thread);
-    _exit(0);
+    if (main_thread_exiting &&
+       __pthread_main_thread->p_nextlive == __pthread_main_thread) {
+     restart(__pthread_main_thread);
+     _exit(0);
+    }
   }
 }
 
 static void pthread_reap_children(void)
 {
   pid_t pid;
-  int status;
-
+  int status, signo;
+  sigset_t mask;
+  struct sigaction sa;
+	
   while ((pid = __libc_waitpid(-1, &status, WNOHANG | __WCLONE)) > 0) {
     pthread_exited(pid);
     if (WIFSIGNALED(status)) {
       /* If a thread died due to a signal, send the same signal to
          all other threads, including the main thread. */
-      pthread_kill_all_threads(WTERMSIG(status), 1);
+      signo = WTERMSIG(status);
+      pthread_kill_all_threads(signo, 1);
+      /* die with the same signal */
+      sa.sa_handler = SIG_DFL;
+      sa.sa_flags = 0;
+      sigemptyset(&sa.sa_mask);
+      __sigaction(signo, &sa, NULL);
+      kill(getpid(), signo);
+      sigfillset(&mask);
+      sigdelset(&mask, signo);
+      sigprocmask(SIG_SETMASK, &mask, NULL);
       _exit(0);
     }
   }
@@ -624,7 +823,7 @@
   th = handle->h_descr;
   if (th->p_exited) {
     __pthread_unlock(&handle->h_lock);
-    pthread_free(th);
+    __pthread_free(th);
   } else {
     /* The Unix process of the thread is still running.
        Mark the thread as detached so that the thread manager will
@@ -639,11 +838,16 @@
 static void pthread_kill_all_threads(int sig, int main_thread_also)
 {
   pthread_descr th;
+  int pid;
+
+  __pthread_lock(&__thrlive_lock, NULL);
   for (th = __pthread_main_thread->p_nextlive;
        th != __pthread_main_thread;
        th = th->p_nextlive) {
-    kill(th->p_pid, sig);
+	  if ((pid = th->p_pid) > 0)
+	    kill(pid, sig);
   }
+  __pthread_unlock(&__thrlive_lock);
   if (main_thread_also) {
     kill(__pthread_main_thread->p_pid, sig);
   }
@@ -660,6 +864,7 @@
      thread, but excluding the thread from which the exit request originated
      (that thread must complete the exit, e.g. calling atexit functions
      and flushing stdio buffers). */
+  __pthread_lock(&__thrlive_lock, NULL);
   for (th = issuing_thread->p_nextlive;
        th != issuing_thread;
        th = th->p_nextlive) {
@@ -672,8 +877,14 @@
        th = th->p_nextlive) {
     waitpid(th->p_pid, NULL, __WCLONE);
   }
+  __pthread_unlock(&__thrlive_lock);
   restart(issuing_thread);
-  _exit(0);
+  if (__pthread_new_manager) {
+    /* thread manager acumulates all times */
+    waitpid(issuing_thread->p_pid, NULL, __WCLONE);
+    _exit(__pthread_exit_code);
+  } else
+    _exit(0);
 }
 
 /* Handler for __pthread_sig_cancel in thread manager thread */
diff -ruN linuxthreads.orig/ptexec.c linuxthreads/ptexec.c
--- linuxthreads.orig/ptexec.c	Thu Jan  1 01:00:00 1970
+++ linuxthreads/ptexec.c	Thu Mar 23 11:56:20 2000
@@ -0,0 +1,4 @@
+int __execve(const char *filename, char *const argv[], char *const envp[])
+{
+	return 0;
+}
diff -ruN linuxthreads.orig/pthread.c linuxthreads/pthread.c
--- linuxthreads.orig/pthread.c	Fri Jan 21 02:40:19 2000
+++ linuxthreads/pthread.c	Tue Mar 28 10:10:25 2000
@@ -23,6 +23,7 @@
 #include <fcntl.h>
 #include <sys/wait.h>
 #include <sys/resource.h>
+#include <sys/prctl.h>
 #include "pthread.h"
 #include "internals.h"
 #include "spinlock.h"
@@ -174,8 +175,13 @@
 extern int _errno;
 extern int _h_errno;
 
+/* switch for new manager */
+int __pthread_new_manager = 0;
+
 /* Forward declarations */
 
+int __clone2(int (*fn)(void *arg), void *child_stack, int flags, void *arg);
+
 static void pthread_exit_process(int retcode, void *arg);
 #ifndef __i386__
 static void pthread_handle_sigcancel(int sig);
@@ -242,6 +248,8 @@
 #endif
 
       current_rtmax = __SIGRTMAX;
+      /* switch to use manager as parent of all */
+      __pthread_new_manager = 1;
     }
 
   rtsigs_initialized = 1;
@@ -298,9 +306,34 @@
 
 static void pthread_initialize(void) __attribute__((constructor));
 
-static void pthread_initialize(void)
+static void install_common_sighandlers(void)
 {
   struct sigaction sa;
+#ifndef __i386__
+  sa.sa_handler = pthread_handle_sigrestart;
+#else
+  sa.sa_handler = (__sighandler_t) pthread_handle_sigrestart;
+#endif
+  sigemptyset(&sa.sa_mask);
+  sa.sa_flags = 0;
+  __sigaction(__pthread_sig_restart, &sa, NULL);
+#ifndef __i386__
+  sa.sa_handler = pthread_handle_sigcancel;
+#else
+  sa.sa_handler = (__sighandler_t) pthread_handle_sigcancel;
+#endif
+  sa.sa_flags = 0;
+  __sigaction(__pthread_sig_cancel, &sa, NULL);
+  if (__pthread_sig_debug > 0) {
+    sa.sa_handler = pthread_handle_sigdebug;
+    sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    __sigaction(__pthread_sig_debug, &sa, NULL);
+  }
+}
+
+static void pthread_initialize(void)
+{
   sigset_t mask;
   struct rlimit limit;
   int max_stack;
@@ -342,27 +375,7 @@
   /* Setup signal handlers for the initial thread.
      Since signal handlers are shared between threads, these settings
      will be inherited by all other threads. */
-#ifndef __i386__
-  sa.sa_handler = pthread_handle_sigrestart;
-#else
-  sa.sa_handler = (__sighandler_t) pthread_handle_sigrestart;
-#endif
-  sigemptyset(&sa.sa_mask);
-  sa.sa_flags = 0;
-  __sigaction(__pthread_sig_restart, &sa, NULL);
-#ifndef __i386__
-  sa.sa_handler = pthread_handle_sigcancel;
-#else
-  sa.sa_handler = (__sighandler_t) pthread_handle_sigcancel;
-#endif
-  sa.sa_flags = 0;
-  __sigaction(__pthread_sig_cancel, &sa, NULL);
-  if (__pthread_sig_debug > 0) {
-    sa.sa_handler = pthread_handle_sigdebug;
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = 0;
-    __sigaction(__pthread_sig_debug, &sa, NULL);
-  }
+  install_common_sighandlers();
   /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */
   sigemptyset(&mask);
   sigaddset(&mask, __pthread_sig_restart);
@@ -397,6 +410,13 @@
     free(__pthread_manager_thread_bos);
     return -1;
   }
+
+  /* get the pid of new manager now */
+  if (__pthread_new_manager) {
+    __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1;
+    __pthread_manager_thread.p_pid = getpid();
+  }
+	
   /* Start the thread manager */
   pid = 0;
   if (__pthread_initial_thread.p_report_events)
@@ -410,11 +430,18 @@
 		   | __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx]))
 	  != 0)
 	{
-	  pid = __clone(__pthread_manager_event,
+	  if (__pthread_new_manager)
+  	    pid = __clone2(__pthread_manager_event,
+			(void **) __pthread_manager_thread_tos,
+			CLONE_VM | CLONE_FS | CLONE_FILES | __pthread_sig_cancel,
+			(void *)(long)manager_pipe[0]);
+	  else
+  	    pid = __clone(__pthread_manager_event,
 			(void **) __pthread_manager_thread_tos,
 			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
 			(void *)(long)manager_pipe[0]);
 
+
 	  if (pid != -1)
 	    {
 	      /* Now fill in the information about the new thread in
@@ -425,8 +452,10 @@
 		&__pthread_manager_thread;
 	      __pthread_manager_thread.p_eventbuf.eventnum = TD_CREATE;
 	      __pthread_last_event = &__pthread_manager_thread;
-	      __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1;
-	      __pthread_manager_thread.p_pid = pid;
+	      if (!__pthread_new_manager) {
+	        __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1;
+	        __pthread_manager_thread.p_pid = pid;
+	      }
 
 	      /* Now call the function which signals the event.  */
 	      __linuxthreads_create_event ();
@@ -436,21 +465,46 @@
 	    }
 	}
     }
-
-  if (pid == 0)
-    pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos,
+  /* 
+   * do it with clone2 and without CLONE_SIGHAND because manager
+   * has its own signal handlers
+   */
+  if (pid == 0) {
+    if (__pthread_new_manager) {
+      pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_tos,
+		  CLONE_VM | CLONE_FS | CLONE_FILES | __pthread_sig_cancel,
+		  (void *)(long)manager_pipe[0]);
+    } else {
+      pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos,
 		  CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
 		  (void *)(long)manager_pipe[0]);
+      __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1;
+      __pthread_manager_thread.p_pid = pid;
+    }
+  }
+
   if (pid == -1) {
     free(__pthread_manager_thread_bos);
     __libc_close(manager_pipe[0]);
     __libc_close(manager_pipe[1]);
     return -1;
   }
+  if (__pthread_new_manager) {
+    /*
+     * now we are runing with new pid and without signal handlers (child)
+     */
+    prctl(PR_SET_PDEATHSIG, SIGKILL);
+    if (getppid() == 1)
+	kill(getpid(), SIGKILL);
+    /* clone2 changed the pid of main */
+    __pthread_initial_thread.p_pid = __getpid();
+    sigprocmask(SIG_SETMASK, NULL, &__pthread_initial_thread.p_sigmask);
+    install_common_sighandlers();
+  }
   __pthread_manager_request = manager_pipe[1]; /* writing end */
   __pthread_manager_reader = manager_pipe[0]; /* reading end */
-  __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1;
-  __pthread_manager_thread.p_pid = pid;
+
+
   /* Make gdb aware of new thread manager */
   if (__pthread_threads_debug && __pthread_sig_debug > 0)
     {
@@ -458,66 +512,13 @@
       /* We suspend ourself and gdb will wake us up when it is
 	 ready to handle us. */
       __pthread_wait_for_restart_signal(thread_self());
+      /* Synchronize debugging of the thread manager */
+      request.req_kind = REQ_DEBUG;
+      __libc_write(__pthread_manager_request, (char *) &request, sizeof(request));
     }
-  /* Synchronize debugging of the thread manager */
-  request.req_kind = REQ_DEBUG;
-  __libc_write(__pthread_manager_request, (char *) &request, sizeof(request));
   return 0;
 }
 
-/* Thread creation */
-
-int __pthread_create_2_1(pthread_t *thread, const pthread_attr_t *attr,
-			 void * (*start_routine)(void *), void *arg)
-{
-  pthread_descr self = thread_self();
-  struct pthread_request request;
-  if (__pthread_manager_request < 0) {
-    if (__pthread_initialize_manager() < 0) return EAGAIN;
-  }
-  request.req_thread = self;
-  request.req_kind = REQ_CREATE;
-  request.req_args.create.attr = attr;
-  request.req_args.create.fn = start_routine;
-  request.req_args.create.arg = arg;
-  sigprocmask(SIG_SETMASK, (const sigset_t *) NULL,
-              &request.req_args.create.mask);
-  __libc_write(__pthread_manager_request, (char *) &request, sizeof(request));
-  suspend(self);
-  if (THREAD_GETMEM(self, p_retcode) == 0)
-    *thread = (pthread_t) THREAD_GETMEM(self, p_retval);
-  return THREAD_GETMEM(self, p_retcode);
-}
-
-#if defined HAVE_ELF && defined PIC && defined DO_VERSIONING
-default_symbol_version (__pthread_create_2_1, pthread_create, GLIBC_2.1);
-
-int __pthread_create_2_0(pthread_t *thread, const pthread_attr_t *attr,
-			 void * (*start_routine)(void *), void *arg)
-{
-  /* The ATTR attribute is not really of type `pthread_attr_t *'.  It has
-     the old size and access to the new members might crash the program.
-     We convert the struct now.  */
-  pthread_attr_t new_attr;
-
-  if (attr != NULL)
-    {
-      size_t ps = __getpagesize ();
-
-      memcpy (&new_attr, attr,
-	      (size_t) &(((pthread_attr_t*)NULL)->__guardsize));
-      new_attr.__guardsize = ps;
-      new_attr.__stackaddr_set = 0;
-      new_attr.__stackaddr = NULL;
-      new_attr.__stacksize = STACK_SIZE - ps;
-      attr = &new_attr;
-    }
-  return __pthread_create_2_1 (thread, attr, start_routine, arg);
-}
-symbol_version (__pthread_create_2_0, pthread_create, GLIBC_2.0);
-#else
-strong_alias (__pthread_create_2_1, pthread_create)
-#endif
 
 /* Simple operations on thread identifiers */
 
@@ -608,11 +609,15 @@
     request.req_args.exit.code = retcode;
     __libc_write(__pthread_manager_request,
 		 (char *) &request, sizeof(request));
+    /* wait before manager cancels all threads except this */
     suspend(self);
-    /* Main thread should accumulate times for thread manager and its
-       children, so that timings for main thread account for all threads. */
-    if (self == __pthread_main_thread)
-      waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
+
+    if (!__pthread_new_manager) {
+      /* Main thread should accumulate times for thread manager and its
+         children, so that timings for main thread account for all threads. */
+      if (self == __pthread_main_thread)
+	waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
+    }
   }
 }
 
@@ -661,10 +666,12 @@
       return;
     }
   if (__pthread_exit_requested) {
-    /* Main thread should accumulate times for thread manager and its
-       children, so that timings for main thread account for all threads. */
-    if (self == __pthread_main_thread)
-      waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
+    if (!__pthread_new_manager) {
+      /* Main thread should accumulate times for thread manager and its
+         children, so that timings for main thread account for all threads. */
+      if (self == __pthread_main_thread)
+        waitpid(__pthread_manager_thread.p_pid, NULL, __WCLONE);
+    }
     _exit(__pthread_exit_code);
   }
   if (THREAD_GETMEM(self, p_canceled)
@@ -813,7 +820,6 @@
    be a wasteful wrapper for __pthread_wait_for_restart_signal */
 
 /* Debugging aid */
-
 #ifdef DEBUG
 #include <stdarg.h>
 
diff -ruN linuxthreads.orig/signals.c linuxthreads/signals.c
--- linuxthreads.orig/signals.c	Mon Oct  4 21:50:04 1999
+++ linuxthreads/signals.c	Sun Mar 26 15:27:19 2000
@@ -22,26 +22,68 @@
 #include <ucontext.h>
 #include <sigcontextinfo.h>
 
+/*
+ * lock used to protect all signal masks in thread descriptors
+ * and signal delivery
+ */
+struct _pthread_fastlock __sigmask_lock = LOCK_INITIALIZER;
+static int __sig_pending[NSIG];
+
+static void match_pending(pid_t pid, sigset_t *p_sigmask)
+{
+  int i;
+	
+  for (i = 1; i < NSIG; i++) {
+    if (__sig_pending[i] > 0 && !__sigismember(p_sigmask, i)) {
+      for ( ; __sig_pending[i] > 0; --__sig_pending[i])
+        kill(pid, i);
+    }
+  }
+}
+
 int pthread_sigmask(int how, const sigset_t * newmask, sigset_t * oldmask)
 {
+  int i;
   sigset_t mask;
-
+  pthread_descr self = thread_self();
+	
   if (newmask != NULL) {
     mask = *newmask;
+    if (__pthread_new_manager)
+	    __pthread_lock(&__sigmask_lock, self);
     /* Don't allow __pthread_sig_restart to be unmasked.
        Don't allow __pthread_sig_cancel to be masked. */
     switch(how) {
     case SIG_SETMASK:
-      sigaddset(&mask, __pthread_sig_restart);
-      sigdelset(&mask, __pthread_sig_cancel);
+      __sigaddset(&mask, __pthread_sig_restart);
+      __sigdelset(&mask, __pthread_sig_cancel);
+      if (__pthread_new_manager) {
+        self->p_sigmask = mask;
+        match_pending(THREAD_GETMEM(self, p_pid), &self->p_sigmask);
+      }
       break;
     case SIG_BLOCK:
-      sigdelset(&mask, __pthread_sig_cancel);
+      __sigdelset(&mask, __pthread_sig_cancel);
+      if (__pthread_new_manager) {
+        for (i = 1; i < NSIG; i++) {
+          if (__sigismember(&mask, i))
+  	    __sigaddset(&self->p_sigmask, i);
+        }
+      }
       break;
     case SIG_UNBLOCK:
-      sigdelset(&mask, __pthread_sig_restart);
+      __sigdelset(&mask, __pthread_sig_restart);
+      if (__pthread_new_manager) {
+        for (i = 1; i < NSIG; i++) {
+          if (__sigismember(&mask, i))
+  	    __sigdelset(&self->p_sigmask, i);
+        }
+        match_pending(THREAD_GETMEM(self, p_pid), &self->p_sigmask);
+      }
       break;
     }
+    if (__pthread_new_manager)
+	__pthread_unlock(&__sigmask_lock);
     newmask = &mask;
   }
   if (sigprocmask(how, newmask, oldmask) == -1)
@@ -76,11 +118,108 @@
   void (*rt) (int, struct siginfo *, struct ucontext *);
 } sighandler[NSIG];
 
+static int is_synch_signal(int signo)
+{
+	switch (signo) {
+	    case SIGILL:
+#if 0
+	    case SIGIOT:	/* SIGIOT is same as SIGABRT */
+#endif
+	    case SIGABRT:
+	    case SIGFPE:
+	    case SIGSEGV:
+	    case SIGBUS:
+	    case SIGSYS:
+	    case SIGPIPE:
+		return 1;
+	    default:
+		return 0;
+	}
+}
+
+/*
+ * signal handler for manager signals
+ * called with all signals masked
+ */
+static void pthread_sighandler_manager(int signo, struct siginfo *si, struct ucontext *uc)
+{
+	pthread_descr self, th;
+	pid_t pid;
+	
+	if (si->si_code > 0 && is_synch_signal(signo)) {
+		/* fatal signal for manager generated by the kernel
+		   die with this signal, threads will be killed automaticly */
+		struct sigaction sa;
+		sigset_t mask;
+		sa.sa_handler = SIG_DFL;
+		sa.sa_flags = 0;
+		sigemptyset(&sa.sa_mask);
+		__sigaction(signo, &sa, NULL);
+		kill(getpid(), signo);
+	        sigfillset(&mask);
+                sigdelset(&mask, signo);
+                sigprocmask(SIG_SETMASK, &mask, NULL);
+		_exit(0);
+	} else {
+		/* generated by user process or due to asynchronous event
+		 * by kernel (like SIGINT, SIGHUP, ...) */
+		self = thread_self();
+		__pthread_lock(&__sigmask_lock, self);
+		/* check main */
+		pid = THREAD_GETMEM(__pthread_main_thread, p_pid);
+		if (!sigismember(&__pthread_main_thread->p_sigmask, signo) && pid > 0) {
+			kill(pid, signo);
+			__pthread_unlock(&__sigmask_lock);
+			return;
+		}
+		/* check others */
+		__pthread_lock(&__thrlive_lock, self);
+		for (th = __pthread_main_thread->p_nextlive;
+		     th != __pthread_main_thread;
+		     th = th->p_nextlive) {
+			pid = THREAD_GETMEM(th, p_pid);
+			if (!sigismember(&th->p_sigmask, signo) && pid > 0) {
+				kill(pid, signo);
+				__pthread_unlock(&__thrlive_lock);
+				__pthread_unlock(&__sigmask_lock);
+				return;
+			}
+		}
+		__pthread_unlock(&__thrlive_lock);
+	
+		/* ok, all have signo masked so set it as pending */
+		__sig_pending[signo]++;
+		__pthread_unlock(&__sigmask_lock);
+	}
+}
+
+void install_manager_sighandlers(void)
+{
+	struct sigaction sa;
+	int i;
+	
+	for (i = 1; i < NSIG; i++) {
+		if (i == __pthread_sig_restart ||
+		    i == __pthread_sig_cancel ||
+		    i == __pthread_sig_debug)
+			continue;
+#ifndef __i386__
+		sa.sa_handler = pthread_sighandler_manager;
+#else
+		sa.sa_handler = (__sighandler_t) pthread_sighandler_manager;
+#endif
+		sigfillset(&sa.sa_mask); /* run handler with all signals blocked */
+		sa.sa_flags = SA_SIGINFO;
+		__sigaction(i, &sa, NULL);
+	}
+}
+
 /* The wrapper around user-provided signal handlers */
 static void pthread_sighandler(int signo, SIGCONTEXT ctx)
 {
   pthread_descr self = thread_self();
   char * in_sighandler;
+	
   /* If we're in a sigwait operation, just record the signal received
      and return without calling the user's handler */
   if (THREAD_GETMEM(self, p_sigwaiting)) {

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]