static void make_connections(EMBXLB_Transport_t *tplb, EMBXLB_LocalPortHandle_t *phlb, const EMBX_CHAR *portName) { EMBXLB_ConnectBlockList_t *cbl = tplb->connectionRequests; EMBX_BOOL bRefuseConnection = EMBX_FALSE; /* In this transport we can directly access the connect block list, * without any additional locking, as all access to it is via API * calls which are serialized by the driver lock in the API * framework. If this transport had to use another thread to * manage connections then a transport level lock on the block list * would be required for all accesses to the list. */ while(cbl != 0) { EMBXLB_ConnectBlockList_t *next = cbl->next; /* We cannot use the phlb->port.portName member yet as it * hasn't been initialized. */ if(!strcmp(portName, cbl->portName)) { if(bRefuseConnection) { cbl->ev->result = EMBX_CONNECTION_REFUSED; } else { cbl->ev->result = create_remote_port(phlb, cbl->port); /* If we only support single connections then we must refuse any other * connection request for the same port name, assuming the * connection we just tried succeeded. */ if( cbl->ev->result == EMBX_SUCCESS && !tplb->transport.transportInfo.allowsMultipleConnections ) { bRefuseConnection = EMBX_TRUE; } } EMBX_OS_EVENT_POST(&cbl->ev->event); if(cbl->prev != 0) cbl->prev->next = next; else tplb->connectionRequests = next; if(next != 0) next->prev = cbl->prev; EMBX_OS_MemFree(cbl); } cbl = next; } }
static MME_ERROR RemoteTransformer_WaitForMessage(Transformer_t* transformer, MME_Event_t* eventPtr, MME_Command_t** commandPtr) { EMBX_RECEIVE_EVENT event; RemoteTransformer_t* remoteTransformer = (RemoteTransformer_t*)transformer; EMBX_ERROR err; MME_Assert(transformer); MME_Assert(eventPtr); MME_Assert(commandPtr); err = EMBX_ReceiveBlock(remoteTransformer->replyPort.port, &event); if (EMBX_SUCCESS != err) { *eventPtr = MME_COMMAND_COMPLETED_EVT; *commandPtr = NULL; return (err == EMBX_SYSTEM_INTERRUPT ? MME_SYSTEM_INTERRUPT : MME_TRANSFORMER_NOT_RESPONDING); } MME_Assert(event.data); MME_Assert(event.type == EMBX_REC_MESSAGE); /* received message. */ switch (((MME_UINT *) event.data)[0]) { case TMESSID_TRANSFORM: receiveTransformMessage(remoteTransformer, (TransformerTransformMessage *) event.data, eventPtr, commandPtr); freeBuffer(remoteTransformer, event.data); return MME_SUCCESS; case TMESSID_STARVATION: { receiveStavationMessage(remoteTransformer, (TransformerStarvationMessage *) event.data, eventPtr, commandPtr); freeBuffer(remoteTransformer, event.data); return MME_SUCCESS; } case TMESSID_TERMINATE: { /* A Terminate message returned */ remoteTransformer->terminationResult = ((TransformerTerminateMessage *) event.data)->result; MME_Assert(MME_SUCCESS == remoteTransformer->terminationResult); cleanupTerminateMessage(remoteTransformer, (TransformerTerminateMessage *) event.data); *eventPtr = MME_COMMAND_COMPLETED_EVT; *commandPtr = NULL; EMBX_OS_EVENT_POST(&remoteTransformer->terminateWasReplied); return MME_TRANSFORMER_NOT_RESPONDING; } default: MME_Info(MME_INFO_TRANSFORMER, (DEBUG_NOTIFY_STR "Unexpected message: %x\n", (unsigned) ((MME_UINT *) event.data)[0])); MME_Assert(0); } return MME_INTERNAL_ERROR; }
static void terminateExecutionLoops(MMEManager_t *mgr) { int i; for (i=0; i<MME_NUM_EXECUTION_LOOPS; i++) { if (mgr->loopTasksRunning[i]) { mgr->loopTasksRunning[i] = 0; EMBX_OS_EVENT_POST(&(mgr->commandEvents[i])); EMBX_OS_ThreadDelete(mgr->loopTasks[i]); EMBX_OS_EVENT_DESTROY(&(mgr->commandEvents[i])); EMBX_OS_MUTEX_DESTROY(&(mgr->receiverListMutexes[i])); mgr->loopTasks[i] = NULL; mgr->receiverLists[i] = NULL; } } }
/* * Transport method to close an open handle */ static EMBX_ERROR closeHandle (EMBX_Transport_t *tp, EMBX_TransportHandle_t *tph) { EMBXSHM_Transport_t *tpshm = (EMBXSHM_Transport_t *)tp; EMBX_EventState_t *es, *next; EMBX_Info (EMBX_INFO_TRANSPORT, (">>>closeHandle()\n")); EMBX_Assert (tpshm); EMBX_Assert (tph); EMBX_OS_MUTEX_TAKE (&tpshm->connectionListMutex); /* * Unblock processes waiting for a connection through the closing handle */ for (es = tpshm->connectionRequests; es; es = next) { EMBXSHM_ConnectBlockState_t *cbs = es->data; /* match with CBS IN DATA */ next = es->next; if (cbs->requestingHandle == tph) { EMBX_EventListRemove(&tpshm->connectionRequests, es); EMBX_OS_MemFree (cbs); es->result = EMBX_TRANSPORT_CLOSED; EMBX_OS_EVENT_POST (&es->event); } } EMBX_OS_MUTEX_RELEASE (&tpshm->connectionListMutex); /* * Make key handle structures invalid to help catch use after close */ tph->state = EMBX_HANDLE_CLOSED; tph->transport = 0; EMBX_OS_MemFree (tph); EMBX_OS_MODULE_UNREF(); EMBX_Info (EMBX_INFO_TRANSPORT, ("<<<closeHandle = EMBX_SUCCESS\n")); return EMBX_SUCCESS; }
static void unblockWaitors(RemoteTransformer_t* remoteTransformer, MME_Event_t event, CommandSlot_t* command) { HostManager_t* manager = MMEGetManager(); /* Lock whilst this thread does event notification */ MME_Assert(manager); EMBX_OS_MUTEX_TAKE(&manager->eventLock); manager->eventTransformer = remoteTransformer; manager->eventCommand = command; manager->eventCommandType = event; EMBX_OS_EVENT_POST(command->waitor); EMBX_OS_EVENT_WAIT(&manager->waitorDone); EMBX_OS_MUTEX_RELEASE(&manager->eventLock); }
static EMBX_ERROR do_close_transport(EMBX_TRANSPORT htp) { EMBX_ERROR res = EMBX_INVALID_TRANSPORT; EMBX_TransportHandle_t *tph; tph = (EMBX_TransportHandle_t *)EMBX_HANDLE_GETOBJ(&_embx_handle_manager, htp); if(tph != 0) { EMBX_Transport_t *tp; EMBX_TransportHandleList_t *handleList; if( (tph->state != EMBX_HANDLE_VALID) && (tph->state != EMBX_HANDLE_INVALID) ) { EMBX_DebugMessage(("Failed 'transport handle state is corrupted'\n")); return EMBX_INVALID_TRANSPORT; } if( (tph->localPorts != 0) || (tph->remotePorts != 0) ) { EMBX_DebugMessage(("Failed 'transport still has open ports'\n")); return EMBX_PORTS_STILL_OPEN; } tp = tph->transport; handleList = tp->transportHandles; while(handleList) { if(handleList->transportHandle == tph) break; handleList = handleList->next; } #if defined(EMBX_VERBOSE) if(handleList == 0) { EMBX_DebugMessage(("Unable to find transport handle (0x%08lx) on transport (0x%08lx) handle list!\n",(unsigned long)tph,(unsigned long)tp)); } #endif /* EMBX_VERBOSE */ res = tp->methods->close_handle(tp, tph); if(res == EMBX_SUCCESS) { /* At this point tph has been freed by the transport * so we must not use it again. */ EMBX_HANDLE_FREE(&_embx_handle_manager, htp); tp->transportInfo.nrOpenHandles--; /* Unhook the transport handle list entry */ if(handleList != 0) { if(handleList->prev != 0) handleList->prev->next = handleList->next; else tp->transportHandles = handleList->next; if(handleList->next != 0) handleList->next->prev = handleList->prev; EMBX_OS_MemFree(handleList); } if(tp->closeEvent != 0 && tp->transportHandles == 0) { /* Another thread is waiting for the last handle to * close on this transport. Signal it now this has * happened. */ EMBX_OS_EVENT_POST(&tp->closeEvent->event); } } } return res; }
/* * Helper function to kill off any worker threads started * by the transport. This is used in closedown and to tidy * up initialization if it fails. */ EMBX_ERROR EMBXSHM_killThread (EMBXSHM_Transport_t *tpshm, EMBX_UINT threadName) { EMBX_ERROR res = EMBX_SUCCESS; EMBX_Info (EMBX_INFO_TRANSPORT, (">>>EMBXSHM_killThread()\n")); switch (threadName) { case EMBXSHM_NEWPORT_WORKER: { if(tpshm->locksValid && tpshm->secondHalfDieFlag == 0) { tpshm->secondHalfDieFlag = 1; EMBX_OS_EVENT_POST (&tpshm->secondHalfEvent); } if (tpshm->secondHalfThread != EMBX_INVALID_THREAD) { res = EMBX_OS_ThreadDelete(tpshm->secondHalfThread); if (res == EMBX_SUCCESS) { tpshm->secondHalfThread = EMBX_INVALID_THREAD; } } tpshm->secondHalfDieFlag = 0; break; } /* EMBXSHM_NEWPORT_WORKER */ case EMBXSHM_CLOSEPORT_WORKER: { if(tpshm->locksValid && tpshm->closedPortDieFlag == 0) { tpshm->closedPortDieFlag = 1; EMBX_OS_EVENT_POST (&tpshm->closedPortEvent); } if (tpshm->closedPortThread != EMBX_INVALID_THREAD) { res = EMBX_OS_ThreadDelete(tpshm->closedPortThread); if (res == EMBX_SUCCESS) { tpshm->closedPortThread = EMBX_INVALID_THREAD; } } tpshm->closedPortDieFlag = 0; break; } /* EMBXSHM_CLOSEPORT_WORKER */ default: { EMBX_Assert(0); res = EMBX_INVALID_ARGUMENT; } /* default */ } EMBX_Info (EMBX_INFO_TRANSPORT, ("<<<EMBXSHM_killThread\n")); return res; }
/* * Transport method to invalidate a transport */ static EMBX_VOID invalidate (EMBX_Transport_t *tp) { EMBXSHM_Transport_t *tpshm = (EMBXSHM_Transport_t *)tp; EMBX_TransportHandleList_t *thandles = tpshm->transport.transportHandles; EMBX_Info (EMBX_INFO_TRANSPORT, (">>>invalidate()\n")); EMBX_Assert (tpshm); /* * Tell the other CPUs we are about to invalidate the transport. */ if (!tpshm->remoteInvalidateFlag) { EMBXSHM_PipeElement_t element; int i; element.control = EMBXSHM_PIPE_CTRL_TRANSPORT_INVALIDATE; for (i=0; i<EMBXSHM_MAX_CPUS; i++) { if (i != tpshm->cpuID && tpshm->participants[i]) { EMBX_ERROR err; /* * We are already part way through the operation so we'll * keep trying to repost until we manage it. */ while (EMBX_SUCCESS != (err = EMBXSHM_enqueuePipeElement (tpshm, i, &element))) { EMBX_Assert (EMBX_NOMEM == err); EMBX_OS_Delay(10); } } } } thandles = tpshm->transport.transportHandles; /* * First of all wake up any pending connection requests */ EMBX_OS_MUTEX_TAKE (&tpshm->connectionListMutex); while (tpshm->connectionRequests) { EMBX_EventState_t *es = EMBX_EventListFront(&tpshm->connectionRequests); EMBX_OS_MemFree(es->data); /* match with CBS IN DATA */ /* * When we post this event we have effectively freed es, it must not be used again */ EMBX_OS_EVENT_POST (&es->event); } EMBX_OS_MUTEX_RELEASE (&tpshm->connectionListMutex); /* * Now go and deal with still open transport handles */ while (thandles) { EMBXSHM_TransportHandle_t *th = (EMBXSHM_TransportHandle_t *)thandles->transportHandle; doInvalidateHandle (th); thandles = thandles->next; } EMBX_Info (EMBX_INFO_TRANSPORT, ("<<<invalidate\n")); }
static EMBX_ERROR do_send(EMBXLB_RemotePortHandle_t *phlb , EMBX_RECEIVE_TYPE evtype, EMBX_HANDLE handle, EMBX_VOID *data , EMBX_UINT offset, EMBX_UINT size ) { if(phlb->destination->blocked_receivers != 0) { EMBXLB_RecBlockList_t *receiver; /* Pick the first blocked receiver and put the object event info * directly into its receive event structure, then signal it to * wake up. */ receiver = phlb->destination->blocked_receivers; phlb->destination->blocked_receivers = receiver->next; receiver->recev->handle = handle; receiver->recev->data = data; receiver->recev->offset = offset; receiver->recev->size = size; receiver->recev->type = evtype; receiver->ev->result = EMBX_SUCCESS; EMBX_OS_EVENT_POST(&receiver->ev->event); EMBX_OS_MemFree(receiver); } else { EMBXLB_RecEventList_t *node; /* Nobody is waiting for the message so we have to queue it * on the destination */ node = (EMBXLB_RecEventList_t *)EMBX_OS_MemAlloc(sizeof(EMBXLB_RecEventList_t)); if(node == 0) return EMBX_NOMEM; node->recev.handle = handle; node->recev.data = data; node->recev.offset = offset; node->recev.size = size; node->recev.type = evtype; node->next = 0; if(phlb->destination->pending_head != 0) { phlb->destination->pending_tail->next = node; phlb->destination->pending_tail = node; } else { phlb->destination->pending_tail = node; phlb->destination->pending_head = node; } } return EMBX_SUCCESS; }
MME_ERROR MME_SendCommand(MME_TransformerHandle_t handle, MME_Command_t * commandInfo) { Transformer_t *transformer; MME_ERROR result; CommandSlot_t *commandPrivate; #ifndef MME_LEAN_AND_MEAN if (manager == NULL) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Driver not initialized\n")); return MME_DRIVER_NOT_INITIALIZED; /* the manager must exist */ } if (0 == handle) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Invalid handle - NULL\n")); return MME_INVALID_HANDLE; } if (NULL == commandInfo || commandInfo->StructSize != sizeof(MME_Command_t)) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Invalid struct size\n")); return MME_INVALID_ARGUMENT; } if (commandInfo->CmdCode != MME_SET_GLOBAL_TRANSFORM_PARAMS && commandInfo->CmdCode != MME_TRANSFORM && commandInfo->CmdCode != MME_SEND_BUFFERS) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Invalid command code\n")); return MME_INVALID_ARGUMENT; } if (commandInfo->CmdEnd != MME_COMMAND_END_RETURN_NO_INFO && commandInfo->CmdEnd != MME_COMMAND_END_RETURN_NOTIFY) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Invalid command notify type\n")); return MME_INVALID_ARGUMENT; } #endif EMBX_OS_MUTEX_TAKE(&manager->monitorMutex); result = findTransformerInstance(handle, &transformer); if (result != MME_SUCCESS) { /* cannot find transformer for this handle */ MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Cannot find transformer with handle 0x%08x\n", handle)); result = MME_INVALID_HANDLE; goto EXIT; } result = transformer->vtable->sendCommand(transformer, commandInfo, &commandPrivate); #ifdef ENABLE_MME_WAITCOMMAND /* Wake up any thread waiting for new commands with MME_WaitCommand or place the new command in a 1-deep buffer for thread that is about to wait */ /* Grab this mutex to prevent any command completion events from fiddling with the manager event state */ EMBX_OS_MUTEX_TAKE(&manager->eventLock); if (manager->newCommandEvents) { /* One or more threads waiting for a new command event */ int i, waitors=0; NewCommand_t* current; manager->eventTransformer = transformer; manager->eventCommand = commandPrivate; manager->eventCommandType = MME_NEW_COMMAND_EVT; current = manager->newCommandEvents; while (current) { waitors++; EMBX_OS_EVENT_POST(current->event); current = current->next; } for (i=0; i<waitors; i++) { /* Wait for the last waitor thread to unblock and remove it's event */ EMBX_OS_EVENT_WAIT(&manager->waitorDone); } /* All waitor threads have let us know they have dealt with new event - now remove them from the list */ RemoveNewCommandEvents_HostManager(); manager->newCommand = NULL; manager->newCommandTransformer = NULL; } else { manager->newCommand = commandInfo; manager->newCommandTransformer = transformer; } EMBX_OS_MUTEX_RELEASE(&manager->eventLock); #endif EXIT: EMBX_OS_MUTEX_RELEASE(&manager->monitorMutex); MME_Info( MME_INFO_MANAGER, (DEBUG_NOTIFY_STR "<<<< (%d)\n", result)); return result; }