Provide hook for initializing code before the fork.
[kopensolaris-gnu/glibc.git] / linuxthreads / manager.c
index 325955d..8844dec 100644 (file)
@@ -99,7 +99,8 @@ int __pthread_manager(void *arg)
     FD_SET(reqfd, &readfds);
     timeout.tv_sec = 2;
     timeout.tv_usec = 0;
-    n = __select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
+    n = __select(reqfd + 1, &readfds, NULL, NULL, &timeout);
+
     /* Check for termination of the main thread */
     if (getppid() == 1) {
       pthread_kill_all_threads(SIGKILL, 0);
@@ -172,27 +173,54 @@ static int pthread_start_thread(void *arg)
 }
 
 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)
 {
   size_t sseg;
   int pid;
   pthread_descr new_thread;
   pthread_t new_thread_id;
-  int i;
+  void *guardaddr = NULL;
 
   /* Find a free stack segment for the current stack */
-  for (sseg = 1; ; sseg++) {
-    if (sseg >= PTHREAD_THREADS_MAX) return EAGAIN;
-    if (__pthread_handles[sseg].h_descr != NULL) continue;
-    new_thread = thread_segment(sseg);
-    /* 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) break;
-    /* It seems part of this segment is already mapped. Try the next. */
-  }
+  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);
+         /* 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)
+               {
+                 guardaddr = mmap ((caddr_t)((char *)(new_thread+1)
+                                             - STACK_SIZE),
+                                   attr ? attr->guardsize : __getpagesize (),
+                                   0, MAP_FIXED, -1, 0);
+                 if (guardaddr == MAP_FAILED)
+                   /* We don't make this an error.  */
+                   guardaddr = NULL;
+               }
+             break;
+           }
+         /* It seems part of this segment is already mapped. Try the next. */
+       }
+      else
+       {
+         new_thread = (pthread_descr) attr->stackaddr - 1;
+         break;
+       }
+    }
   /* Allocate new thread identifier */
   pthread_threads_counter += PTHREAD_THREADS_MAX;
   new_thread_id = sseg + pthread_threads_counter;
@@ -217,8 +245,14 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
   new_thread->p_errno = 0;
   new_thread->p_h_errnop = &new_thread->p_h_errno;
   new_thread->p_h_errno = 0;
-  for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++)
-    new_thread->p_specific[i] = NULL;
+  new_thread->p_guardaddr = guardaddr;
+  new_thread->p_guardsize = (guardaddr == NULL
+                            ? 0
+                            : (attr == NULL
+                               ? __getpagesize () : attr->guardsize));
+  new_thread->p_userstack = attr != NULL && attr->stackaddr_set;
+  memset (new_thread->p_specific, '\0',
+         PTHREAD_KEY_1STLEVEL_SIZE * sizeof (new_thread->p_specific[0]));
   /* Initialize the thread handle */
   __pthread_handles[sseg].h_spinlock = 0; /* should already be 0 */
   __pthread_handles[sseg].h_descr = new_thread;
@@ -249,9 +283,14 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
                 new_thread);
   /* Check if cloning succeeded */
   if (pid == -1) {
-    /* Free the stack */
-    munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
-           INITIAL_STACK_SIZE);
+    /* Free the stack if we allocated it */
+    if (attr == NULL || !attr->stackaddr_set)
+      {
+       munmap((caddr_t)((char *)(new_thread+1) - INITIAL_STACK_SIZE),
+              INITIAL_STACK_SIZE);
+       if (new_thread->p_guardsize != 0)
+         munmap(new_thread->p_guardaddr, new_thread->p_guardsize);
+      }
     __pthread_handles[sseg].h_descr = NULL;
     return errno;
   }
@@ -268,6 +307,7 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
   return 0;
 }
 
+
 /* Free the resources of a thread. */
 
 static void pthread_free(pthread_descr th)
@@ -281,8 +321,13 @@ static void pthread_free(pthread_descr th)
   release(&handle->h_spinlock);
   /* If initial thread, nothing to free */
   if (th == &__pthread_initial_thread) return;
-  /* Free the stack and thread descriptor area */
-  munmap((caddr_t) ((char *)(th+1) - STACK_SIZE), STACK_SIZE);
+  if (!th->p_userstack)
+    {
+      /* Free the stack and thread descriptor area */
+      munmap((caddr_t) ((char *)(th+1) - STACK_SIZE), STACK_SIZE);
+      if (th->p_guardsize != 0)
+       munmap(th->p_guardaddr, th->p_guardsize);
+    }
 }
 
 /* Handle threads that have exited */