about summary refs log tree commit diff
path: root/linuxthreads/manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'linuxthreads/manager.c')
-rw-r--r--linuxthreads/manager.c133
1 files changed, 87 insertions, 46 deletions
diff --git a/linuxthreads/manager.c b/linuxthreads/manager.c
index d14a57ccd7..41acf01b29 100644
--- a/linuxthreads/manager.c
+++ b/linuxthreads/manager.c
@@ -23,6 +23,7 @@
 #include <unistd.h>
 #include <sys/poll.h>		/* for poll */
 #include <sys/mman.h>           /* for mmap */
+#include <sys/param.h>
 #include <sys/time.h>
 #include <sys/wait.h>           /* for waitpid macros */
 #include <linux/tasks.h>
@@ -99,11 +100,11 @@ int __pthread_manager(void *arg)
   /* Set the error variable.  */
   __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno;
   __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno;
-  /* Block all signals except PTHREAD_SIG_RESTART, PTHREAD_SIG_CANCEL
+  /* Block all signals except __pthread_sig_restart, __pthread_sig_cancel
      and SIGTRAP */
   sigfillset(&mask);
-  sigdelset(&mask, PTHREAD_SIG_RESTART);
-  sigdelset(&mask, PTHREAD_SIG_CANCEL); /* for debugging new threads */
+  sigdelset(&mask, __pthread_sig_restart);
+  sigdelset(&mask, __pthread_sig_cancel); /* for debugging new threads */
   sigdelset(&mask, SIGTRAP);            /* for debugging purposes */
   sigprocmask(SIG_SETMASK, &mask, NULL);
   /* Raise our priority to match that of main thread */
@@ -161,7 +162,7 @@ int __pthread_manager(void *arg)
         break;
       case REQ_DEBUG:
         /* Make gdb aware of new thread */
-        if (__pthread_threads_debug) raise(PTHREAD_SIG_CANCEL);
+	if (__pthread_threads_debug) raise(__pthread_sig_cancel);
         restart(request.req_thread);
         break;
       }
@@ -205,6 +206,78 @@ static int pthread_start_thread(void *arg)
   return 0;
 }
 
+static int pthread_allocate_stack(const pthread_attr_t *attr,
+                                  pthread_descr default_new_thread,
+                                  int pagesize,
+                                  pthread_descr * out_new_thread,
+                                  char ** out_new_thread_bottom,
+                                  char ** out_guardaddr,
+                                  size_t * out_guardsize)
+{
+  pthread_descr new_thread;
+  char * new_thread_bottom;
+  char * guardaddr;
+  size_t stacksize, guardsize;
+
+  if (attr != NULL && attr->stackaddr_set)
+    {
+      /* The user provided a stack. */
+      new_thread =
+        (pthread_descr) ((long)(attr->stackaddr) & -sizeof(void *)) - 1;
+      new_thread_bottom = (char *) attr->stackaddr - attr->stacksize;
+      guardaddr = NULL;
+      guardsize = 0;
+    }
+  else
+    {
+      /* Allocate space for stack and thread descriptor at default address */
+      new_thread = default_new_thread;
+      new_thread_bottom = (char *) new_thread - STACK_SIZE;
+      if (mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE),
+               INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN,
+               -1, 0) == MAP_FAILED)
+        /* Bad luck, this segment is already mapped. */
+        return -1;
+      /* We manage to get a stack.  Now see whether we need a guard
+         and allocate it if necessary.  Notice that the default
+         attributes (stack_size = STACK_SIZE - pagesize and
+         guardsize = pagesize) do not need a guard page, since
+         the RLIMIT_STACK soft limit prevents stacks from
+         running into one another. */
+      if (attr == NULL ||
+          attr->guardsize == 0 ||
+          (attr->guardsize == pagesize &&
+           attr->stacksize == STACK_SIZE - pagesize))
+        {
+          /* We don't need a guard page. */
+          guardaddr = NULL;
+          guardsize = 0;
+        }
+      else
+        {
+          /* Put a bad page at the bottom of the stack */
+          stacksize = roundup(attr->stacksize, pagesize);
+          if (stacksize >= STACK_SIZE - pagesize)
+            stacksize = STACK_SIZE - pagesize;
+          guardaddr = (void *)new_thread - stacksize;
+          guardsize = attr->guardsize;
+          if (mmap ((caddr_t) guardaddr, guardsize, 0, MAP_FIXED, -1, 0)
+              == MAP_FAILED)
+            {
+              /* We don't make this an error.  */
+              guardaddr = NULL;
+              guardsize = 0;
+            }
+        }
+    }
+  *out_new_thread = new_thread;
+  *out_new_thread_bottom = new_thread_bottom;
+  *out_guardaddr = guardaddr;
+  *out_guardsize = guardsize;
+  return 0;
+}
+
 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)
@@ -214,8 +287,9 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
   pthread_descr new_thread;
   char * new_thread_bottom;
   pthread_t new_thread_id;
-  void *guardaddr = NULL;
+  char *guardaddr = NULL;
   size_t guardsize = 0;
+  int pagesize = __getpagesize();
 
   /* 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
@@ -223,50 +297,17 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
      but this is hard to implement.  FIXME  */
   if (attr != NULL && attr->schedpolicy != SCHED_OTHER && geteuid () != 0)
     return EPERM;
-  /* Find a free stack segment for the current stack */
+  /* Find a free segment for the thread, and allocate a stack if needed */
   for (sseg = 1; ; sseg++)
     {
       if (sseg >= PTHREAD_THREADS_MAX)
 	return EAGAIN;
       if (__pthread_handles[sseg].h_descr != NULL)
 	continue;
-
-      if (attr == NULL || !attr->stackaddr_set)
-	{
-	  new_thread = thread_segment(sseg);
-	  new_thread_bottom = (char *) new_thread - STACK_SIZE;
-	  /* Allocate space for stack and thread descriptor. */
-	  if (mmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
-		   INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
-		   MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN,
-		   -1, 0) != MAP_FAILED)
-	    {
-	      /* We manage to get a stack.  Now see whether we need a guard
-		 and allocate it if necessary.  */
-	      if (attr == NULL || attr->guardsize != 0)
-		{
-		  guardsize = attr ? attr->guardsize : __getpagesize ();
-		  guardaddr = mmap ((caddr_t)((char *)(new_thread+1)
-					      - STACK_SIZE),
-				    guardsize, 0, MAP_FIXED, -1, 0);
-		  if (guardaddr == MAP_FAILED)
-		    {
-		      /* We don't make this an error.  */
-		      guardaddr = NULL;
-		      guardsize = 0;
-		    }
-		}
-	      break;
-	    }
-	  /* It seems part of this segment is already mapped. Try the next. */
-	}
-      else
-	{
-	  new_thread = (pthread_descr) ((long) attr->stackaddr
-					& -sizeof(void *)) - 1;
-	  new_thread_bottom = (char *) attr->stackaddr - attr->stacksize;
-	  break;
-	}
+      if (pthread_allocate_stack(attr, thread_segment(sseg), pagesize,
+                                 &new_thread, &new_thread_bottom,
+                                 &guardaddr, &guardsize) == 0)
+        break;
     }
   /* Allocate new thread identifier */
   pthread_threads_counter += PTHREAD_THREADS_MAX;
@@ -329,7 +370,7 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
   /* Do the cloning */
   pid = __clone(pthread_start_thread, (void **) new_thread,
                 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
-                PTHREAD_SIG_RESTART,
+                __pthread_sig_restart,
                 new_thread);
   /* Check if cloning succeeded */
   if (pid == -1) {
@@ -492,7 +533,7 @@ static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode)
   for (th = issuing_thread->p_nextlive;
        th != issuing_thread;
        th = th->p_nextlive) {
-    kill(th->p_pid, PTHREAD_SIG_CANCEL);
+    kill(th->p_pid, __pthread_sig_cancel);
   }
   /* Now, wait for all these threads, so that they don't become zombies
      and their times are properly added to the thread manager's times. */
@@ -505,7 +546,7 @@ static void pthread_handle_exit(pthread_descr issuing_thread, int exitcode)
   _exit(0);
 }
 
-/* Handler for PTHREAD_SIG_RESTART in thread manager thread */
+/* Handler for __pthread_sig_restart in thread manager thread */
 
 void __pthread_manager_sighandler(int sig)
 {