Beispiel #1
0
int pthread_completejoin(pid_t pid, FAR void *exit_value)
{
  FAR struct task_group_s *group = task_getgroup(pid);
  FAR struct join_s *pjoin;

  sinfo("pid=%d exit_value=%p group=%p\n", pid, exit_value, group);
  DEBUGASSERT(group);

  /* First, find thread's structure in the private data set. */

  (void)pthread_takesemaphore(&group->tg_joinsem);
  pjoin = pthread_findjoininfo(group, pid);
  if (!pjoin)
    {
      serr("ERROR: Could not find join info, pid=%d\n", pid);
      (void)pthread_givesemaphore(&group->tg_joinsem);
      return ERROR;
    }
  else
    {
      bool waiters;

      /* Save the return exit value in the thread structure. */

      pjoin->terminated = true;
      pjoin->exit_value = exit_value;

      /* Notify waiters of the availability of the exit value */

      waiters = pthread_notifywaiters(pjoin);

      /* If there are no waiters and if the thread is marked as detached.
       * then discard the join information now.  Otherwise, the pthread
       * join logic will call pthread_destroyjoin() when all of the threads
       * have sampled the exit value.
       */

      if (!waiters && pjoin->detached)
        {
           pthread_destroyjoin(group, pjoin);
        }

      /* Giving the following semaphore will allow the waiters
       * to call pthread_destroyjoin.
       */

      (void)pthread_givesemaphore(&group->tg_joinsem);
    }

  return OK;
}
Beispiel #2
0
int pthread_detach(pthread_t thread)
{
  FAR struct tcb_s *rtcb = (FAR struct tcb_s *)g_readytorun.head;
  FAR struct task_group_s *group = rtcb->group;
  FAR struct join_s *pjoin;
  int ret;

  sdbg("Thread=%d group=%p\n", thread, group);
  DEBUGASSERT(group);

  /* Find the entry associated with this pthread. */

  (void)pthread_takesemaphore(&group->tg_joinsem);
  pjoin = pthread_findjoininfo(group, (pid_t)thread);
  if (!pjoin)
    {
      sdbg("Could not find thread entry\n");
      ret = EINVAL;
    }
  else
    {
      /* Has the thread already terminated? */

      if (pjoin->terminated)
        {
          /* YES.. just remove the thread entry. */

          pthread_destroyjoin(group, pjoin);
        }
      else
        {
          /* NO.. Just mark the thread as detached.  It
           * will be removed and deallocated when the
           * thread exits
           */

          pjoin->detached = true;
        }

      /* Either case is successful */

      ret = OK;
    }

  (void)pthread_givesemaphore(&group->tg_joinsem);

  sdbg("Returning %d\n", ret);
  return ret;
}
int pthread_completejoin(pid_t pid, FAR void *exit_value)
{
  FAR join_t *pjoin;

  sdbg("process_id=%d exit_value=%p\n", pid, exit_value);

  /* First, find thread's structure in the private data set. */

  (void)pthread_takesemaphore(&g_join_semaphore);
  pjoin = pthread_findjoininfo(pid);
  if (!pjoin)
    {

      (void)pthread_givesemaphore(&g_join_semaphore);
      return ERROR;
    }
  else
    {
      bool waiters;

      /* Save the return exit value in the thread structure. */

      pjoin->terminated = true;
      pjoin->exit_value = exit_value;

      /* Notify waiters of the availability of the exit value */

      waiters = pthread_notifywaiters(pjoin);

      /* If there are no waiters and if the thread is marked as detached.
       * then discard the join information now.  Otherwise, the pthread
       * join logic will call pthread_destroyjoin() when all of the threads
       * have sampled the exit value.
       */

      if (!waiters && pjoin->detached)
        {
           pthread_destroyjoin(pjoin);
        }

      /* Giving the following semaphore will allow the waiters
       * to call pthread_destroyjoin.
       */

      (void)pthread_givesemaphore(&g_join_semaphore);
    }

  return OK;
}
Beispiel #4
0
static void *findjoininfo_callback(void *param)
{
	int ret_chk = 0;
	FAR struct task_group_s *group;
	FAR struct join_s *st_pjoininfo;

	g_bpthreadcallback = true;

	pid_t pid = getpid();
	group = task_getgroup(pid);

	st_pjoininfo = pthread_findjoininfo(group, pid);
	if (st_pjoininfo == NULL) {
		printf("pthread_findjoininfo: Fail \n");
		g_bpthreadcallback = false;
		goto err;
	}
	ret_chk = pthread_equal((pid_t)st_pjoininfo->thread, pid);
	if (ret_chk != 1) {
		printf("tc_pthread_pthread_findjoininfo_destroyjoin pthread_equal fail\n");
		g_bpthreadcallback = false;
		goto err;
	}

	pthread_destroyjoin(group, st_pjoininfo);

	st_pjoininfo = pthread_findjoininfo(group, pid);
	if (st_pjoininfo != NULL) {
		printf("pthread_findjoininfo: st_pjoininfo Fail \n");
		g_bpthreadcallback = false;
		goto err;
	}
err:
	pthread_exit(NULL);
	return NULL;
}
Beispiel #5
0
int pthread_join(pthread_t thread, FAR pthread_addr_t *pexit_value)
{
  FAR struct tcb_s *rtcb = this_task();
  FAR struct task_group_s *group = rtcb->group;
  FAR struct join_s *pjoin;
  int ret;

  sdbg("thread=%d group=%p\n", thread, group);
  DEBUGASSERT(group);

  /* First make sure that this is not an attempt to join to
   * ourself.
   */

  if ((pid_t)thread == getpid())
    {
      return EDEADLK;
    }

  /* Make sure no other task is mucking with the data structures
   * while we are performing the following operations.  NOTE:
   * we can be also sure that pthread_exit() will not execute
   * because it will also attempt to get this semaphore.
   */

  (void)pthread_takesemaphore(&group->tg_joinsem);

  /* Find the join information associated with this thread.
   * This can fail for one of three reasons:  (1) There is no
   * thread associated with 'thread,' (2) the thread is a task
   * and does not have join information, or (3) the thread
   * was detached and has exited.
   */

  pjoin = pthread_findjoininfo(group, (pid_t)thread);
  if (!pjoin)
    {
      /* Determine what kind of error to return */

      FAR struct tcb_s *tcb = sched_gettcb((pthread_t)thread);

      sdbg("Could not find thread data\n");

      /* Case (1) or (3) -- we can't tell which.  Assume (3) */

      if (!tcb)
        {
          ret = ESRCH;
        }

      /* The thread is still active but has no join info.  In that
       * case, it must be a task and not a pthread.
       */

      else
        {
          ret = EINVAL;
        }

      (void)pthread_givesemaphore(&group->tg_joinsem);
    }
  else
    {
      /* We found the join info structure.  Increment for the reference
       * to the join structure that we have.  This will keep things
       * stable for we have to do
       */

      sched_lock();
      pjoin->crefs++;

      /* Check if the thread is still running.  If not, then things are
       * simpler.  There are still race conditions to be concerned with.
       * For example, there could be multiple threads executing in the
       * 'else' block below when we enter!
       */

      if (pjoin->terminated)
        {
          sdbg("Thread has terminated\n");

          /* Get the thread exit value from the terminated thread. */

          if (pexit_value)
            {
              sdbg("exit_value=0x%p\n", pjoin->exit_value);
              *pexit_value = pjoin->exit_value;
            }
        }
      else
        {
          sdbg("Thread is still running\n");

          /* Relinquish the data set semaphore.  Since pre-emption is
           * disabled, we can be certain that no task has the
           * opportunity to run between the time we relinquish the
           * join semaphore and the time that we wait on the thread exit
           * semaphore.
           */

          (void)pthread_givesemaphore(&group->tg_joinsem);

          /* Take the thread's thread exit semaphore.  We will sleep here
           * until the thread exits.  We need to exercise caution because
           * there could be multiple threads waiting here for the same
           * pthread to exit.
           */

          (void)pthread_takesemaphore(&pjoin->exit_sem);

          /* The thread has exited! Get the thread exit value */

          if (pexit_value)
            {
             *pexit_value = pjoin->exit_value;
              sdbg("exit_value=0x%p\n", pjoin->exit_value);
            }

          /* Post the thread's data semaphore so that the exiting thread
           * will know that we have received the data.
           */

          (void)pthread_givesemaphore(&pjoin->data_sem);

          /* Retake the join semaphore, we need to hold this when
           * pthread_destroyjoin is called.
           */

          (void)pthread_takesemaphore(&group->tg_joinsem);
        }

      /* Pre-emption is okay now. The logic still cannot be re-entered
       * because we hold the join semaphore
       */

      sched_unlock();

      /* Release our reference to the join structure and, if the reference
       * count decrements to zero, deallocate the join structure.
       */

      if (--pjoin->crefs <= 0)
        {
          (void)pthread_destroyjoin(group, pjoin);
        }

      (void)pthread_givesemaphore(&group->tg_joinsem);
      ret = OK;
    }

  sdbg("Returning %d\n", ret);
  return ret;
}
int pthread_mutex_destroy(FAR pthread_mutex_t *mutex)
{
	struct tcb_s *ptcb;
	struct join_s *pjoin = NULL;
	int ret = EINVAL;
	int status;

	svdbg("mutex=0x%p\n", mutex);
	DEBUGASSERT(mutex != NULL);

	if (mutex != NULL) {

		/* Make sure the semaphore is stable while we make the following checks */

		sched_lock();

		/* Is the semaphore available? */

		if (mutex->pid >= 0) {
			DEBUGASSERT(mutex->pid != 0);	/* < 0: available, >0 owned, ==0 error */
		

			/* No.. Verify that the PID still exists.  We may be destroying
			 * the mutex after cancelling a pthread and the mutex may have
			 * been in a bad state owned by the dead pthread.  NOTE: The
			 * following behavior is unspecified for pthread_mutex_destroy()
			 * (see pthread_mutex_consistent()).
			 *
			 * If the holding thread is still valid, then we should be able to
			 * map its PID to the underlying TCB. That is what sched_gettcb()
			 * does.
			 */

			ptcb = sched_gettcb(mutex->pid);
			if (ptcb && ((ptcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD)) {
				pjoin = pthread_findjoininfo(ptcb->group, ptcb->pid);
			}

			/* In some cases, pthread_mutex_destroy can be executed on middle of
			 * exiting pthread which holds mutex. The sched_releasepid() updates
			 * g_pidhash list to NULL by calling _exit() from pthread_exit().
			 * But, before calling it, pthread_exit() calls pthread_completejoin().
			 * It gives semaphore of pthread_join before executing _exit().
			 * It might cause user call pthread_mutex_destroy before updating scheduler.
			 * Checking pjoin structure and terminated element helps to check
			 * whether pthread which holds mutex is exiting or not.
			 */

			if (ptcb == NULL || \
			   (((ptcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) && (pjoin == NULL || pjoin->terminated == true))) {
				/* The thread associated with the PID no longer exists */

				mutex->pid = -1;

				/* Reset the semaphore.  If threads are were on this
				 * semaphore, then this will awakened them and make
				 * destruction of the semaphore impossible here.
				 */

				status = sem_reset((FAR sem_t *)&mutex->sem, 1);
				if (status < 0) {
					ret = -status;
				}

				/* Check if the reset caused some other thread to lock the
				 * mutex.
				 */
				else if (mutex->pid != -1) {
					/* Yes.. then we cannot destroy the mutex now. */
					ret = EBUSY;
				}

				/* Destroy the underlying semaphore */

				else {
					status = sem_destroy((FAR sem_t *)&mutex->sem);
					ret = (status != OK) ? get_errno() : OK;
				}
			} else {
				ret = EBUSY;
			}
		} else {
			/* Destroy the semaphore
			 *
			 * REVISIT:  What if there are threads waiting on the semaphore?
			 * Perhaps this logic should all sem_reset() first?
			 */

			status = sem_destroy((sem_t *)&mutex->sem);
			ret = ((status != OK) ? get_errno() : OK);
		}

		sched_unlock();
	}

	svdbg("Returning %d\n", ret);
	return ret;
}