예제 #1
0
int
__pthread_clock_settime (clockid_t clock_id, hp_timing_t offset)
{
  pthread_descr self = thread_self ();
  pthread_t thread = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE;
  const unsigned int mask = ~0U >> CLOCK_IDFIELD_SIZE;

  if (thread == 0 || (THREAD_GETMEM (self, p_tid) & mask) == thread)
    /* Our own clock.  */
    THREAD_SETMEM (self, p_cpuclock_offset, offset);
  else
    {
      pthread_descr th;
      pthread_handle handle = thread_handle (thread);
      __pthread_lock (&handle->h_lock, NULL);
      th = handle->h_descr;
      if (th == NULL || (th->p_tid & mask) != thread || th->p_terminated)
	{
	  __pthread_unlock (&handle->h_lock);
	  __set_errno (EINVAL);
	  return -1;
	}
      th->p_cpuclock_offset = offset;
      __pthread_unlock (&handle->h_lock);
   }

  return 0;
}
예제 #2
0
int pthread_cancel(pthread_t thread)
{
  pthread_handle handle = thread_handle(thread);
  int pid;
  int dorestart = 0;
  pthread_descr th;
  pthread_extricate_if *pextricate;
  int already_canceled;

  __pthread_lock(&handle->h_lock, NULL);
  if (invalid_handle(handle, thread)) {
    __pthread_unlock(&handle->h_lock);
    return ESRCH;
  }

  th = handle->h_descr;

  already_canceled = th->p_canceled;
  th->p_canceled = 1;

  if (th->p_cancelstate == PTHREAD_CANCEL_DISABLE || already_canceled) {
    __pthread_unlock(&handle->h_lock);
    return 0;
  }

  pextricate = th->p_extricate;
  pid = th->p_pid;

  /* If the thread has registered an extrication interface, then
     invoke the interface. If it returns 1, then we succeeded in
     dequeuing the thread from whatever waiting object it was enqueued
     with. In that case, it is our responsibility to wake it up.
     And also to set the p_woken_by_cancel flag so the woken thread
     can tell that it was woken by cancellation. */

  if (pextricate != NULL) {
    dorestart = pextricate->pu_extricate_func(pextricate->pu_object, th);
    th->p_woken_by_cancel = dorestart;
  }

  __pthread_unlock(&handle->h_lock);

  /* If the thread has suspended or is about to, then we unblock it by
     issuing a restart, instead of a cancel signal. Otherwise we send
     the cancel signal to unblock the thread from a cancellation point,
     or to initiate asynchronous cancellation. The restart is needed so
     we have proper accounting of restarts; suspend decrements the thread's
     resume count, and restart() increments it.  This also means that suspend's
     handling of the cancel signal is obsolete. */

  if (dorestart)
    restart(th);
  else
    kill(pid, __pthread_sig_cancel);

  return 0;
}
예제 #3
0
static void pthread_free(pthread_descr th)
{
  pthread_handle handle;
  pthread_readlock_info *iter, *next;
#ifndef __ARCH_USE_MMU__
  char *h_bottom_save;
#endif

  /* Make the handle invalid */
  handle =  thread_handle(th->p_tid);
  __pthread_lock(&handle->h_lock, NULL);
#ifndef __ARCH_USE_MMU__
  h_bottom_save = handle->h_bottom;
#endif
  handle->h_descr = NULL;
  handle->h_bottom = (char *)(-1L);
  __pthread_unlock(&handle->h_lock);
#ifdef FREE_THREAD_SELF
  FREE_THREAD_SELF(th, th->p_nr);
#endif
  /* One fewer threads in __pthread_handles */
  __pthread_handles_num--;

  /* Destroy read lock list, and list of free read lock structures.
     If the former is not empty, it means the thread exited while
     holding read locks! */

  for (iter = th->p_readlock_list; iter != NULL; iter = next)
    {
      next = iter->pr_next;
      free(iter);
    }

  for (iter = th->p_readlock_free; iter != NULL; iter = next)
    {
      next = iter->pr_next;
      free(iter);
    }

  /* If initial thread, nothing to free */
  if (th == &__pthread_initial_thread) return;
  if (!th->p_userstack)
    {
#ifdef __ARCH_USE_MMU__
      /* Free the stack and thread descriptor area */
      if (th->p_guardsize != 0)
	munmap(th->p_guardaddr, th->p_guardsize);
      munmap((caddr_t) ((char *)(th+1) - STACK_SIZE), STACK_SIZE);
#else
      /* For non-MMU systems we always malloc the stack, so free it here. -StS */
      free(h_bottom_save);
#endif /* __ARCH_USE_MMU__ */
    }
}
예제 #4
0
static void pthread_free(pthread_descr th)
{
  pthread_handle handle;
  ASSERT(th->p_exited);
  /* Make the handle invalid */
  handle =  thread_handle(th->p_tid);
  acquire(&handle->h_spinlock);
  handle->h_descr = NULL;
  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);
}
예제 #5
0
int pthread_kill(pthread_t thread, int signo)
{
  pthread_handle handle = thread_handle(thread);
  int pid;

  __pthread_lock(&handle->h_lock, NULL);
  if (invalid_handle(handle, thread)) {
    __pthread_unlock(&handle->h_lock);
    return ESRCH;
  }
  pid = handle->h_descr->p_pid;
  __pthread_unlock(&handle->h_lock);
  if (kill(pid, signo) == -1)
    return errno;
  else
    return 0;
}
예제 #6
0
int pthread_kill(pthread_t thread, int signo)
{
    pthread_handle handle = thread_handle(thread);
    int pid;

    acquire(&handle->h_spinlock);
    if (invalid_handle(handle, thread)) {
        release(&handle->h_spinlock);
        return ESRCH;
    }
    pid = handle->h_descr->p_pid;
    release(&handle->h_spinlock);
    if (kill(pid, signo) == -1)
        return errno;
    else
        return 0;
}
예제 #7
0
int pthread_join(pthread_t thread_id, void ** thread_return)
{
  volatile pthread_descr self = thread_self();
  struct pthread_request request;
  pthread_handle handle = thread_handle(thread_id);
  pthread_descr th;

  acquire(&handle->h_spinlock);
  if (invalid_handle(handle, thread_id)) {
    release(&handle->h_spinlock);
    return ESRCH;
  }
  th = handle->h_descr;
  if (th == self) {
    release(&handle->h_spinlock);
    return EDEADLK;
  }
  /* If detached or already joined, error */
  if (th->p_detached || th->p_joining != NULL) {
    release(&handle->h_spinlock);
    return EINVAL;
  }
  /* If not terminated yet, suspend ourselves. */
  if (! th->p_terminated) {
    th->p_joining = self;
    release(&handle->h_spinlock);
    suspend_with_cancellation(self);
    /* This is a cancellation point */
    if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
      th->p_joining = NULL;
      pthread_exit(PTHREAD_CANCELED);
    }
    acquire(&handle->h_spinlock);
  }
  /* Get return value */
  if (thread_return != NULL) *thread_return = th->p_retval;
  release(&handle->h_spinlock);
  /* Send notification to thread manager */
  if (__pthread_manager_request >= 0) {
    request.req_thread = self;
    request.req_kind = REQ_FREE;
    request.req_args.free.thread = th;
    write(__pthread_manager_request, (char *) &request, sizeof(request));
  }
  return 0;
}
예제 #8
0
int pthread_getschedparam(pthread_t thread, int *policy,
                          struct sched_param *param)
{
  pthread_handle handle = thread_handle(thread);
  int pid, pol;

  __pthread_lock(&handle->h_lock, NULL);
  if (invalid_handle(handle, thread)) {
    __pthread_unlock(&handle->h_lock);
    return ESRCH;
  }
  pid = handle->h_descr->p_pid;
  __pthread_unlock(&handle->h_lock);
  pol = sched_getscheduler(pid);
  if (pol == -1) return errno;
  if (sched_getparam(pid, param) == -1) return errno;
  *policy = pol;
  return 0;
}
예제 #9
0
int
__pthread_clock_gettime (clockid_t clock_id, hp_timing_t freq,
			 struct timespec *tp)
{
  hp_timing_t tsc, cpuclock_offset;
  pthread_descr self = thread_self ();
  pthread_t thread = ((unsigned int) clock_id) >> CLOCK_IDFIELD_SIZE;
  const unsigned int mask = ~0U >> CLOCK_IDFIELD_SIZE;

  if (thread == 0 || (THREAD_GETMEM (self, p_tid) & mask) == thread)
    cpuclock_offset = THREAD_GETMEM (self, p_cpuclock_offset);
  else
    {
      pthread_descr th;
      pthread_handle handle = thread_handle (thread);
      __pthread_lock (&handle->h_lock, NULL);
      th = handle->h_descr;
      if (th == NULL || (th->p_tid & mask) != thread || th->p_terminated)
	{
	  __pthread_unlock (&handle->h_lock);
	  __set_errno (EINVAL);
	  return -1;
	}
      cpuclock_offset = th->p_cpuclock_offset;
      __pthread_unlock (&handle->h_lock);
   }

  /* Get the current counter.  */
  HP_TIMING_NOW (tsc);

  /* Compute the offset since the start time of the process.  */
  tsc -= cpuclock_offset;

  /* Compute the seconds.  */
  tp->tv_sec = tsc / freq;

  /* And the nanoseconds.  This computation should be stable until
     we get machines with about 16GHz frequency.  */
  tp->tv_nsec = ((tsc % freq) * 1000000000ull) / freq;

  return 0;
}
예제 #10
0
int pthread_setschedparam(pthread_t thread, int policy,
                          const struct sched_param *param)
{
  pthread_handle handle = thread_handle(thread);
  pthread_descr th;

  __pthread_lock(&handle->h_lock, NULL);
  if (invalid_handle(handle, thread)) {
    __pthread_unlock(&handle->h_lock);
    return ESRCH;
  }
  th = handle->h_descr;
  if (sched_setscheduler(th->p_pid, policy, param) == -1) {
    __pthread_unlock(&handle->h_lock);
    return errno;
  }
  th->p_priority = policy == SCHED_OTHER ? 0 : param->sched_priority;
  __pthread_unlock(&handle->h_lock);
  if (__pthread_manager_request >= 0)
    __pthread_manager_adjust_prio(th->p_priority);
  return 0;
}
예제 #11
0
int pthread_detach(pthread_t thread_id)
{
  int terminated;
  struct pthread_request request;
  pthread_handle handle = thread_handle(thread_id);
  pthread_descr th;

  __pthread_lock(&handle->h_lock, NULL);
  if (invalid_handle(handle, thread_id)) {
    __pthread_unlock(&handle->h_lock);
    return ESRCH;
  }
  th = handle->h_descr;
  /* If already detached, error */
  if (th->p_detached) {
    __pthread_unlock(&handle->h_lock);
    return EINVAL;
  }
  /* If already joining, don't do anything. */
  if (th->p_joining != NULL) {
    __pthread_unlock(&handle->h_lock);
    return 0;
  }
  /* Mark as detached */
  th->p_detached = 1;
  terminated = th->p_terminated;
  __pthread_unlock(&handle->h_lock);
  /* If already terminated, notify thread manager to reclaim resources */
  if (terminated && __pthread_manager_request >= 0) {
    request.req_thread = thread_self();
    request.req_kind = REQ_FREE;
    request.req_args.free.thread_id = thread_id;
    TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request,
		(char *) &request, sizeof(request)));
  }
  return 0;
}
예제 #12
0
static void pthread_handle_free(pthread_t th_id)
{
  pthread_handle handle = thread_handle(th_id);
  pthread_descr th;

  __pthread_lock(&handle->h_lock, NULL);
  if (invalid_handle(handle, th_id)) {
    /* pthread_reap_children has deallocated the thread already,
       nothing needs to be done */
    __pthread_unlock(&handle->h_lock);
    return;
  }
  th = handle->h_descr;
  if (th->p_exited) {
    __pthread_unlock(&handle->h_lock);
    pthread_free(th);
  } else {
    /* The Unix process of the thread is still running.
       Mark the thread as detached so that the thread manager will
       deallocate its resources when the Unix process exits. */
    th->p_detached = 1;
    __pthread_unlock(&handle->h_lock);
  }
}
예제 #13
0
static void pthread_free(pthread_descr th)
{
  pthread_handle handle;
  pthread_readlock_info *iter, *next;

  ASSERT(th->p_exited);
  /* Make the handle invalid */
  handle =  thread_handle(th->p_tid);
  __pthread_lock(&handle->h_lock, NULL);
  handle->h_descr = NULL;
  handle->h_bottom = (char *)(-1L);
  __pthread_unlock(&handle->h_lock);
#ifdef FREE_THREAD
  FREE_THREAD(th, th->p_nr);
#endif
  /* One fewer threads in __pthread_handles */
  __pthread_handles_num--;

  /* Destroy read lock list, and list of free read lock structures.
     If the former is not empty, it means the thread exited while
     holding read locks! */

  for (iter = th->p_readlock_list; iter != NULL; iter = next)
    {
      next = iter->pr_next;
      free(iter);
    }

  for (iter = th->p_readlock_free; iter != NULL; iter = next)
    {
      next = iter->pr_next;
      free(iter);
    }

  /* If initial thread, nothing to free */
  if (!th->p_userstack)
    {
      size_t guardsize = th->p_guardsize;
      /* Free the stack and thread descriptor area */
      char *guardaddr = th->p_guardaddr;
#ifdef _STACK_GROWS_UP
# ifdef USE_TLS
      size_t stacksize = guardaddr - th->p_stackaddr;
      guardaddr = th->p_stackaddr;
# else
      size_t stacksize = guardaddr - (char *)th;
      guardaddr = (char *)th;
# endif
#else
      /* Guardaddr is always set, even if guardsize is 0.  This allows
	 us to compute everything else.  */
# ifdef USE_TLS
      size_t stacksize = th->p_stackaddr - guardaddr - guardsize;
# else
      size_t stacksize = (char *)(th+1) - guardaddr - guardsize;
# endif
# ifdef NEED_SEPARATE_REGISTER_STACK
      /* Take account of the register stack, which is below guardaddr.  */
      guardaddr -= stacksize;
      stacksize *= 2;
# endif
#endif
      /* Unmap the stack.  */
      munmap(guardaddr, stacksize + guardsize);

    }

#ifdef USE_TLS
# if TLS_DTV_AT_TP
  th = (pthread_descr) ((char *) th + TLS_PRE_TCB_SIZE);
# endif
  _dl_deallocate_tls (th, true);
#endif
}
예제 #14
0
int pthread_getattr_np (pthread_t thread, pthread_attr_t *attr)
{
  pthread_handle handle = thread_handle (thread);
  pthread_descr descr;
#ifdef NOT_FOR_L4
  int ret = 0;
#endif

  if (handle == NULL)
    return ENOENT;

  descr = handle_to_descr(handle);

  attr->__detachstate = (descr->p_detached
			 ? PTHREAD_CREATE_DETACHED
			 : PTHREAD_CREATE_JOINABLE);

  attr->__schedpolicy = descr->p_sched_policy;
  if (attr->__schedpolicy == -1)
    return EINVAL;
  attr->__schedparam.sched_priority = descr->p_priority;

  if (attr->__schedparam.sched_priority < 0)
    return EINVAL;

  attr->__inheritsched = descr->p_inheritsched;
  attr->__scope = PTHREAD_SCOPE_SYSTEM;

#ifdef _STACK_GROWS_DOWN
# ifdef USE_TLS
  attr->__stacksize = descr->p_stackaddr - (char *)descr->p_guardaddr
		      - descr->p_guardsize;
# else
  attr->__stacksize = (char *)(descr + 1) - (char *)descr->p_guardaddr
		      - descr->p_guardsize;
# endif
#else
# ifdef USE_TLS
  attr->__stacksize = (char *)descr->p_guardaddr - descr->p_stackaddr;
# else
  attr->__stacksize = (char *)descr->p_guardaddr - (char *)descr;
# endif
#endif
  attr->__guardsize = descr->p_guardsize;
  attr->__stackaddr_set = descr->p_userstack;
#ifdef NEED_SEPARATE_REGISTER_STACK
  if (descr->p_userstack == 0)
    attr->__stacksize *= 2;
  /* XXX This is awkward.  The guard pages are in the middle of the
     two stacks.  We must count the guard size in the stack size since
     otherwise the range of the stack area cannot be computed.  */
  attr->__stacksize += attr->__guardsize;
#endif
#ifdef USE_TLS
  attr->__stackaddr = descr->p_stackaddr;
#else
# ifndef _STACK_GROWS_UP
  attr->__stackaddr = (char *)(descr + 1);
# else
  attr->__stackaddr = (char *)descr;
# endif
#endif


#ifdef NOT_FOR_L4 // XXX: fix for initial thread
#ifdef USE_TLS
  if (attr->__stackaddr == NULL)
#else
  if (descr == &__pthread_initial_thread)
#endif
    {
      /* Stack size limit.  */
      struct rlimit rl;

      /* The safest way to get the top of the stack is to read
	 /proc/self/maps and locate the line into which
	 __libc_stack_end falls.  */
      FILE *fp = fopen ("/proc/self/maps", "rc");
      if (fp == NULL)
	ret = errno;
      /* We need the limit of the stack in any case.  */
      else if (getrlimit (RLIMIT_STACK, &rl) != 0)
	ret = errno;
      else
	{
	  /* We need no locking.  */
	  __fsetlocking (fp, FSETLOCKING_BYCALLER);

	  /* Until we found an entry (which should always be the case)
	     mark the result as a failure.  */
	  ret = ENOENT;

	  char *line = NULL;
	  size_t linelen = 0;
	  uintptr_t last_to = 0;

	  while (! feof_unlocked (fp))
	    {
	      if (getdelim (&line, &linelen, '\n', fp) <= 0)
		break;

	      uintptr_t from;
	      uintptr_t to;
	      if (sscanf (line, "%" SCNxPTR "-%" SCNxPTR, &from, &to) != 2)
		continue;
	      if (from <= (uintptr_t) __libc_stack_end
		  && (uintptr_t) __libc_stack_end < to)
		{
		  /* Found the entry.  Now we have the info we need.  */
		  attr->__stacksize = rl.rlim_cur;
#ifdef _STACK_GROWS_UP
		  /* Don't check to enforce a limit on the __stacksize */
		  attr->__stackaddr = (void *) from;
#else
		  attr->__stackaddr = (void *) to;

		  /* The limit might be too high.  */
		  if ((size_t) attr->__stacksize
		      > (size_t) attr->__stackaddr - last_to)
		    attr->__stacksize = (size_t) attr->__stackaddr - last_to;
#endif

		  /* We succeed and no need to look further.  */
		  ret = 0;
		  break;
		}
	      last_to = to;
	    }

	  fclose (fp);
	  free (line);
	}
    }
#endif
  return 0;

}
예제 #15
0
int pthread_join(pthread_t thread_id, void ** thread_return)
{
  volatile pthread_descr self = thread_self();
  struct pthread_request request;
  pthread_handle handle = thread_handle(thread_id);
  pthread_descr th;
  pthread_extricate_if extr;
  int already_canceled = 0;
  PDEBUG("\n");

  /* Set up extrication interface */
  extr.pu_object = handle;
  extr.pu_extricate_func = join_extricate_func;

  __pthread_lock(&handle->h_lock, self);
  if (invalid_handle(handle, thread_id)) {
    __pthread_unlock(&handle->h_lock);
    return ESRCH;
  }
  th = handle->h_descr;
  if (th == self) {
    __pthread_unlock(&handle->h_lock);
    return EDEADLK;
  }
  /* If detached or already joined, error */
  if (th->p_detached || th->p_joining != NULL) {
    __pthread_unlock(&handle->h_lock);
    return EINVAL;
  }
  /* If not terminated yet, suspend ourselves. */
  if (! th->p_terminated) {
    /* Register extrication interface */
    __pthread_set_own_extricate_if(self, &extr);
    if (!(THREAD_GETMEM(self, p_canceled)
	&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
      th->p_joining = self;
    else
      already_canceled = 1;
    __pthread_unlock(&handle->h_lock);

    if (already_canceled) {
      __pthread_set_own_extricate_if(self, 0);
      __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
    }

  PDEBUG("before suspend\n");
    suspend(self);
  PDEBUG("after suspend\n");
    /* Deregister extrication interface */
    __pthread_set_own_extricate_if(self, 0);

    /* This is a cancellation point */
    if (THREAD_GETMEM(self, p_woken_by_cancel)
	&& THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
      THREAD_SETMEM(self, p_woken_by_cancel, 0);
      __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
    }
    __pthread_lock(&handle->h_lock, self);
  }
  /* Get return value */
  if (thread_return != NULL) *thread_return = th->p_retval;
  __pthread_unlock(&handle->h_lock);
  /* Send notification to thread manager */
  if (__pthread_manager_request >= 0) {
    request.req_thread = self;
    request.req_kind = REQ_FREE;
    request.req_args.free.thread_id = thread_id;
    TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request,
		(char *) &request, sizeof(request)));
  }
  return 0;
}