|  | @@ -14,9 +14,12 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* The "thread manager" thread: manages creation and termination of threads */
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/* mods for uClibc: getpwd and getpagesize are the syscalls */
 | 
	
		
			
				|  |  | +/* mods for uClibc */
 | 
	
		
			
				|  |  |  #define __getpid getpid
 | 
	
		
			
				|  |  |  #define __getpagesize getpagesize
 | 
	
		
			
				|  |  | +#define __sched_get_priority_max sched_get_priority_max
 | 
	
		
			
				|  |  | +#define __sched_getscheduler sched_getscheduler
 | 
	
		
			
				|  |  | +#define __sched_getparam sched_getparam
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #include <features.h>
 | 
	
		
			
				|  |  |  #define __USE_GNU
 | 
	
	
		
			
				|  | @@ -81,8 +84,13 @@ volatile pthread_descr __pthread_last_event;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static inline pthread_descr thread_segment(int seg)
 | 
	
		
			
				|  |  |  {
 | 
	
		
			
				|  |  | +# ifdef _STACK_GROWS_UP
 | 
	
		
			
				|  |  | +  return (pthread_descr)(THREAD_STACK_START_ADDRESS + (seg - 1) * STACK_SIZE)
 | 
	
		
			
				|  |  | +         + 1;
 | 
	
		
			
				|  |  | +# else
 | 
	
		
			
				|  |  |    return (pthread_descr)(THREAD_STACK_START_ADDRESS - (seg - 1) * STACK_SIZE)
 | 
	
		
			
				|  |  |           - 1;
 | 
	
		
			
				|  |  | +# endif
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Flag set in signal handler to record child termination */
 | 
	
	
		
			
				|  | @@ -149,7 +157,7 @@ __pthread_manager(void *arg)
 | 
	
		
			
				|  |  |    sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */
 | 
	
		
			
				|  |  |    sigdelset(&manager_mask, SIGTRAP);            /* for debugging purposes */
 | 
	
		
			
				|  |  |    if (__pthread_threads_debug && __pthread_sig_debug > 0)
 | 
	
		
			
				|  |  | -      sigdelset(&manager_mask, __pthread_sig_debug);
 | 
	
		
			
				|  |  | +    sigdelset(&manager_mask, __pthread_sig_debug);
 | 
	
		
			
				|  |  |    sigprocmask(SIG_SETMASK, &manager_mask, NULL);
 | 
	
		
			
				|  |  |    /* Raise our priority to match that of main thread */
 | 
	
		
			
				|  |  |    __pthread_manager_adjust_prio(__pthread_main_thread->p_priority);
 | 
	
	
		
			
				|  | @@ -245,10 +253,12 @@ __pthread_manager(void *arg)
 | 
	
		
			
				|  |  |          PDEBUG("got REQ_DEBUG\n");
 | 
	
		
			
				|  |  |  	/* Make gdb aware of new thread and gdb will restart the
 | 
	
		
			
				|  |  |  	   new thread when it is ready to handle the new thread. */
 | 
	
		
			
				|  |  | -	if (__pthread_threads_debug && __pthread_sig_debug > 0) {
 | 
	
		
			
				|  |  | -      PDEBUG("about to call raise(__pthread_sig_debug)\n");
 | 
	
		
			
				|  |  | +	if (__pthread_threads_debug && __pthread_sig_debug > 0)
 | 
	
		
			
				|  |  | +	{
 | 
	
		
			
				|  |  | +	  PDEBUG("about to call raise(__pthread_sig_debug)\n");
 | 
	
		
			
				|  |  |  	  raise(__pthread_sig_debug);
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +        break;
 | 
	
		
			
				|  |  |        case REQ_KICK:
 | 
	
		
			
				|  |  |  	/* This is just a prod to get the manager to reap some
 | 
	
		
			
				|  |  |  	   threads right away, avoiding a potential delay at shutdown. */
 | 
	
	
		
			
				|  | @@ -279,6 +289,7 @@ int __pthread_manager_event(void *arg)
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Process creation */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static int
 | 
	
		
			
				|  |  |  __attribute__ ((noreturn))
 | 
	
		
			
				|  |  |  pthread_start_thread(void *arg)
 | 
	
	
		
			
				|  | @@ -286,9 +297,16 @@ pthread_start_thread(void *arg)
 | 
	
		
			
				|  |  |    pthread_descr self = (pthread_descr) arg;
 | 
	
		
			
				|  |  |    struct pthread_request request;
 | 
	
		
			
				|  |  |    void * outcome;
 | 
	
		
			
				|  |  | +#if HP_TIMING_AVAIL
 | 
	
		
			
				|  |  | +  hp_timing_t tmpclock;
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |    /* Initialize special thread_self processing, if any.  */
 | 
	
		
			
				|  |  |  #ifdef INIT_THREAD_SELF
 | 
	
		
			
				|  |  |    INIT_THREAD_SELF(self, self->p_nr);
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  | +#if HP_TIMING_AVAIL
 | 
	
		
			
				|  |  | +  HP_TIMING_NOW (tmpclock);
 | 
	
		
			
				|  |  | +  THREAD_SETMEM (self, p_cpuclock_offset, tmpclock);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |    PDEBUG("\n");
 | 
	
		
			
				|  |  |    /* Make sure our pid field is initialized, just in case we get there
 | 
	
	
		
			
				|  | @@ -363,12 +381,39 @@ static int pthread_allocate_stack(const pthread_attr_t *attr,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (attr != NULL && attr->__stackaddr_set)
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  | +#ifdef _STACK_GROWS_UP
 | 
	
		
			
				|  |  |        /* The user provided a stack. */
 | 
	
		
			
				|  |  | +# ifdef USE_TLS
 | 
	
		
			
				|  |  | +      /* This value is not needed.  */
 | 
	
		
			
				|  |  | +      new_thread = (pthread_descr) attr->__stackaddr;
 | 
	
		
			
				|  |  | +      new_thread_bottom = (char *) new_thread;
 | 
	
		
			
				|  |  | +# else
 | 
	
		
			
				|  |  | +      new_thread = (pthread_descr) attr->__stackaddr;
 | 
	
		
			
				|  |  | +      new_thread_bottom = (char *) (new_thread + 1);
 | 
	
		
			
				|  |  | +# endif
 | 
	
		
			
				|  |  | +      guardaddr = attr->__stackaddr + attr->__stacksize;
 | 
	
		
			
				|  |  | +      guardsize = 0;
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +      /* The user provided a stack.  For now we interpret the supplied
 | 
	
		
			
				|  |  | +	 address as 1 + the highest addr. in the stack segment.  If a
 | 
	
		
			
				|  |  | +	 separate register stack is needed, we place it at the low end
 | 
	
		
			
				|  |  | +	 of the segment, relying on the associated stacksize to
 | 
	
		
			
				|  |  | +	 determine the low end of the segment.  This differs from many
 | 
	
		
			
				|  |  | +	 (but not all) other pthreads implementations.  The intent is
 | 
	
		
			
				|  |  | +	 that on machines with a single stack growing toward higher
 | 
	
		
			
				|  |  | +	 addresses, stackaddr would be the lowest address in the stack
 | 
	
		
			
				|  |  | +	 segment, so that it is consistently close to the initial sp
 | 
	
		
			
				|  |  | +	 value. */
 | 
	
		
			
				|  |  | +# ifdef USE_TLS
 | 
	
		
			
				|  |  | +      new_thread = (pthread_descr) attr->__stackaddr;
 | 
	
		
			
				|  |  | +# else
 | 
	
		
			
				|  |  |        new_thread =
 | 
	
		
			
				|  |  |          (pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1;
 | 
	
		
			
				|  |  | +# endif
 | 
	
		
			
				|  |  |        new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize;
 | 
	
		
			
				|  |  |        guardaddr = NULL;
 | 
	
		
			
				|  |  |        guardsize = 0;
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |        __pthread_nonstandard_stacks = 1;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    else
 | 
	
	
		
			
				|  | @@ -493,7 +538,7 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* 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
 | 
	
		
			
				|  |  | -     return value of the sched_setscheduler call in pthread_start_thread
 | 
	
		
			
				|  |  | +     return value of the __sched_setscheduler call in pthread_start_thread
 | 
	
		
			
				|  |  |       but this is hard to implement.  FIXME  */
 | 
	
		
			
				|  |  |    if (attr != NULL && attr->__schedpolicy != SCHED_OTHER && geteuid () != 0)
 | 
	
		
			
				|  |  |      return EPERM;
 | 
	
	
		
			
				|  | @@ -546,8 +591,8 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
 | 
	
		
			
				|  |  |  	      sizeof (struct sched_param));
 | 
	
		
			
				|  |  |        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);
 | 
	
		
			
				|  |  | +      new_thread->p_start_args.schedpolicy = __sched_getscheduler(father_pid);
 | 
	
		
			
				|  |  | +      __sched_getparam(father_pid, &new_thread->p_start_args.schedparam);
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      new_thread->p_priority =
 | 
	
	
		
			
				|  | @@ -588,17 +633,36 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
 | 
	
		
			
				|  |  |  	  __pthread_lock(new_thread->p_lock, NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	  /* We have to report this event.  */
 | 
	
		
			
				|  |  | +#ifdef NEED_SEPARATE_REGISTER_STACK
 | 
	
		
			
				|  |  | +	  /* Perhaps this version should be used on all platforms. But
 | 
	
		
			
				|  |  | +	   this requires that __clone2 be uniformly supported
 | 
	
		
			
				|  |  | +	   everywhere.
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	   And there is some argument for changing the __clone2
 | 
	
		
			
				|  |  | +	   interface to pass sp and bsp instead, making it more IA64
 | 
	
		
			
				|  |  | +	   specific, but allowing stacks to grow outward from each
 | 
	
		
			
				|  |  | +	   other, to get less paging and fewer mmaps.  */
 | 
	
		
			
				|  |  | +	  pid = __clone2(pthread_start_thread_event,
 | 
	
		
			
				|  |  | +  		 (void **)new_thread_bottom,
 | 
	
		
			
				|  |  | +			 (char *)stack_addr - new_thread_bottom,
 | 
	
		
			
				|  |  | +			 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
 | 
	
		
			
				|  |  | +			 __pthread_sig_cancel, new_thread);
 | 
	
		
			
				|  |  | +#elif _STACK_GROWS_UP
 | 
	
		
			
				|  |  | +	  pid = __clone(pthread_start_thread_event, (void *) new_thread_bottom,
 | 
	
		
			
				|  |  | +			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
 | 
	
		
			
				|  |  | +			__pthread_sig_cancel, new_thread);
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  |  	  pid = clone(pthread_start_thread_event, (void **) new_thread,
 | 
	
		
			
				|  |  |  			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
 | 
	
		
			
				|  |  |  			__pthread_sig_cancel, new_thread);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +#endif
 | 
	
		
			
				|  |  |  	  saved_errno = errno;
 | 
	
		
			
				|  |  |  	  if (pid != -1)
 | 
	
		
			
				|  |  |  	    {
 | 
	
		
			
				|  |  |  	      /* Now fill in the information about the new thread in
 | 
	
		
			
				|  |  | -	         the newly created thread's data structure.  We cannot let
 | 
	
		
			
				|  |  | -	         the new thread do this since we don't know whether it was
 | 
	
		
			
				|  |  | -	         already scheduled when we send the event.  */
 | 
	
		
			
				|  |  | +		 the newly created thread's data structure.  We cannot let
 | 
	
		
			
				|  |  | +		 the new thread do this since we don't know whether it was
 | 
	
		
			
				|  |  | +		 already scheduled when we send the event.  */
 | 
	
		
			
				|  |  |  	      new_thread->p_eventbuf.eventdata = new_thread;
 | 
	
		
			
				|  |  |  	      new_thread->p_eventbuf.eventnum = TD_CREATE;
 | 
	
		
			
				|  |  |  	      __pthread_last_event = new_thread;
 | 
	
	
		
			
				|  | @@ -619,9 +683,21 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
 | 
	
		
			
				|  |  |    if (pid == 0)
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  |        PDEBUG("cloning new_thread = %p\n", new_thread);
 | 
	
		
			
				|  |  | +#ifdef NEED_SEPARATE_REGISTER_STACK
 | 
	
		
			
				|  |  | +      pid = __clone2(pthread_start_thread,
 | 
	
		
			
				|  |  | +		     (void **)new_thread_bottom,
 | 
	
		
			
				|  |  | +                     (char *)stack_addr - new_thread_bottom,
 | 
	
		
			
				|  |  | +		     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
 | 
	
		
			
				|  |  | +		     __pthread_sig_cancel, new_thread);
 | 
	
		
			
				|  |  | +#elif _STACK_GROWS_UP
 | 
	
		
			
				|  |  | +      pid = __clone(pthread_start_thread, (void *) new_thread_bottom,
 | 
	
		
			
				|  |  | +		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
 | 
	
		
			
				|  |  | +		    __pthread_sig_cancel, new_thread);
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  |        pid = clone(pthread_start_thread, (void **) new_thread,
 | 
	
		
			
				|  |  |  		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
 | 
	
		
			
				|  |  |  		    __pthread_sig_cancel, new_thread);
 | 
	
		
			
				|  |  | +#endif /* !NEED_SEPARATE_REGISTER_STACK */
 | 
	
		
			
				|  |  |        saved_errno = errno;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    /* Check if cloning succeeded */
 | 
	
	
		
			
				|  | @@ -922,7 +998,7 @@ void __pthread_manager_adjust_prio(int thread_prio)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (thread_prio <= __pthread_manager_thread.p_priority) return;
 | 
	
		
			
				|  |  |    param.sched_priority =
 | 
	
		
			
				|  |  | -    thread_prio < sched_get_priority_max(SCHED_FIFO)
 | 
	
		
			
				|  |  | +    thread_prio < __sched_get_priority_max(SCHED_FIFO)
 | 
	
		
			
				|  |  |      ? thread_prio + 1 : thread_prio;
 | 
	
		
			
				|  |  |    sched_setscheduler(__pthread_manager_thread.p_pid, SCHED_FIFO, ¶m);
 | 
	
		
			
				|  |  |    __pthread_manager_thread.p_priority = thread_prio;
 |