/* Wait for a condition, putting thread into blocked state. Fails if: - condp has not been initialized - thread doesn't hold mutexp - thread is blocked on some other object - thread is already blocked on mutex */ void VG_(tm_cond_wait)(ThreadId tid, Addr condp, Addr mutexp) { struct thread *th = thread_get(tid); struct mutex *mx; struct condvar *cv; struct condvar_waiter *waiter; /* Condvar must exist */ cv = condvar_check_initialized(tid, condp, "waiting"); /* Mutex must exist */ mx = mutex_check_initialized(tid, mutexp, "waiting on condvar"); /* Thread must own mutex */ if (mx->state != MX_Locked) { mutex_report(tid, mutexp, MXE_NotLocked, "waiting on condvar"); VG_(tm_mutex_trylock)(tid, mutexp); VG_(tm_mutex_acquire)(tid, mutexp); } else if (mx->owner != tid) { mutex_report(tid, mutexp, MXE_NotOwner, "waiting on condvar"); mx->owner = tid; } /* Thread must not be already waiting for condvar */ waiter = get_waiter(cv, tid); if (waiter != NULL) condvar_report(tid, condp, CVE_Blocked, "waiting"); else { waiter = VG_(arena_malloc)(VG_AR_CORE, sizeof(*waiter)); waiter->condvar = cv; waiter->mutex = mx; waiter->next = cv->waiters; cv->waiters = waiter; } /* Thread is now blocking on condvar */ do_thread_block_condvar(th, cv); /* (half) release mutex */ VG_(tm_mutex_tryunlock)(tid, mutexp); }
/** Send a message and wait for a reply. * * @param client client to send message for * @param msg_header message vchiq_header to send * @param size length of message, including header * @param msgid message id * @param dest destination for reply * @param destlen size of destination, updated with actual length * @param send_dummy_bulk whether to send a dummy bulk transfer */ MMAL_STATUS_T mmal_vc_sendwait_message(struct MMAL_CLIENT_T *client, mmal_worker_msg_header *msg_header, size_t size, uint32_t msgid, void *dest, size_t *destlen, MMAL_BOOL_T send_dummy_bulk) { MMAL_STATUS_T ret; MMAL_WAITER_T *waiter; VCHIQ_STATUS_T vst; VCHIQ_ELEMENT_T elems[] = {{msg_header, size}}; vcos_assert(size >= sizeof(mmal_worker_msg_header)); vcos_assert(dest); if (!client->inited) { vcos_assert(0); return MMAL_EINVAL; } if (send_dummy_bulk) vcos_mutex_lock(&client->bulk_lock); waiter = get_waiter(client); msg_header->msgid = msgid; msg_header->u.waiter = waiter; msg_header->magic = MMAL_MAGIC; waiter->dest = dest; waiter->destlen = *destlen; LOG_TRACE("wait %p, reply to %p", waiter, dest); mmal_vc_use_internal(client); vst = vchiq_queue_message(client->service, elems, 1); if (vst != VCHIQ_SUCCESS) { ret = MMAL_EIO; if (send_dummy_bulk) vcos_mutex_unlock(&client->bulk_lock); goto fail_msg; } if (send_dummy_bulk) { uint32_t data_size = 8; /* The data is just some dummy bytes so it's fine for it to be static */ static uint8_t data[8]; vst = vchiq_queue_bulk_transmit(client->service, data, data_size, msg_header); vcos_mutex_unlock(&client->bulk_lock); if (!vcos_verify(vst == VCHIQ_SUCCESS)) { LOG_ERROR("failed bulk transmit"); /* This really should not happen and if it does, things will go wrong as * we've already queued the vchiq message above. */ vcos_assert(0); ret = MMAL_EIO; goto fail_msg; } } /* now wait for the reply... * * FIXME: we could do with a timeout here. Need to be careful to cancel * the semaphore on a timeout. */ vcos_semaphore_wait(&waiter->sem); mmal_vc_release_internal(client); LOG_TRACE("got reply (len %i/%i)", (int)*destlen, (int)waiter->destlen); *destlen = waiter->destlen; release_waiter(client, waiter); return MMAL_SUCCESS; fail_msg: mmal_vc_release_internal(client); release_waiter(client, waiter); return ret; }
bool dismiss_wait(waiter* ) { auto w = get_waiter(); return w == 0 || ( w != signaled && state.compare_exchange_strong(w, empty)); }
bool try_wait(waiter * w) { assert(w); auto old_w = get_waiter(); return (old_w != signaled && state.compare_exchange_strong(old_w, w)); }