/*********************************************************** * Name: os_cond_wait * * Arguments: OS_COND_T *cond, * OS_SEMAPHORE_T *semaphore * * Description: Routine to wait for a condition variable * to be signalled. Semaphore is released * while waiting. The same semaphore must * always be used. * * Returns: int32_t - success == 0 * ***********************************************************/ int32_t os_cond_wait( OS_COND_T *cond, OS_SEMAPHORE_T *semaphore ) { int32_t success = -1; if (cond && semaphore) { COND_WAITER_T w; COND_WAITER_T *p, **prev; // Check the API is being followed os_assert((*cond)->semaphore == semaphore && os_semaphore_obtained(semaphore)); // Fill in a new waiter structure allocated on our stack w.next = NULL; vcos_demand(vcos_event_create(&w.latch, NULL) == VCOS_SUCCESS); // Add it to the end of the condvar's wait queue (we wake first come, first served) prev = &(*cond)->waiters; p = (*cond)->waiters; while (p) prev = &p->next, p = p->next; *prev = &w; // Ready to go to sleep now success = os_semaphore_release(semaphore); os_assert(success == 0); vcos_event_wait(&w.latch); success = os_semaphore_obtain(semaphore); os_assert(success == 0); } return success; }
//Unlock the host state static void lock_release (void) { int32_t success; vcos_assert(cecservice_client.initialised); vcos_assert(os_semaphore_obtained(&cecservice_client.sema)); success = os_semaphore_release( &cecservice_client.sema ); vcos_assert( success >= 0 ); }
/* ---------------------------------------------------------------------- * called from the vchi layer whenever an event happens. * here, we are only interested in the 'message available' callback * -------------------------------------------------------------------- */ static void vc_ilcs_callback( void *callback_param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle ) { int32_t success; OS_SEMAPHORE_T *sem; switch( reason ) { case VCHI_CALLBACK_MSG_AVAILABLE: sem = (OS_SEMAPHORE_T *)callback_param; if ( sem == NULL ) break;; if ( os_semaphore_obtained(sem) ) { success = os_semaphore_release( sem ); assert( success >= 0 ); } break; #if 0 case VCHI_CALLBACK_BULK_RECEIVED: case VCHI_CALLBACK_BULK_SENT: sem = (OS_SEMAPHORE_T *)msg_handle; success = os_semaphore_release( sem ); assert( success >= 0 ); break; #endif } }
void ThreadCheck() { VCOS_THREAD_T thread; // First create a sync semaphore TEST_OK("os_semaphore_create", os_semaphore_create(&sem1, OS_SEMAPHORE_TYPE_SUSPEND)); // and grab it TEST_OK("os_semaphore_obtain", os_semaphore_obtain(&sem1)); // Start the thread which shuold stall on the semaphore TEST_OK("os_thread_start", os_thread_start( &thread, &ThreadOne, NULL, 1000, "ThreadOne")); // Wait for thread to start for 1000 - should stall on semaphore and not change flag TEST_OK("os_delay", os_delay(1000)); // Check global data is unchanged TEST_OK("Flag = 0", flag); // release semaphore TEST_OK("os_semaphore_release", os_semaphore_release(&sem1)); // Wait for thread to continue for 100 - should be enough for it to set the flag TEST_OK("os_delay", os_delay(100)); // Check global data is changed to non-zero TEST_OK("Flag = 1", (flag == 0)); // Semaphore is currently released, so check the obtained function is correct. TEST_OK("os_semaphore_obtained - 0", os_semaphore_obtained(&sem1)) // now get the sema and test again TEST_OK("os_semaphore_obtain", os_semaphore_obtain(&sem1)); TEST_OK("os_semaphore_obtained - 1", (os_semaphore_obtained(&sem1) == 0)) TEST_OK("os_semaphore_release", os_semaphore_release(&sem1)); }
/*********************************************************** * Name: hostreq_client_callback * * Arguments: semaphore, callback reason and message handle * * Description: VCHI callback for the HOSTREQ service * ***********************************************************/ static void hostreq_client_callback( void *callback_param, const VCHI_CALLBACK_REASON_T reason, void *msg_handle ) { OS_SEMAPHORE_T *sem = (OS_SEMAPHORE_T *)callback_param; if ( reason != VCHI_CALLBACK_MSG_AVAILABLE ) return; if ( sem == NULL ) return; if ( os_semaphore_obtained(sem) ) { int32_t success = os_semaphore_release( sem ); assert( success >= 0 ); } }
static void lock_release (void) { int32_t success; assert(os_semaphore_obtained(&gencmd_client.sema)); success = os_semaphore_release( &gencmd_client.sema ); assert( success >= 0 ); }
/* ---------------------------------------------------------------------- * send a string to the host side IL component service. if resp is NULL * then there is no response to this call, so we should not wait for one. * * returns response, written to 'resp' pointer * -------------------------------------------------------------------- */ void vc_ilcs_execute_function( IL_FUNCTION_T func, void *data, int len, void *data2, int len2, void *resp, int resplen ) { VC_ILCS_WAIT_T *wait; int num; // the host MUST receive a response assert( resp ); // need to atomically find free ->wait entry os_semaphore_obtain( &vc_ilcsg.wait_sem ); for (;;) { num = 0; while( num < VC_ILCS_MAX_WAITING && vc_ilcsg.wait[num].resp ) num++; if ( num < VC_ILCS_MAX_WAITING ) break; assert( num < VC_ILCS_MAX_WAITING ); // might be a fatal error if another thread is relying // on this call completing before it can complete // we'll pause until we can carry on and hope that's sufficient. os_semaphore_release( &vc_ilcsg.wait_sem ); os_sleep( 10 ); // 10 msec os_semaphore_obtain( &vc_ilcsg.wait_sem ); } wait = &vc_ilcsg.wait[num]; wait->resp = resp; wait->xid = vc_ilcsg.next_xid++; os_semaphore_create( &wait->sem, OS_SEMAPHORE_TYPE_SUSPEND ); os_semaphore_obtain( &wait->sem ); // at this point, ->wait is exclusively ours () os_semaphore_release( &vc_ilcsg.wait_sem ); // write the command header. vc_ilcs_transmit( func, wait->xid, data, len, data2, len2 ); if ( !os_thread_current(vc_ilcsg.thread) ) { os_semaphore_obtain( &wait->sem ); } else { // we're the vcilcs task, so wait for, and handle, incoming // messages while we're not completed for (;;) { // wait->sem will not be released until we process the response message if ( vc_ilcs_process_message() == 0 ) { // there were no more messages in the fifo; need to wait os_semaphore_obtain( &vc_ilcsg.rxmsg_sem ); continue; } // did the last message release wait->sem ? if ( !os_semaphore_obtained(&wait->sem) ) break; } } // safe to do the following - the assignment of NULL is effectively atomic os_semaphore_destroy( &wait->sem ); wait->resp = NULL; }
/* ---------------------------------------------------------------------- * send a string to the host side IL component service. if resp is NULL * then there is no response to this call, so we should not wait for one. * * returns 0 on successful call made, -1 on failure to send call. * on success, the response is written to 'resp' pointer * -------------------------------------------------------------------- */ int vc_ilcs_execute_function( IL_FUNCTION_T func, void *data, int len, void *data2, int len2, void *bulk, int bulk_len, void *resp ) { VC_ILCS_WAIT_T *wait; int i, num; // the host MUST receive a response vc_assert( resp ); // need to atomically find free ->wait entry os_semaphore_obtain( &vc_ilcsg.wait_sem ); // we try a number of times then give up with an error message // rather than just deadlocking for (i=0; i<VC_ILCS_WAIT_TIMEOUT; i++) { num = 0; while( num < VC_ILCS_MAX_WAITING && vc_ilcsg.wait[num].resp ) num++; if ( num < VC_ILCS_MAX_WAITING || i == VC_ILCS_WAIT_TIMEOUT-1) break; // might be a fatal error if another thread is relying // on this call completing before it can complete // we'll pause until we can carry on and hope that's sufficient. os_semaphore_release( &vc_ilcsg.wait_sem ); os_sleep( 10 ); // 10 msec // if we're the vcilcs thread, then the waiters might need // us to handle their response, so try and clear those now if(os_thread_is_running(&vc_ilcsg.thread)) while(vc_ilcs_process_message(0)); os_logging_message( "%s: wait for sem", __FUNCTION__); os_semaphore_obtain( &vc_ilcsg.wait_sem ); } if(num == VC_ILCS_MAX_WAITING) { // failed to send message. vc_assert(0); os_semaphore_release( &vc_ilcsg.wait_sem ); return -1; } wait = &vc_ilcsg.wait[num]; wait->resp = resp; wait->xid = vc_ilcsg.next_xid++; os_semaphore_create( &wait->sem, OS_SEMAPHORE_TYPE_SUSPEND ); os_semaphore_obtain( &wait->sem ); // at this point, ->wait is exclusively ours () os_semaphore_release( &vc_ilcsg.wait_sem ); if(bulk) os_semaphore_obtain( &vc_ilcsg.send_sem); // write the command header. vc_ilcs_transmit( func, wait->xid, data, len, data2, len2 ); if(bulk) { int result; result = vchi_bulk_queue_transmit( vc_ilcsg.vchi_handle, // call to VCHI bulk, bulk_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ); vc_assert(result == 0); os_semaphore_release( &vc_ilcsg.send_sem); } if ( !os_thread_is_running(&vc_ilcsg.thread) ) { os_semaphore_obtain( &wait->sem ); } else { // we're the vcilcs task, so wait for, and handle, incoming // messages while we're not completed for (;;) { // wait->sem will not be released until we process the response message vc_ilcs_process_message(1); // did the last message release wait->sem ? if ( !os_semaphore_obtained(&wait->sem) ) break; } } // safe to do the following - the assignment of NULL is effectively atomic os_semaphore_destroy( &wait->sem ); wait->resp = NULL; return 0; }
//Unlock the host state static void lock_release (void) { assert(hostreq_client.initialised); assert(os_semaphore_obtained(&hostreq_client.sema)); int32_t success = os_semaphore_release(&hostreq_client.sema); assert( success >= 0 ); }
//Lock the host state static void lock_obtain (void) { assert(hostreq_client.initialised); assert(!os_semaphore_obtained(&hostreq_client.sema)); int success = os_semaphore_obtain(&hostreq_client.sema); assert(success >= 0); }