MME_ERROR MME_KillTransformer(MME_TransformerHandle_t handle) { Transformer_t *transformer; MME_ERROR res; #ifndef MME_LEAN_AND_MEAN if (NULL == manager) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Driver not initialized\n")); return MME_DRIVER_NOT_INITIALIZED; /* the manager must exist */ } #endif EMBX_OS_MUTEX_TAKE(&manager->monitorMutex); /* Find the transformer */ res = findTransformerInstance(handle, &transformer); if (res != MME_SUCCESS) { EMBX_OS_MUTEX_RELEASE(&manager->monitorMutex); MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Failed to find transformer instance\n")); return MME_INVALID_HANDLE; } res = transformer->vtable->kill(transformer); if (MME_SUCCESS == res) { deregisterTransformerInstance(handle); transformer->vtable->destroy(transformer); } EMBX_OS_MUTEX_RELEASE(&manager->monitorMutex); return res; }
MME_ERROR MME_HostTerm(void) #endif { TransportInfo_t *tpInfo, *next; #ifndef MME_LEAN_AND_MEAN if (manager == NULL) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Failed to find transformer instance\n")); return MME_DRIVER_NOT_INITIALIZED; } #endif if (!MME_LookupTable_IsEmpty(manager->transformerInstances)) { /* Need to close all transformers first */ MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Handles still open\n")); return MME_HANDLES_STILL_OPEN; } /* Deregister all the transports (so that the companions receive terminate messages) */ for (tpInfo = manager->transportList; tpInfo && (next = tpInfo->next, 1); tpInfo = next) { destroyTransportInfo(tpInfo); } EMBX_OS_MUTEX_DESTROY(&manager->monitorMutex); EMBX_OS_MUTEX_DESTROY(&manager->eventLock); EMBX_OS_EVENT_DESTROY(&manager->waitorDone); MME_LookupTable_Delete(manager->transformerInstances); EMBX_OS_MemFree(manager); manager = NULL; return MME_SUCCESS; }
MME_ERROR MME_MessageQueue_Dequeue(MMEMessageQueue * msgQ, void **message) { MMEMessageQueueEntry *entry; MME_Info(MME_INFO_QUEUE, (">>>MME_MessageQueue_Dequeue(0x%08x, ...)\n", (unsigned) msgQ)); sortMessageQueue(msgQ); EMBX_OS_MUTEX_TAKE(&msgQ->queueLock); /* dequeue the first message */ entry = msgQ->sorted_front; if (NULL == entry) { *message = NULL; MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Dequeue(..., 0x%08x) = MME_INVALID_HANDLE\n", (unsigned) *message)); EMBX_OS_MUTEX_RELEASE(&msgQ->queueLock); return MME_INVALID_HANDLE; } msgQ->sorted_front = entry->next; /* push it onto the free list */ entry->next = msgQ->free_list; msgQ->free_list = entry; *message = entry->message; MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Dequeue(..., 0x%08x) = MME_SUCCESS\n", (unsigned) *message)); EMBX_OS_MUTEX_RELEASE(&msgQ->queueLock); return MME_SUCCESS; }
MME_ERROR MME_MessageQueue_RemoveAll(MMEMessageQueue * msgQ) { MMEMessageQueueEntry **prev; int i; MME_Info(MME_INFO_QUEUE, (">>>MME_MessageQueue_RemoveAll(0x%08x)\n", (unsigned) msgQ)); MME_Assert(msgQ); MME_Assert(msgQ->maxEntries > 0); EMBX_OS_MUTEX_TAKE(&msgQ->queueLock); /* initialize the free list */ for (prev = &(msgQ->free_list), i=0; i < msgQ->maxEntries; prev = &(msgQ->queue[i].next), i++) { *prev = &(msgQ->queue[i]); } *prev = NULL; msgQ->sorted_front = 0; msgQ->unsorted_front = 0; EMBX_OS_MUTEX_RELEASE(&msgQ->queueLock); MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_RemoveAll = MME_SUCCESS\n")); return MME_SUCCESS; }
MME_ERROR MME_MessageQueue_Init(MMEMessageQueue * msgQ, int maxEntries) { MME_ERROR err; int size = maxEntries * sizeof(MMEMessageQueueEntry); MME_Info(MME_INFO_QUEUE, (">>>MME_MessageQueue_Init(0x%08x, %d)\n", (unsigned) msgQ, maxEntries)); msgQ->maxEntries = maxEntries; msgQ->queue = (MMEMessageQueueEntry*) EMBX_OS_MemAlloc(size); if (msgQ->queue == NULL) { MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Init = MME_NOMEM\n")); return MME_NOMEM; } memset(msgQ->queue, 0, size); if (!EMBX_OS_MUTEX_INIT(&msgQ->queueLock)) { MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Init = MME_NOMEM\n")); return MME_NOMEM; } err = MME_MessageQueue_RemoveAll(msgQ); MME_Assert(MME_SUCCESS == err); /* currently has no failure path */ MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Init = MME_SUCCESS\n")); return MME_SUCCESS; }
/* Clean up and deallocate everything. */ void MME_MessageQueue_Term(MMEMessageQueue * msgQ) { MME_Info(MME_INFO_QUEUE, (">>>MME_MessageQueue_Term(0x%08x)\n", (unsigned) msgQ)); EMBX_OS_MUTEX_DESTROY(&msgQ->queueLock); if (msgQ->queue != NULL) { EMBX_OS_MemFree(msgQ->queue); } memset(msgQ, 0, sizeof(*msgQ)); MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Term\n")); }
MME_ERROR MME_Deinit(void) { EMBX_ERROR err; int i; if (manager == NULL) { return MME_DRIVER_NOT_INITIALIZED; } MME_Info(MME_INFO_MANAGER, ("TerminateMMEManager...\n")); /* We cannot terminate if there is any receiver * * TODO: this is not thread-safe (and the receiver list locks are no * good here). we really need request the manager thread perform the * shutdown, the same code would be safe there! */ for (i=0; i<MME_NUM_EXECUTION_LOOPS; i++) { if (NULL != manager->receiverLists[i]) { MME_Info(MME_INFO_MANAGER, ("Cannot terminate MMEManager, receiverList isn't empty\n")); return MME_COMMAND_STILL_EXECUTING; /* potentially, this is true */ } } /* reap all the execution loop threads */ terminateExecutionLoops(manager); /* TODO: there should normally be no need to reap the thread since it this code * should refuse to run if MME_Run() is still active. */ manager->managerRunning = 0; /* TODO: this cleanup should be delegated to MME_DeregisterTransport() */ /* Close the administration port. */ MME_Info(MME_INFO_MANAGER, ("Invalidate adminPort...\n")); err = EMBX_InvalidatePort(manager->adminPort); MME_Info(MME_INFO_MANAGER, ("Invalidate adminPort...err %d\n", err)); MME_Info(MME_INFO_MANAGER, ("Close adminPort...\n")); err = EMBX_ClosePort(manager->adminPort); MME_Info(MME_INFO_MANAGER, ("Close adminPort...err %d\n", err)); /* Close the transport and EMBX. */ MME_Info(MME_INFO_MANAGER, ("Close Transport...\n")); err = EMBX_CloseTransport(manager->transportHandle); MME_Info(MME_INFO_MANAGER, ("EMBX_CloseTransport() - handle %d\n", manager->transportHandle)); if (err != EMBX_SUCCESS) { MME_Info(MME_INFO_MANAGER, ("EMBX_CloseTransport() failed, error=%d\n", err)); } /* Delete the mutex. */ EMBX_OS_MUTEX_DESTROY(&(manager->factoryListMutex)); EMBX_OS_MUTEX_DESTROY(&(manager->abortMutex)); EMBX_OS_MemFree(manager); manager = NULL; return MME_SUCCESS; }
MME_ERROR MME_HostRegisterTransport(const char *name) #endif { MME_ERROR res; EMBX_ERROR err; TransportInfo_t *tpInfo = 0; #ifndef MME_LEAN_AND_MEAN if (manager == NULL) { MME_Info(MME_INFO_MANAGER, (DEBUG_ERROR_STR "MME not initialized\n")); return MME_DRIVER_NOT_INITIALIZED; /* the manager must exist */ } if (name == NULL) { MME_Info(MME_INFO_MANAGER, (DEBUG_ERROR_STR "Name not valid\n")); return MME_INVALID_ARGUMENT; } #endif EMBX_OS_MUTEX_TAKE(&manager->monitorMutex); #ifndef MME_LEAN_AND_MEAN /* prevent duplicate transport registrations */ for (tpInfo = manager->transportList; tpInfo; tpInfo = tpInfo->next) { EMBX_TPINFO embxTpInfo; err = EMBX_GetTransportInfo(tpInfo->handle, &embxTpInfo); MME_Assert(EMBX_SUCCESS == err); if (0 == strcmp(name, embxTpInfo.name)) { EMBX_OS_MUTEX_RELEASE(&manager->monitorMutex); MME_Info(MME_INFO_MANAGER, (DEBUG_ERROR_STR "Transport already registered\n")); return MME_INVALID_ARGUMENT; } } #endif /* allocate space for the transport descriptor */ res = createTransportInfo(name, &tpInfo); if (MME_SUCCESS == res) { /* update the lists with in the manager */ tpInfo->next = manager->transportList; manager->transportList = tpInfo; } EMBX_OS_MUTEX_RELEASE(&manager->monitorMutex); MME_Info(MME_INFO_MANAGER, (DEBUG_NOTIFY_STR "<<<< (%d)\n", res)); return res; }
static void receiveTransformMessage(RemoteTransformer_t *remoteTransformer, TransformerTransformMessage *message, MME_Event_t* eventPtr, MME_Command_t** commandPtr) { MME_UINT slot; MME_CommandStatus_t *status; cleanupTransformMessage(remoteTransformer, message); /* Find the right slot for this commandID. */ slot = MME_CMDID_GET_COMMAND(message->command.CmdStatus.CmdId); /* Setup our results and update the client's MME_CommandStatus_t. */ *eventPtr = MME_COMMAND_COMPLETED_EVT; *commandPtr = remoteTransformer->commandSlots[slot].command; status = (MME_CommandStatus_t*) &((*commandPtr)->CmdStatus); status->Error = message->command.CmdStatus.Error; status->ProcessedTime = message->command.CmdStatus.ProcessedTime; /* At the moment that we write the command state, a sampling client will know we are finished with the command. The command has completed or failed. */ status->State = message->command.CmdStatus.State; RemoteTransformer_ReleaseCommandSlot((Transformer_t *) remoteTransformer, &(remoteTransformer->commandSlots[slot])); MME_Info(MME_INFO_TRANSFORMER, (DEBUG_NOTIFY_STR "MME_COMMAND_COMPLETED_EVT (cmd %08x @ 0x%08x)\n", message->command.CmdStatus.CmdId, (unsigned) *commandPtr)); }
static MME_ERROR RemoteTransformer_AbortCommand(Transformer_t* transformer, MME_CommandId_t commandId) { RemoteTransformer_t *remoteTransformer = (RemoteTransformer_t *) transformer; EMBX_ERROR err; EMBX_VOID *buffer; TransformerAbortMessage *message; CommandSlot_t *slot; /* TODO: shouldn't this be asserted! */ if (!remoteTransformer->sendPort.valid) { MME_Info(MME_INFO_TRANSFORMER, (DEBUG_ERROR_STR "MME port does not exist\n")); return MME_DRIVER_NOT_INITIALIZED; } /* confirm that the command is actually pending on the companion before we * issue the abort */ slot = &(remoteTransformer->commandSlots[MME_CMDID_GET_COMMAND(commandId)]); if (slot->status != MME_RUNNING || commandId != slot->command->CmdStatus.CmdId) { return MME_INVALID_ARGUMENT; } /* Allocate an abort message and send it to the companion side, which disposes the buffer */ buffer = allocBuffer(remoteTransformer, sizeof(TransformerAbortMessage)); if (0 == buffer) { return MME_NOMEM; } /* initialize the message */ message = (TransformerAbortMessage *) buffer; message->id = TMESSID_ABORT; message->messageSize = sizeof(TransformerAbortMessage); message->commandId = commandId; /* post the message */ err = EMBX_SendMessage(remoteTransformer->sendPort.port, message, message->messageSize); if (err != EMBX_SUCCESS) { /* If sending the message did not work, there is nothing we can do. */ MME_Info(MME_INFO_TRANSFORMER, (DEBUG_ERROR_STR "EMBX_SendMessage(TransformerAbortMessage) failed, error=%d\n", err)); freeBuffer(remoteTransformer, buffer); return MME_NOMEM; } /* success does not indicate the command has been aborted only * that the request has been sent */ return MME_SUCCESS; }
MME_ERROR MME_DeregisterTransport(const char *name) { EMBX_ERROR err; MME_Info(MME_INFO_MANAGER, ("MME_DeregisterTransport()\n")); if (NULL == manager) { return MME_DRIVER_NOT_INITIALIZED; } if (NULL == name) { return MME_INVALID_ARGUMENT; } MME_Info(MME_INFO_MANAGER, ("EMBX_InvalidatePort() - handle %d\n", manager->adminPort)); err = EMBX_InvalidatePort(manager->adminPort); if (err != EMBX_SUCCESS) { MME_Info(MME_INFO_MANAGER, ("EMBX_InvalidatePort() failed, error=%d\n", err)); return MME_HANDLES_STILL_OPEN; } MME_Info(MME_INFO_MANAGER, ("EMBX_ClosePort() - handle %d\n", manager->adminPort)); EMBX_ClosePort(manager->adminPort); if (err != EMBX_SUCCESS) { MME_Info(MME_INFO_MANAGER, ("EMBX_ClosePort() failed, error=%d\n", err)); return MME_HANDLES_STILL_OPEN; } MME_Info(MME_INFO_MANAGER, ("EMBX_CloseTransport() - handle %d\n", manager->transportHandle)); err = EMBX_CloseTransport(manager->transportHandle); if (err != EMBX_SUCCESS) { MME_Info(MME_INFO_MANAGER, ("EMBX_CloseTransport() failed, error=%d\n", err)); return MME_HANDLES_STILL_OPEN; } return MME_SUCCESS; }
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 MME_ERROR createTransportInfo(const char *name, TransportInfo_t **tpInfo_p) { const char portName[] = "MMEHostReplyPort#0"; TransportInfo_t *tpInfo; EMBX_ERROR err; /* Allocate space for the transport descriptor */ tpInfo = EMBX_OS_MemAlloc(sizeof(TransportInfo_t)); if (!tpInfo) { return MME_NOMEM; } memset(tpInfo, 0, sizeof(TransportInfo_t)); /* Open a transport handle */ err = EMBX_OpenTransport(name, &tpInfo->handle); if (EMBX_SUCCESS != err) { goto error_recovery; } /* Create the reply port. */ memcpy(tpInfo->replyPortName, portName, sizeof(portName)); /* MULTIHOST support */ do { MME_Info(MME_INFO_MANAGER, (" EMBX_CreatePort(), port name <%s>...\n", tpInfo->replyPortName)); /* Create the reply port. This port is purely synchronous (it only receives * messages that are replies to outstanding messages) and as such does not * need its own management thread. */ err = EMBX_CreatePort(tpInfo->handle, tpInfo->replyPortName, &tpInfo->replyPort); } while (EMBX_ALREADY_BIND == err && tpInfo->replyPortName[sizeof(portName)-2]++ < '9'); if (EMBX_SUCCESS != err) { goto error_recovery; } *tpInfo_p = tpInfo; return MME_SUCCESS; error_recovery: if (tpInfo->handle) { err = EMBX_CloseTransport(tpInfo->handle); MME_Assert(EMBX_SUCCESS == err); } EMBX_OS_MemFree(tpInfo); return MME_EMBX_ERROR; }
static void receiveTransformerRegisteredMessage(TransformerRegisteredMessage* message) { EMBX_PORT replyPort; EMBX_ERROR embxError; MMEReceiverFactory* factory; message->result = MME_SUCCESS; /* preliminary result */ /* Connect to the reply port. */ embxError = EMBX_ConnectBlock(manager->transportHandle, message->portName, &replyPort); if (EMBX_SUCCESS != embxError) { /* ??? This is a bit of a problem. We cannot connect to the port that we should now send the error message to. */ MME_Info(MME_INFO_MANAGER, ("EMBX_ConnectBlock() to reply port failed, error=%d\n", embxError)); return; } /* Need a lock on this list */ /* Find the right receiver factory. */ factory = manager->factoryList; while (factory && factory->transformerType && strcmp(factory->transformerType, message->transformerType) != 0) { factory = factory->next; } if (factory == NULL) { /* No such factory available. */ MME_Info(MME_INFO_MANAGER, ("No receiver found for %s\n", message->transformerType)); message->result = MME_UNKNOWN_TRANSFORMER; } /* Send the message back with the updated result field */ embxError = EMBX_SendMessage(replyPort, message, message->messageSize); if (EMBX_SUCCESS != embxError) { MME_Info(MME_INFO_MANAGER, ("EMBX_SendMessage() to reply port failed, error=%d\n", embxError)); return; } EMBX_ClosePort(replyPort); }
/* Peek does not dequeue the entry. */ MME_ERROR MME_MessageQueue_Peek(MMEMessageQueue * msgQ, void **message) { MME_Info(MME_INFO_QUEUE, (">>>MME_MessageQueue_Peek(0x%08x, ...)\n", (unsigned) msgQ)); sortMessageQueue(msgQ); EMBX_OS_MUTEX_TAKE(&msgQ->queueLock); if (NULL == msgQ->sorted_front) { *message = NULL; MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Peek(..., 0) = MME_INVALID_HANDLE\n")); EMBX_OS_MUTEX_RELEASE(&msgQ->queueLock); return MME_INVALID_HANDLE; } *message = msgQ->sorted_front->message; EMBX_OS_MUTEX_RELEASE(&msgQ->queueLock); MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Peek(..., 0x%08x) = MME_SUCCESS\n", (unsigned) *message)); return MME_SUCCESS; }
MME_ERROR MME_HostDeregisterTransport(const char* name) #endif { EMBX_ERROR err; TransportInfo_t *tpInfo, **prev; MME_ERROR res; #ifndef MME_LEAN_AND_MEAN if (manager == NULL) { MME_Info(MME_INFO_MANAGER, (DEBUG_ERROR_STR "MME not initialized\n")); return MME_DRIVER_NOT_INITIALIZED; /* the manager must exist */ } if (name == NULL) { MME_Info(MME_INFO_MANAGER, (DEBUG_ERROR_STR "Transport name NULL\n")); return MME_INVALID_ARGUMENT; } #endif EMBX_OS_MUTEX_TAKE(&manager->monitorMutex); MME_Info(MME_INFO_MANAGER, (DEBUG_NOTIFY_STR "Looking for transport %s\n", name)); /* search the transport list for the appropriate transport */ for (tpInfo = *(prev = &manager->transportList); tpInfo; tpInfo = *(prev = &tpInfo->next)) { EMBX_TPINFO embxTpInfo; err = EMBX_GetTransportInfo(tpInfo->handle, &embxTpInfo); MME_Assert(EMBX_SUCCESS == err); if (0 == strcmp(name, embxTpInfo.name)) { break; } } if (!tpInfo) { MME_Info(MME_INFO_MANAGER, (DEBUG_ERROR_STR "Transport not found\n")); res = MME_INVALID_ARGUMENT; } else if (0 != tpInfo->referenceCount) { MME_Info(MME_INFO_MANAGER, (DEBUG_ERROR_STR "Handles still open\n")); res = MME_HANDLES_STILL_OPEN; } else { res = MME_SUCCESS; MME_Info(MME_INFO_MANAGER, (DEBUG_NOTIFY_STR "Removing transport\n")); /* remove the transport information from the list and cleanup */ *prev = tpInfo->next; destroyTransportInfo(tpInfo); } EMBX_OS_MUTEX_RELEASE(&manager->monitorMutex); MME_Info(MME_INFO_MANAGER, (DEBUG_NOTIFY_STR "<<<< (%d)\n", res)); return res; }
static MME_ERROR RemoteTransformer_KillCommand(Transformer_t* transformer, MME_CommandId_t commandId) { RemoteTransformer_t *remoteTransformer = (RemoteTransformer_t *) transformer; MME_ERROR result; EMBX_ERROR err; CommandSlot_t *slot; EMBX_VOID *buffer; TransformerTransformMessage *message; EMBX_PORT replyPort; /* TODO: shouldn't this be asserted! */ if (!remoteTransformer->sendPort.valid) { MME_Info(MME_INFO_TRANSFORMER, (DEBUG_ERROR_STR "MME port does not exist\n")); return MME_DRIVER_NOT_INITIALIZED; } /* confirm that the command is actually pending on the companion before we * issue the abort */ slot = &(remoteTransformer->commandSlots[MME_CMDID_GET_COMMAND(commandId)]); if (slot->status != MME_RUNNING || commandId != slot->command->CmdStatus.CmdId) { return MME_INVALID_ARGUMENT; } /* mark the command as complete */ slot->command->CmdStatus.Error = MME_COMMAND_ABORTED; slot->command->CmdStatus.State = MME_COMMAND_FAILED; /* fake up a completed transform request */ result = createTransformMessage(remoteTransformer, slot->command, &buffer); if (result != MME_SUCCESS) { return result; } /* connect to our own reply port */ err = EMBX_Connect(remoteTransformer->super.info->handle, remoteTransformer->replyPort.name, &replyPort); if (EMBX_SUCCESS != err) { return MME_EMBX_ERROR; } /* send the message */ message = (TransformerTransformMessage *) buffer; err = EMBX_SendMessage(replyPort, message, message->messageSize); if (EMBX_SUCCESS != err) { return MME_EMBX_ERROR; } EMBX_ClosePort(replyPort); return MME_SUCCESS; }
MME_ERROR MME_MessageQueue_Enqueue(MMEMessageQueue * msgQ, void *message, unsigned int priority) { MMEMessageQueueEntry *entry; MME_Info(MME_INFO_QUEUE, (">>>MME_MessageQueue_Enqueue(0x%08x, 0x%08x)\n", (unsigned) msgQ, (unsigned) message)); EMBX_OS_MUTEX_TAKE(&msgQ->queueLock); /* fetch a free linkage structure from the free list */ entry = msgQ->free_list; if (NULL == entry) { EMBX_OS_MUTEX_RELEASE(&msgQ->queueLock); MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Enqueue = MME_NOMEM\n")); return MME_NOMEM; } msgQ->free_list = entry->next; /* fill in the linkage structure */ entry->next = NULL; entry->priority = priority; entry->message = message; /* add it to the unsorted FIFO queue. we use a FIFO queue in order to * exploit the FIFO optimizations in SortMMEMessageQueue. */ if (NULL == msgQ->unsorted_front) { msgQ->unsorted_front = entry; } else { msgQ->unsorted_back->next = entry; } msgQ->unsorted_back = entry; EMBX_OS_MUTEX_RELEASE(&msgQ->queueLock); MME_Info(MME_INFO_QUEUE, ("<<<MME_MessageQueue_Enqueue = MME_SUCCESS\n")); return MME_SUCCESS; }
static void executionLoopTask(void *params) { int id = (int) params; for (EMBX_OS_EVENT_WAIT(&(manager->commandEvents[id])); manager->loopTasksRunning[id]; EMBX_OS_EVENT_WAIT(&(manager->commandEvents[id]))) { MMEReceiver *receiver; MMEReceiver *lowestReceiver; MME_Time_t dueTime, lowestDueTime; int found = 0; EMBX_OS_MUTEX_TAKE(&(manager->receiverListMutexes[id])); EMBX_OS_MUTEX_TAKE(&(manager->abortMutex)); /* Find the receiver with the lowest dueTime. */ lowestReceiver = manager->receiverLists[id]; lowestDueTime = MME_MaxTime_c; for (receiver = lowestReceiver; receiver; receiver = receiver->next) { if (MME_SUCCESS == MME_Receiver_NextDueTime(receiver, &dueTime)) { if (dueTime < lowestDueTime) { found = 1; lowestReceiver = receiver; lowestDueTime = dueTime; } } } /* TODO: Note that if we support the bufferQueue, we need to serve it here */ if (found) { EMBX_OS_MUTEX_RELEASE(&(manager->receiverListMutexes[id])); /* Execute this receiver's command. */ /* Mutex will be released once the message is dequeued - otherwise an abort requiest may come take the message off the queue but leave the receiver in the executing state */ MME_Receiver_ProcessCommand(lowestReceiver); } else { /* Nothing is pending. We could waste some time. */ MME_Info(MME_INFO_MANAGER, ("Execution loop error: Semaphore signalled but no command found!\n")); EMBX_OS_MUTEX_RELEASE(&(manager->receiverListMutexes[id])); EMBX_OS_MUTEX_RELEASE(&(manager->abortMutex)); } } }
static void receiveIsAliveMessage(TransformerIsAliveMessage * message) { EMBX_PORT replyPort = EMBX_INVALID_HANDLE_VALUE; EMBX_ERROR err; MMEReceiver **prev = NULL, *receiver = NULL; int id; /* Search each receiver list for a matching handle */ for (id=0; id<MME_NUM_EXECUTION_LOOPS; id++) { if (manager->loopTasksRunning[id]) { EMBX_OS_MUTEX_TAKE(&(manager->receiverListMutexes[id])); /* iterate of the receiver list keeping track of the linkage pointer */ for (prev = &(manager->receiverLists[id]), receiver = *prev; NULL != receiver; prev = &(receiver->next), receiver = *prev) { if (receiver == (void *) (message->mmeHandle)) { /* even Java lets you use labelled jumps to do this ... */ goto double_break; } } EMBX_OS_MUTEX_RELEASE(&(manager->receiverListMutexes[id])); } else { MME_Assert(0 == manager->loopTasks[id]); MME_Assert(0 == manager->receiverLists[id]); } } double_break: /* WARNING: if receiver is non-NULL we still own receiverListMutexes[id] */ if (NULL != receiver) { replyPort = MME_Receiver_GetReplyPort(receiver); EMBX_OS_MUTEX_RELEASE(&(manager->receiverListMutexes[id])); /* send the message back to the host */ err = EMBX_SendMessage(replyPort, message, message->messageSize); MME_Assert(EMBX_SUCCESS == err); /* cannot recover */ } else { MME_Info(MME_INFO_MANAGER, ("receiveIsAliveMessage could not find receiver, no reply port available!\n")); } }
static void receiverThread(void* ctx) { RemoteTransformer_t* remoteTransformer = (RemoteTransformer_t*) ctx; MME_ERROR res; MME_Assert(remoteTransformer); MME_Assert(remoteTransformer->replyPort.valid); while (1) { MME_Event_t evt; MME_Command_t *cmd; /* wait for a transformer message (callback) to be received */ res = RemoteTransformer_WaitForMessage( (Transformer_t *) remoteTransformer, &evt, &cmd); if (MME_SUCCESS != res) { break; } MME_Assert(cmd); /* perform the callback if this has been requested */ if (MME_COMMAND_COMPLETED_EVT != evt || MME_COMMAND_END_RETURN_NOTIFY == cmd->CmdEnd) { /* it would really make more sense to assert Callback and make it illegal to send * commands with MME_COMMAND_END_RETURN_NOTIFY fail if Callback is NULL. However this * would mean changing the behavior of the API. */ if (remoteTransformer->super.initParams.Callback) { remoteTransformer->super.initParams.Callback(evt, cmd, remoteTransformer->super.initParams.CallbackUserData); } } } MME_Info(MME_INFO_TRANSFORMER, ("receiverThread: terminating due (res = %d)\n", res)); }
MME_ERROR MME_RegisterTransport(const char *transportName) { const char portName[] = "MMECompanionAdmin#0"; EMBX_ERROR err; if (NULL == transportName) { return MME_INVALID_ARGUMENT; } if (NULL == manager) { return MME_DRIVER_NOT_INITIALIZED; } MME_Info(MME_INFO_MANAGER, ("EMBX_OpenTransport(), name <%s>...\n", transportName)); /* Open the transport. */ err = EMBX_OpenTransport(transportName, &manager->transportHandle); MME_Info(MME_INFO_MANAGER, ("EMBX_OpenTransport() - handle %d\n", manager->transportHandle)); if (EMBX_SUCCESS != err) { MME_Info(MME_INFO_MANAGER, ("Failed to open EMBX_OpenTransport() - EMBX err %d\n", err)); return MME_INVALID_ARGUMENT; } /* Create the administration port. */ memcpy(manager->adminPortName, portName, sizeof(portName)); do { MME_Info(MME_INFO_MANAGER, (" EMBX_CreatePort(), port name <%s>...\n", manager->adminPortName)); err = EMBX_CreatePort(manager->transportHandle, manager->adminPortName, &manager->adminPort); } while (EMBX_ALREADY_BIND == err && manager->adminPortName[sizeof(portName)-2]++ < '9'); if (err != EMBX_SUCCESS) { MME_Info(MME_INFO_MANAGER, ("EMBX_CreatePort(%s) failed - error %d\n", manager->adminPortName, err)); EMBX_CloseTransport(manager->transportHandle); manager->transportHandle = 0; return MME_INVALID_ARGUMENT; } MME_Info(MME_INFO_MANAGER, ("EMBX_CreatePort(%s) handle 0x%08x\n", manager->adminPortName, manager->adminPort)); manager->managerRunning = 1; return MME_SUCCESS; }
static void receiveStavationMessage(RemoteTransformer_t *remoteTransformer, TransformerStarvationMessage *message, MME_Event_t* eventPtr, MME_Command_t** commandPtr) { MME_UINT slot; MME_CommandStatus_t *status; /* Find the right slot for this commandID. */ slot = MME_CMDID_GET_COMMAND(message->status.CmdId); *eventPtr = (MME_Event_t) message->event; /* Copy the status from the message to the client's MME_CommandStatus_t. */ *commandPtr = remoteTransformer->commandSlots[slot].command; status = (MME_CommandStatus_t*) &((*commandPtr)->CmdStatus); status->Error = message->status.Error; status->ProcessedTime = message->status.ProcessedTime; status->State = message->status.State; MME_Info(MME_INFO_TRANSFORMER, (DEBUG_NOTIFY_STR "Stavation event %d (cmd %08x @ 0x%08x)\n", *eventPtr, message->status.CmdId, (unsigned) *commandPtr)); }
/* Run the manager. This call only returns when everything is shut down. */ MME_ERROR MME_Run(void) { MME_ERROR result; EMBX_ERROR err; EMBX_RECEIVE_EVENT event; MME_UINT messageID; int running = 1; int oldTaskPriority; if (manager == NULL) { return MME_DRIVER_NOT_INITIALIZED; } /* Note that the manager should be running at high priority (e.g. 200 of 255). */ oldTaskPriority = task_priority_set(NULL, MANAGER_TASK_PRIORITY); while (running && manager->managerRunning) { /* Wait for a host request. */ MME_Info(MME_INFO_MANAGER, ("Waiting for host request... on port 0x%08x\n", manager->adminPort)); err = EMBX_ReceiveBlock(manager->adminPort, &event); if (err == EMBX_SUCCESS) { if (event.type == EMBX_REC_MESSAGE && event.size >= sizeof(MME_UINT) && event.data != NULL) { /* The message ID decides. */ messageID = *((MME_UINT*) event.data); switch (messageID) { case TMESSID_INIT: /* It is a TransformerInitMessage. */ receiveInitMessage((TransformerInitMessage *) event.data); break; case TMESSID_TERMINATE: /* It is a TransformerTerminateMessage to terminate a single transformer. */ receiveTerminateMessage((TransformerTerminateMessage *) event.data); break; case TMESSID_CAPABILITY: receiveCapabilityMessage((TransformerCapabilityMessage *) event.data); break; case TMESSID_TERMINATE_MME: { /* It is a TransformerTerminateMessage to terminate all of the MME! */ TransformerTerminateMMEMessage *msg = (TransformerTerminateMMEMessage*) event.data; result = MME_Term(); msg->result = result; running = 0; /* ??? Problem: We need to tell someone if termination worked, but there's no port to talk to, and EMBX has been shut down as well. */ break; } case TMESSID_TRANSFORMER_REGISTERED: receiveTransformerRegisteredMessage((TransformerRegisteredMessage*) event.data); break; default: MME_Info(MME_INFO_MANAGER, ("Received unknown message ID %d\n", messageID)); break; } } else { /* Strange message arrived. */ MME_Info(MME_INFO_MANAGER, ("Strange message: type %d, size %d, data %0x\n", event.type, event.size, event.data)); } } else { if (err == EMBX_INVALID_PORT || err == EMBX_PORT_INVALIDATED) { MME_Info(MME_INFO_MANAGER, ("RunMMEManager:EMBX_ReceiveBlock() returned due to invalid(ated) port, error=%d\n", err)); result = MME_Term(); if (result != MME_SUCCESS) { MME_Info(MME_INFO_MANAGER, ("TerminateMMEManager() failed, result=%d\n", result)); } running = 0; } else { MME_Info(MME_INFO_MANAGER, ("RunMMEManager: EMBX_ReceiveBlock() failed, error=%d\n", err)); } } } task_priority_set(NULL, oldTaskPriority); return MME_SUCCESS; }
static MME_ERROR createTransformMessage(RemoteTransformer_t* remoteTransformer, MME_Command_t * cmd, EMBX_VOID ** buffer) { union { TransformerTransformMessage *message; MME_DataBuffer_t *buffer; MME_ScatterPage_t *page; EMBX_HANDLE *hdl; char *ch; int i; void *p; void **pp; } p, q, size; MME_ERROR res = MME_NOMEM; EMBX_ERROR err; unsigned int i, j; /* all argument checking should have been performed further up the food chain * so all the argument checking in this function can asserted */ MME_Assert(remoteTransformer); MME_Assert(cmd); MME_Assert(buffer); MME_Info(MME_INFO_TRANSFORMER, (DEBUG_NOTIFY_STR "Command 0x%08x\n", (int)cmd)); /* determine the size of message we will need */ size.i = 0; size.message += 1; size.buffer += cmd->NumberInputBuffers + cmd->NumberOutputBuffers; size.pp += cmd->NumberInputBuffers + cmd->NumberOutputBuffers; for (i=0; i < (cmd->NumberInputBuffers + cmd->NumberOutputBuffers); i++) { size.page += cmd->DataBuffers_p[i]->NumberOfScatterPages; size.hdl += cmd->DataBuffers_p[i]->NumberOfScatterPages; } size.i += cmd->CmdStatus.AdditionalInfoSize; size.i += cmd->ParamSize; /* allocate the message */ p.p = allocBuffer(remoteTransformer, size.i); if (0 == p.p) { return MME_NOMEM; } *buffer = p.p; /* populate the fundamental message structure */ p.message = (TransformerTransformMessage *) (*buffer); p.message->id = TMESSID_TRANSFORM; p.message->messageSize = size.i; p.message->hostCommand = cmd; p.message->receiverInstance = (MME_UINT)remoteTransformer->mmeHandle; /* used for sanity check on companion */ p.message->command = *cmd; p.message->command.DataBuffers_p = NULL; /* invalid local pointers */ p.message->transformer = remoteTransformer; p.message->numInputBuffers = cmd->NumberInputBuffers; p.message->numOutputBuffers = cmd->NumberOutputBuffers; p.message += 1; /* copy the data buffers into our message */ for (i=0; i < (cmd->NumberInputBuffers + cmd->NumberOutputBuffers); i++) { MME_Info(MME_INFO_TRANSFORMER, (DEBUG_NOTIFY_STR "Buffer %d at 0x%08x\n", i, (int)(cmd->DataBuffers_p[i]) )); *p.buffer++ = *cmd->DataBuffers_p[i]; } /* skip the pre-allocated data buffers structure */ p.pp += cmd->NumberInputBuffers + cmd->NumberOutputBuffers; /* copy the scatter pages into our message */ for (i=0; i < (cmd->NumberInputBuffers + cmd->NumberOutputBuffers); i++) { MME_DataBuffer_t *buf = cmd->DataBuffers_p[i]; MME_ScatterPage_t *pages; EMBX_HANDLE *hdls; pages = p.page; p.page += buf->NumberOfScatterPages; hdls = p.hdl; p.hdl += buf->NumberOfScatterPages; for (j=0; j < buf->NumberOfScatterPages; j++) { MME_ScatterPage_t *page = &buf->ScatterPages_p[j]; MME_Info(MME_INFO_TRANSFORMER, (DEBUG_NOTIFY_STR "Page %d at 0x%08x\n", j, (int)page )); /* copy the original page into the data buffer */ pages[j] = *page; /* serialize the object (try direct pointer warping before falling back to registering * the object) */ err = EMBX_Offset(remoteTransformer->super.info->handle, page->Page_p, (EMBX_INT *) hdls + j); MME_Info(MME_INFO_TRANSFORMER, (DEBUG_NOTIFY_STR "Page 0x%08x, Pointer warp %s, Handle 0x%08x buf-id %d, page-id %d\n", (int) page->Page_p, (EMBX_INCOHERENT_MEMORY==err) ? "PURGE" : (EMBX_SUCCESS==err) ? "YES" : "NO", (int)hdls[j], i, j)); if (EMBX_INCOHERENT_MEMORY == err) { if (0 == (page->FlagsIn & MME_DATA_CACHE_COHERENT)) { EMBX_OS_PurgeCache(page->Page_p, page->Size); } } else if (EMBX_SUCCESS != err) { err = EMBX_RegisterObject(remoteTransformer->super.info->handle, page->Page_p, page->Size, hdls + j); if (EMBX_SUCCESS != err) { res = MME_EMBX_ERROR; MME_Info(1, ("Failed to reg obj err %d, i %d, j %d\n", err, i, j)); goto error_recovery; } } /* update the copy (or view) of the object at our destination port */ if (0xf0000000 & hdls[j]) { err = EMBX_UpdateObject(remoteTransformer->sendPort.port, hdls[j], 0, page->Size); if (EMBX_SUCCESS != err) { MME_Info(1, ("Failed to update obj err %d\n", err )); res = MME_EMBX_ERROR; goto error_recovery; } } } } /* TODO: Need to use a macro to swap all args to little endian if on a big endian machine */ if (cmd->CmdStatus.AdditionalInfoSize > 0) { memcpy(p.p, cmd->CmdStatus.AdditionalInfo_p, cmd->CmdStatus.AdditionalInfoSize); p.ch += cmd->CmdStatus.AdditionalInfoSize; } if (cmd->ParamSize > 0) { memcpy(p.p, cmd->Param_p, cmd->ParamSize); } return MME_SUCCESS; error_recovery: /* to recover from the error we walk through the currently marshalled data knowing * that p (in any of its forms) points to the first uninitialized byte in the * buffer. */ /* get to the scatter page and handles section of the buffer */ q.p = *buffer; q.message += 1; q.buffer += cmd->NumberInputBuffers + cmd->NumberOutputBuffers; q.pp += cmd->NumberInputBuffers + cmd->NumberOutputBuffers; /* now iterate though the buffer deregistering the objects */ for (i=0; i < (cmd->NumberInputBuffers + cmd->NumberOutputBuffers) && q.p < p.p; i++) { q.page += cmd->DataBuffers_p[i]->NumberOfScatterPages; for (j=0; j < cmd->DataBuffers_p[i]->NumberOfScatterPages && q.p < p.p; j++) { if (0xf0000000 & q.hdl[j]) { err = EMBX_DeregisterObject( remoteTransformer->super.info->handle, q.hdl[j]); MME_Assert(EMBX_SUCCESS == err); /* no error recovery possible */ } } q.hdl += cmd->DataBuffers_p[i]->NumberOfScatterPages; } /* unallocate the buffer */ freeBuffer(remoteTransformer, buffer); return res; }
MME_ERROR MME_AllocDataBuffer(MME_TransformerHandle_t handle, MME_UINT size, MME_AllocationFlags_t flags, MME_DataBuffer_t ** dataBuffer_p) { static const MME_AllocationFlags_t illegalFlags = (MME_AllocationFlags_t) ~(MME_ALLOCATION_PHYSICAL | MME_ALLOCATION_CACHED | MME_ALLOCATION_UNCACHED); Transformer_t *transformer; struct InternalDataBuffer *buf; unsigned localSize; #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 == size || NULL == dataBuffer_p || (flags & illegalFlags)) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "size==0 || NULL == dataBuffer_p || (flags & illegalFlags)\n")); return MME_INVALID_ARGUMENT; } if (0 > (int) size) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "size<0\n")); return MME_NOMEM; } #endif /* lookup whether we should allocate using EMBX_OS_MemAlloc or EMBX_Alloc() */ if (MME_SUCCESS != findTransformerInstance(handle, &transformer)) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "invalid transformer handle\n")); return MME_INVALID_HANDLE; } if (0 == transformer->info) { /* this is a local transformers so we can't allocate memory using EMBX_Alloc */ flags |= MME_ALLOCATION_CACHED; } /* Allocate the buffer structure */ /* Cannot present a "negative" value to EMBX_OS_MemAlloc on SHLINUX KERNEL mode * as it "succeeds" and returns a non-NULL value */ localSize = (int) (sizeof(*buf) + (flags & MME_ALLOCATION_CACHED ? size + MME_MAX_CACHE_LINE-1 : 0)); if (0 > (int) localSize) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "localSze <0\n")); return MME_NOMEM; } buf = EMBX_OS_MemAlloc(localSize); if (NULL == buf) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Cannot EMBX_OS_MemAlloc(%d)\n", sizeof(*buf) + (flags & MME_ALLOCATION_CACHED ? size : 0) )); return MME_NOMEM; } /* populate the buffer structure */ memset(buf, 0, sizeof(*buf)); buf->buffer.StructSize = sizeof(MME_DataBuffer_t); buf->buffer.NumberOfScatterPages = 1; buf->buffer.ScatterPages_p = buf->pages; buf->buffer.TotalSize = size; buf->flags = flags; buf->pages[0].Size = size; if (flags & MME_ALLOCATION_CACHED) { /* We MUST align the data buffer to a cacheline boundary to keep this safe */ buf->pages[0].Page_p = (void *) MME_CACHE_LINE_ALIGN((buf + 1)); } else { /* if transportHandle is 0 this will fail so we have no specific path to * prevent uncached allocations for local transformers. */ EMBX_ERROR err = EMBX_Alloc(transformer->info->handle, size, &buf->pages[0].Page_p); if (EMBX_SUCCESS != err) { MME_Info( MME_INFO_MANAGER, (DEBUG_ERROR_STR "Cannot EMBX_Alloc(0x%08x, %d, 0x%08x)\n", transformer->info->handle, size, (unsigned) &buf->pages[0].Page_p)); EMBX_OS_MemFree(buf); return MME_NOMEM; } } *dataBuffer_p = &(buf->buffer); return MME_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; }
static MME_ERROR RemoteTransformer_SendCommand(Transformer_t* transformer, MME_Command_t * commandInfo, CommandSlot_t** slot) { RemoteTransformer_t *remoteTransformer = (RemoteTransformer_t *) transformer; EMBX_VOID *buffer; EMBX_ERROR err; MME_CommandStatus_t *status; TransformerTransformMessage *message; MME_ERROR result; int i; MME_CommandCode_t cmdCode = commandInfo->CmdCode; int newCommandIndex; if (!remoteTransformer->sendPort.valid) { MME_Info(MME_INFO_TRANSFORMER, (DEBUG_ERROR_STR "MME port does not exist\n")); return MME_INVALID_ARGUMENT; } status = (MME_CommandStatus_t*) &(commandInfo->CmdStatus); MME_Assert(cmdCode == MME_TRANSFORM || cmdCode == MME_SEND_BUFFERS || cmdCode == MME_SET_GLOBAL_TRANSFORM_PARAMS); /* Acquire lock on the transformer's command slots */ EMBX_OS_MUTEX_TAKE(&remoteTransformer->commandSlotLock); if (remoteTransformer->numCommandSlots >= remoteTransformer->maxCommandSlots) { /* no free slot */ EMBX_OS_MUTEX_RELEASE(&remoteTransformer->commandSlotLock); MME_Info(MME_INFO_TRANSFORMER, (DEBUG_ERROR_STR "SendCommand: maxCommandSlots overflow\n")); return MME_NOMEM; } /* Find a free command slot so we can memorize parameters */ for (i = 0; i < remoteTransformer->maxCommandSlots && remoteTransformer->commandSlots[remoteTransformer->commandIndex].status != MME_COMMAND_COMPLETED_EVT; i++) { MME_Info(MME_INFO_TRANSFORMER, (DEBUG_NOTIFY_STR "RemoteTransformer: SendCommand: CommandIndex %d is already used\n", remoteTransformer->commandIndex)); remoteTransformer->commandIndex++; if (remoteTransformer->commandIndex >= remoteTransformer->maxCommandSlots) { remoteTransformer->commandIndex = 0; } } if (i >= remoteTransformer->maxCommandSlots) { EMBX_OS_MUTEX_RELEASE(&remoteTransformer->commandSlotLock); MME_Info(MME_INFO_TRANSFORMER, (DEBUG_ERROR_STR "SendCommand error: No free command slot found!\n")); return MME_NOMEM; } newCommandIndex = remoteTransformer->commandIndex; /* Generate a unique command ID per transformer */ status->CmdId = MME_CMDID_PACK( (remoteTransformer->super.handle)-MME_TRANSFORMER_HANDLE_PREFIX, newCommandIndex, &(remoteTransformer->commandIDCounter)); MME_Info(MME_INFO_TRANSFORMER, (DEBUG_NOTIFY_STR "RemoteTransformer: SendCommand: code=%d ID=%d slot=%d\n", cmdCode, status->CmdId, newCommandIndex)); /* In order to avoid sending buffers, but then being unable to allocate the transform message, we create and fill in the transform message first */ result = createTransformMessage(remoteTransformer, commandInfo, &buffer); if (result != MME_SUCCESS) { EMBX_OS_MUTEX_RELEASE(&remoteTransformer->commandSlotLock); MME_Info(MME_INFO_TRANSFORMER, (DEBUG_ERROR_STR "CreateTransformMsg() failed, result=%d\n", result)); return MME_NOMEM; } /* Setting the command state to FAILED allows us to identify incomplete SendCommand()s at our receiver task. */ status->State = MME_COMMAND_FAILED; /* New command slot entry. Initially, assume that the transform message can't be sent */ status->Error = MME_SUCCESS; remoteTransformer->commandSlots[newCommandIndex].endType = commandInfo->CmdEnd; /* In the moment that the status is not zero, the receiver task regards it as valid */ remoteTransformer->commandSlots[newCommandIndex].command = commandInfo; remoteTransformer->commandSlots[newCommandIndex].waitor = NULL; remoteTransformer->commandSlots[newCommandIndex].status = MME_RUNNING; remoteTransformer->numCommandSlots++; EMBX_OS_MUTEX_RELEASE(&remoteTransformer->commandSlotLock); /* TODO: Should we move the state here or on the companion once the command is * scheduled - I think the latter */ status->State = MME_COMMAND_EXECUTING; message = (TransformerTransformMessage *) buffer; /* Send the message */ err = EMBX_SendMessage(remoteTransformer->sendPort.port, message, message->messageSize); if (err != EMBX_SUCCESS) { /* The message could not be sent. Mark the command slot as incomplete */ MME_Info(MME_INFO_TRANSFORMER, (DEBUG_ERROR_STR "EMBX_SendMessage() failed, error=%d\n", err)); /* Mark incomplete command */ status->State = MME_COMMAND_FAILED; freeBuffer(remoteTransformer, buffer); return MME_NOMEM; } else { /* Lost ownership */ buffer = NULL; } *slot = &(remoteTransformer->commandSlots[newCommandIndex]); return MME_SUCCESS; }
static MME_ERROR RemoteTransformer_Init(Transformer_t* transformer, const char* name, MME_TransformerInitParams_t * params, MME_TransformerHandle_t handle, EMBX_BOOL createThread) { RemoteTransformer_t *remoteTransformer = (RemoteTransformer_t *) transformer; EMBX_ERROR err; EMBX_RECEIVE_EVENT event; TransformerInitMessage *message = NULL; char receiverThreadName[EMBX_MAX_PORT_NAME+1]; int messageSize,n; MME_ERROR result, res; result = MME_NOMEM; remoteTransformer->super.handle = handle; /* TODO: We should take a copy of our (transformer specific) parameters. These might * be deallocated once the transformer is initialized. */ remoteTransformer->super.initParams = *params; MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: initialising '%s'\n", name)); /* Create the reply port. We use the unique handle to create a unique reply port name.*/ n = sprintf(remoteTransformer->replyPort.name, "MMEReply_0x%x", handle); MME_Assert(n < EMBX_MAX_PORT_NAME); err = EMBX_CreatePort(remoteTransformer->super.info->handle, remoteTransformer->replyPort.name, &remoteTransformer->replyPort.port); if (EMBX_SUCCESS != err) { MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Cannot create port '%s'\n", remoteTransformer->replyPort.name)); goto embx_error_recovery; } remoteTransformer->replyPort.valid = 1; MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Created port '%s', port 0x%08x\n", remoteTransformer->replyPort.name, (unsigned) remoteTransformer->replyPort.port)); /* Create the init message */ res = createInitMessage(remoteTransformer, name, params, (EMBX_VOID **) &message); if (MME_SUCCESS != res) { MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Cannot create initialisation message\n")); goto error_recovery; } /* Remember size for check of reply message */ messageSize = message->messageSize; /* Send the message */ err = EMBX_SendMessage(remoteTransformer->adminPort, message, messageSize); if (err != EMBX_SUCCESS) { MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Cannot set initialisation message\n")); goto embx_error_recovery; } /* Record ownership tranfer (see error_recovery) */ message = NULL; MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Waiting for initialisation reply\n")); /* Wait for an answer from the companion */ err = EMBX_ReceiveBlock(remoteTransformer->replyPort.port, &event); if (EMBX_SUCCESS != err) { MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Error while waiting for initialisation reply\n")); goto embx_error_recovery; } /* Check if the message is as expected */ message = (TransformerInitMessage *) event.data; MME_Assert(EMBX_REC_MESSAGE == event.type); MME_Assert(event.size >= messageSize); MME_Assert(message && message->id == TMESSID_INIT); if (MME_SUCCESS != message->result) { MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Error initialising remote transformer\n")); res = message->result; goto error_recovery; } /* The MME successfully created its transformer */ strncpy(remoteTransformer->sendPort.name, message->portName, EMBX_MAX_PORT_NAME); remoteTransformer->sendPort.name[EMBX_MAX_PORT_NAME] = '\0'; remoteTransformer->mmeHandle = message->mmeHandle; MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Connecting to transformer port '%s'\n", remoteTransformer->sendPort.name)); /* Connect to the MME port */ err = EMBX_ConnectBlock(remoteTransformer->super.info->handle, remoteTransformer->sendPort.name, &remoteTransformer->sendPort.port); if (EMBX_SUCCESS != err) { MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Cannot connect to port '%s'\n", remoteTransformer->sendPort.name)); goto embx_error_recovery; } remoteTransformer->sendPort.valid = 1; MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Connected to port '%s', port 0x%08x\n", remoteTransformer->sendPort.name, (unsigned) remoteTransformer->sendPort.port)); if (createThread) { /* Create our receiver task for the reply port */ sprintf(receiverThreadName, "HostRec%x", handle); MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Creating receiver thread '%s'\n", receiverThreadName)); /* TODO: think about whether we want all the receiver threads to have the same priority */ remoteTransformer->receiverThread = EMBX_OS_ThreadCreate(receiverThread, (void *) remoteTransformer, RECEIVER_TASK_PRIORITY, receiverThreadName); if (EMBX_INVALID_THREAD == remoteTransformer->receiverThread) { MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Cannot create receiver thread '%s'\n", receiverThreadName)); res = MME_NOMEM; goto error_recovery; } MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: Created receiver thread '%s', thread 0x%08x\n", receiverThreadName, (unsigned) remoteTransformer->receiverThread)); } /* Cleanup and exit */ cleanupInitMessage(remoteTransformer, message); MME_Info(MME_INFO_TRANSFORMER, ("RemoteTransformer_Init: SUCCESS\n")); return MME_SUCCESS; embx_error_recovery: /* As normal error recovery but map the EMBX error code to a MME error code first */ res = (EMBX_NOMEM == err ? MME_NOMEM : MME_EMBX_ERROR); error_recovery: if (remoteTransformer->mmeHandle) { MME_Assert(message); message->id = TMESSID_TERMINATE; err = EMBX_SendMessage(remoteTransformer->adminPort, message, message->messageSize); if (EMBX_SUCCESS == err) { /* TODO: is blocking really a good idea during error recovery? */ err = EMBX_ReceiveBlock(remoteTransformer->replyPort.port, &event); message = (EMBX_SUCCESS == err ? event.data : NULL); } remoteTransformer->mmeHandle = 0; } if (remoteTransformer->sendPort.valid) { EMBX_ClosePort(remoteTransformer->sendPort.port); remoteTransformer->sendPort.valid = 0; } if (remoteTransformer->replyPort.valid) { EMBX_ClosePort(remoteTransformer->replyPort.port); remoteTransformer->replyPort.valid = 0; } if (message) { cleanupInitMessage(remoteTransformer, message); } return res; }
static void receiveInitMessage(TransformerInitMessage * message) { EMBX_ERROR err; EMBX_PORT replyPort; MMEReceiverFactory *factory; MMEReceiver *receiver; MME_ERROR res; message->result = MME_NOMEM; /* preliminary result */ /* Connect to the reply port. */ err = EMBX_ConnectBlock(manager->transportHandle, message->portName, &replyPort); if (err != EMBX_SUCCESS) { /* ??? This is a bit of a problem. We cannot connect to the port that we should now send the error message to. */ MME_Info(MME_INFO_MANAGER, ("EMBX_ConnectBlock() to reply port failed, error=%d\n", err)); return; } /* Need a lock on this list */ /* Find the right receiver factory. */ factory = manager->factoryList; while (factory != NULL && strcmp(factory->transformerType, message->transformerType) != 0) { factory = factory->next; } if (factory == NULL) { /* No such factory available. */ MME_Info(MME_INFO_MANAGER, ("No receiver factory found\n")); res = MME_UNKNOWN_TRANSFORMER; } else { /* Create a receiver object. This will result in the constructors being called as well. */ res = MME_Receiver_Create(factory, &receiver); if (MME_SUCCESS == res) { int id = MME_PRIORITY_TO_ID(message->priority); res = createExecutionLoop(manager, id); assert(MME_SUCCESS == res); /* TODO: proper error handling */ /* Initialize the receiver. */ /* This call will also fail if an existing transformer does not support multi-instantiation. */ res = MME_Receiver_Init(receiver, manager, manager->transportHandle, message, replyPort, &(manager->commandEvents[id])); if (res == MME_SUCCESS) { /* Add the new receiver to the list. */ EMBX_OS_MUTEX_TAKE(&(manager->receiverListMutexes[id])); receiver->next = manager->receiverLists[id]; manager->receiverLists[id] = receiver; EMBX_OS_MUTEX_RELEASE(&(manager->receiverListMutexes[id])); /* We are successfully done. */ message->result = res; EMBX_SendMessage(replyPort, message, message->messageSize); return; } /* Could not initialize receiver. Clean up and return error. */ MME_Receiver_Destroy(receiver); } } /* Send the message back to the host with an error. */ message->result = res; EMBX_SendMessage(replyPort, message, message->messageSize); EMBX_ClosePort(replyPort); }