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; }
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; }