Example #1
0
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;
}
Example #2
0
int vnc_update_rectangle(FAR struct vnc_session_s *session,
                         FAR const struct nxgl_rect_s *rect, bool change)
{
  FAR struct vnc_fbupdate_s *update;
  struct nxgl_rect_s intersection;
  bool whupd;

  /* Clip rectangle to the screen dimensions */

  nxgl_rectintersect(&intersection, rect, &g_wholescreen);

  /* Make sure that the clipped rectangle has a area */

  if (!nxgl_nullrect(&intersection))
    {
      /* Check for a whole screen update.  The RealVNC client sends a lot
       * of these (especially when it is confused)
       */

      whupd = (memcmp(&intersection, &g_wholescreen,
                      sizeof(struct nxgl_rect_s)) == 0);

      /* Ignore any client update requests if there have been no changes to
       * the framebuffer since the last whole screen update.
       */

      sched_lock();
      if (!change && !session->change)
        {
          /* No.. ignore the client update.  We have nothing new to report. */

          sched_unlock();
          return OK;
        }

      /* Ignore all updates if there is a queued whole screen update */

      if (session->nwhupd == 0)
        {
          /* No whole screen updates in the queue.  Is this a new whole
           * screen update?
           */

          if (whupd)
            {
              /* Yes.. Discard all of the previously queued updates */

              FAR struct vnc_fbupdate_s *curr;
              FAR struct vnc_fbupdate_s *next;

              updvdbg("New whole screen update...\n");

              curr = (FAR struct vnc_fbupdate_s *)session->updqueue.head;
              sq_init(&session->updqueue);
              sem_reset(&session->queuesem, 0);

              for (; curr != NULL; curr = next)
                {
                  next = curr->flink;
                  vnc_free_update(session, curr);
                }

              /* One whole screen update will be queued.  There have been
               * no frame buffer data changes since this update was queued.
               */

              session->nwhupd = 1;
              session->change = false;
            }
          else
            {
              /* We are not updating the whole screen.  Remember if this
               * update (OR a preceding update) was due to a data change.
               */

              session->change |= change;
            }

          /* Allocate an update structure... waiting if necessary */

          update = vnc_alloc_update(session);
          DEBUGASSERT(update != NULL);

          /* Copy the clipped rectangle into the update structure */

          update->whupd = whupd;
          nxgl_rectcopy(&update->rect, &intersection);

          /* Add the upate to the end of the update queue. */

          vnc_add_queue(session, update);

          updvdbg("Queued {(%d, %d),(%d, %d)}\n",
                  intersection.pt1.x, intersection.pt1.y,
                  intersection.pt2.x, intersection.pt2.y);
        }

      sched_unlock();
    }

  /* Since we ignore bad rectangles and wait for updata structures, there is
   * really no way a failure can occur.
   */

  return OK;
}