/* ---------------------------------------------------------------------- * tear down data structures, and free memory, associated with * the given non-wrap fifo handle * * returns 0 on success, non-0 otherwise * -------------------------------------------------------------------- */ int32_t non_wrap_fifo_destroy( VCHI_NWFIFO_T *_fifo ) { NON_WRAP_FIFO_HANDLE_T *fifo = (NON_WRAP_FIFO_HANDLE_T *)_fifo; int32_t success = -1; // first confirm that the handle has been previously allocated if ( fifo->base_address ) { // free the FIFO memory free( fifo->malloc_address ); // free the slot info memory free( fifo->slot_info ); // destroy the os signalling os_cond_destroy( &fifo->space_available_cond ); os_semaphore_destroy( &fifo->sem ); // free the structure free( fifo ); // success! success = 0; } return success; }
/* ---------------------------------------------------------------------- * 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; }