/* This code forms a small cache of pre-allocated blocks that can be allocated by * the host without using (comparitively slow) spinlocks and semaphores. additionally * block coalescing does not take place which saves a number of uncached reads */ static void *allocBuffer(RemoteTransformer_t *remoteTransformer, MME_UINT sz) { EMBX_ERROR err; EMBX_VOID *ptr; if (sz <= 4096) { EMBX_OS_INTERRUPT_LOCK(); if (remoteTransformer->bufferCache) { ptr = remoteTransformer->bufferCache; remoteTransformer->bufferCache = *remoteTransformer->bufferCache; EMBX_OS_INTERRUPT_UNLOCK(); /* this assert technically has side effects (alters sz) so have a * care if altering this function */ MME_Assert(EMBX_SUCCESS == EMBX_GetBufferSize(ptr, &sz)); MME_Assert(4096 == sz); return ptr; } sz = 4096; EMBX_OS_INTERRUPT_UNLOCK(); } err = EMBX_Alloc(remoteTransformer->super.info->handle, sz, &ptr); return (EMBX_SUCCESS == err ? ptr : 0); }
void send_thread(void *param) { EMBX_PORT port = (EMBX_PORT)param; EMBX_ERROR res; EMBX_VOID *buffer; EMBX_OS_Delay(5000); EMBX_Alloc(tp,BUFFER_SIZE,&buffer); res = EMBX_SendMessage(port,buffer,BUFFER_SIZE); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("port_thread failed, res = %s\n",error_strings[res])); return; } }
/* Construct a one-way message requesting complete termination of our partner CPU. */ static MME_ERROR createTerminateMMEMessage(TransportInfo_t *tpInfo, TransformerTerminateMMEMessage** buffer) { TransformerTerminateMMEMessage *message; EMBX_ERROR err; MME_Assert(manager); MME_Assert(tpInfo); MME_Assert(buffer); err = EMBX_Alloc(tpInfo->handle, sizeof(*message), (EMBX_VOID **) &message); if (EMBX_SUCCESS == err) { message->id = TMESSID_TERMINATE_MME; message->messageSize = sizeof(*message); message->result = MME_SUCCESS; *buffer = message; } /* map the EMBX error to an MME one */ return EMBX_SUCCESS == err ? MME_SUCCESS : EMBX_NOMEM == err ? MME_NOMEM : MME_EMBX_ERROR; }
/* Construct a two-way message to determine if the named transformer can be * instanciated by (has been registered on) a particular companion processor. */ static MME_ERROR createRegisteredMessage(TransportInfo_t *tpInfo, const char *name, TransformerRegisteredMessage **msg) { EMBX_ERROR err; void *buf; err = EMBX_Alloc(tpInfo->handle, sizeof(TransformerRegisteredMessage), &buf); if (EMBX_SUCCESS != err) { return EMBX_NOMEM == err ? MME_NOMEM : MME_EMBX_ERROR; } *msg = buf; (*msg)->id = TMESSID_TRANSFORMER_REGISTERED; (*msg)->messageSize = sizeof(TransformerRegisteredMessage); (*msg)->result = MME_UNKNOWN_TRANSFORMER; /* MULTIHOST support */ strcpy((*msg)->portName, tpInfo->replyPortName); strcpy((*msg)->transformerType, name); return MME_SUCCESS; }
int main() { EMBX_TRANSPORT hTrans; EMBX_PORT bufferpool, consumer, mypoolconnection; EMBX_ERROR err; int i; embxRuntimeInit(); err = EMBX_OpenTransport("shm", &hTrans); assert(EMBX_SUCCESS == err); /* Create the port which will hold the pool of work buffers */ err = EMBX_CreatePort(hTrans, "bufferpool", &bufferpool); assert(EMBX_SUCCESS == err); /* Make a connection to the port we just created so we can inject * empty buffers onto the port's queue as part of the initialization */ err = EMBX_Connect(hTrans, "bufferpool", &mypoolconnection); assert(EMBX_SUCCESS == err); /* Now wait for the consumer port to come into existence and * make a connection to it. */ err = EMBX_ConnectBlock(hTrans, "consumer", &consumer); assert(EMBX_SUCCESS == err); /* Inject empty buffers into the buffer pool */ for(i=0;i<BUFFER_POOL_SIZE;i++) { EMBX_VOID *buffer; err = EMBX_Alloc(hTrans, BUFFER_SIZE, &buffer); assert(EMBX_SUCCESS == err); /* Send empty buffer to the buffer pool port */ err = EMBX_SendMessage(mypoolconnection, buffer, 0); assert(EMBX_SUCCESS == err); } /* We don't need our connection to the buffer pool anymore * so close it down. */ EMBX_ClosePort(mypoolconnection); for(i=0;i<100;i++) { EMBX_RECEIVE_EVENT ev; EMBX_UINT buffersize; /* Jabber ... */ printf("producer: Issuing message %d of 100\n", i+1); /* Get an empty buffer from the pool */ err = EMBX_ReceiveBlock(bufferpool, &ev); assert(EMBX_SUCCESS == err); /* The event size field does not represent the actual * size of the buffer in this case, hence if you need * to find that out use the following. However in this * case where all the buffers are the same known size * it wouldn't be necessary expect as self checking debug. */ err = EMBX_GetBufferSize(ev.data, &buffersize); assert(EMBX_SUCCESS == err); /* Do something to fill the buffer with stuff to be used * by the consumer...... use your imagination ...... */ /* Now send the buffer to the consumer with the real amount * of data in the buffer as the size argument (this can be * less than the buffer size). For this example we assume * the whole buffer contains valid data. */ err = EMBX_SendMessage(consumer, ev.data, buffersize); assert(EMBX_SUCCESS == err); } /* Shut the communication system down. This has the side effect * of causing the consumer to also close down, almost certainly * before outstanding messages have been processed. */ EMBX_ClosePort(bufferpool); EMBX_ClosePort(consumer); EMBX_CloseTransport(hTrans); EMBX_Deinit(); return 0; }
int run_test(void) { EMBX_ERROR res; EMBX_TPINFO tpinfo1; EMBX_BOOL bFailed; EMBX_TRANSPORT tp; EMBX_PORT localPort,remotePort; EMBX_VOID *buffer1,*buffer2; EMBX_FACTORY factory; bFailed = EMBX_FALSE; tp = EMBX_INVALID_HANDLE_VALUE; buffer1 = buffer2 = 0; /* Test 1 */ res = EMBX_SendMessage(EMBX_INVALID_HANDLE_VALUE, buffer1, 0); if(res != EMBX_INVALID_PORT) { EMBX_Info(EMBX_TRUE, ("Test1 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } res = EMBX_RegisterTransport(EMBXLB_loopback_factory,&loopback_config,sizeof(EMBXLB_Config_t),&factory); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Transport Registration failed, res = %s, exiting\n",error_strings[res])); goto skip_remaining_tests; } /* Test 2 */ res = EMBX_Init(); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test2 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 3 */ res = EMBX_GetFirstTransport(&tpinfo1); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test3 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 4 */ res = EMBX_OpenTransport(tpinfo1.name, &tp); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test4 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 5 */ res = EMBX_CreatePort(tp, "testport", &localPort); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test5 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 6 */ res = EMBX_Connect(tp, "testport", &remotePort); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test6 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 7 */ res = EMBX_Alloc(tp, BUFFER_SIZE, &buffer1); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test7 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 8 */ res = EMBX_SendMessage(tp, buffer1, 0); if(res != EMBX_INVALID_PORT) { EMBX_Info(EMBX_TRUE, ("Test8 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } /* Test 9 */ res = EMBX_SendMessage(localPort, buffer1, 0); if(res != EMBX_INVALID_PORT) { EMBX_Info(EMBX_TRUE, ("Test9 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } /* Test 10 */ res = EMBX_SendMessage(remotePort, 0, 0); if(res != EMBX_INVALID_ARGUMENT) { EMBX_Info(EMBX_TRUE, ("Test10 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } /* Test 11 */ res = EMBX_SendMessage(remotePort, buffer1, BUFFER_SIZE+1); if(res != EMBX_INVALID_ARGUMENT) { EMBX_Info(EMBX_TRUE, ("Test11 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 12 */ res = EMBX_SendMessage(remotePort, buffer1, BUFFER_SIZE); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test12 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 13 - Ensure this allocation happens before buffer1 gets free'd * when the port is closed, so buffer1 and buffer2 will not point to * the same memory which is important for later tests. */ res = EMBX_Alloc(tp, BUFFER_SIZE, &buffer2); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test13 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 14 */ res = EMBX_ClosePort(localPort); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test14 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 15 - buffer1 has been freed by test14 so should be garbage */ res = EMBX_SendMessage(remotePort, buffer1, 0); if(res != EMBX_INVALID_ARGUMENT) { EMBX_Info(EMBX_TRUE, ("Test15 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } /* Test 16 */ res = EMBX_SendMessage(remotePort, buffer2, BUFFER_SIZE); if(res != EMBX_INVALID_PORT) { EMBX_Info(EMBX_TRUE, ("Test16 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 17 */ res = EMBX_ClosePort(remotePort); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test17 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 18 */ res = EMBX_CloseTransport(tp); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test18 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 19 */ res = EMBX_Deinit(); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test19 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* These test a different code path to the identical tests done before * EMBX_Init. */ /* Test 20 - Depends on buffer2 not having been freed so we get through * to checking the state of the driver. */ res = EMBX_SendMessage(remotePort, buffer2, 0); if(res != EMBX_INVALID_PORT) { EMBX_Info(EMBX_TRUE, ("Test20 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } /* Test 21 */ res = EMBX_UnregisterTransport(factory); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test21 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } return bFailed?-1:0; skip_remaining_tests: EMBX_Info(EMBX_TRUE, ("Skipping Remaining Tests\n")); return -1; }
int run_test(void) { EMBX_UINT i; EMBX_ERROR res; EMBX_TPINFO tpinfo1; EMBX_BOOL bFailed; EMBX_PORT localPort,remotePort; EMBX_VOID *buffer1; EMBX_FACTORY factory; EMBX_RECEIVE_EVENT ev; bFailed = EMBX_FALSE; buffer1 = 0; /* Test 1 */ res = EMBX_ReceiveBlock(EMBX_INVALID_HANDLE_VALUE, &ev); if(res != EMBX_INVALID_PORT) { EMBX_Info(EMBX_TRUE, ("Test1 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } res = EMBX_RegisterTransport(EMBXLB_loopback_factory, &loopback_config, sizeof(EMBXLB_Config_t), &factory); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Transport Registration failed, res = %s, exiting\n",error_strings[res])); goto skip_remaining_tests; } /* Test 2 */ res = EMBX_Init(); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test2 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 3 */ res = EMBX_GetFirstTransport(&tpinfo1); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test3 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 4 */ res = EMBX_OpenTransport(tpinfo1.name, &tp); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test4 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 5 */ res = EMBX_CreatePort(tp, "testport", &localPort); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test5 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 6 */ res = EMBX_Connect(tp, "testport", &remotePort); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test6 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 7 */ res = EMBX_ReceiveBlock(tp, &ev); if(res != EMBX_INVALID_PORT) { EMBX_Info(EMBX_TRUE, ("Test7 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } /* Test 8 */ res = EMBX_ReceiveBlock(remotePort, &ev); if(res != EMBX_INVALID_PORT) { EMBX_Info(EMBX_TRUE, ("Test8 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } /* Test 9 */ res = EMBX_ReceiveBlock(localPort, 0); if(res != EMBX_INVALID_ARGUMENT) { EMBX_Info(EMBX_TRUE, ("Test9 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } /* Test 10 */ res = EMBX_Alloc(tp, BUFFER_SIZE, &buffer1); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test10 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } for(i=0;i<BUFFER_SIZE;i++) { ((unsigned char *)buffer1)[i] = (unsigned char)i; } /* Test 11 */ res = EMBX_SendMessage(remotePort, buffer1, BUFFER_SIZE); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test11 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 12 */ res = EMBX_ReceiveBlock(localPort, &ev); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test12 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } if(ev.handle != EMBX_INVALID_HANDLE_VALUE || ev.offset != 0 || ev.type != EMBX_REC_MESSAGE || ev.size != BUFFER_SIZE) { EMBX_Info(EMBX_TRUE, ("Test13 failed, event structure incorrect\n")); goto skip_remaining_tests; } for(i=0;i<ev.size;i++) { if( ((unsigned char *)ev.data)[i] != (unsigned char)i ) { EMBX_Info(EMBX_TRUE, ("Test13 failed, buffer contents incorrect\n")); bFailed = EMBX_TRUE; break; } } /* Test 13 */ res = EMBX_Free(ev.data); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test13 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } if(!EMBX_OS_ThreadCreate(send_thread, (void *)remotePort, EMBX_DEFAULT_THREAD_PRIORITY, "send")) { EMBX_Info(EMBX_TRUE, ("Unable to create thread\n")); goto skip_remaining_tests; } /* Test 14 */ res = EMBX_ReceiveBlock(localPort, &ev); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test14 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } if(ev.handle != EMBX_INVALID_HANDLE_VALUE || ev.offset != 0 || ev.type != EMBX_REC_MESSAGE || ev.size != BUFFER_SIZE) { EMBX_Info(EMBX_TRUE, ("Test15 failed, event structure incorrect\n")); goto skip_remaining_tests; } /* Test 15 */ res = EMBX_Free(ev.data); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test15 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } /* Test 16 */ res = EMBX_ClosePort(remotePort); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test16 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 17 */ res = EMBX_ClosePort(localPort); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test17 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 18 */ res = EMBX_CloseTransport(tp); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test18 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* Test 19 */ res = EMBX_Deinit(); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test19 failed, res = %s\n",error_strings[res])); goto skip_remaining_tests; } /* These test a different code path to the identical tests done before * EMBX_Init */ /* Test 20 */ res = EMBX_ReceiveBlock(localPort, &ev); if(res != EMBX_INVALID_PORT) { EMBX_Info(EMBX_TRUE, ("Test20 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } /* Test 21 */ res = EMBX_UnregisterTransport(factory); if(res != EMBX_SUCCESS) { EMBX_Info(EMBX_TRUE, ("Test21 failed, res = %s\n",error_strings[res])); bFailed = EMBX_TRUE; } return bFailed?-1:0; skip_remaining_tests: EMBX_Info(EMBX_TRUE, ("Skipping Remaining Tests\n")); return -1; }
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; }