//-------------------------------------------------------------------------------------------------- le_msg_SessionEventHandlerRef_t le_msg_AddServiceCloseHandler ( le_msg_ServiceRef_t serviceRef, ///< [in] Reference to the service. le_msg_SessionEventHandler_t handlerFunc,///< [in] Handler function. void* contextPtr ///< [in] Opaque pointer value to pass to handler. ) //-------------------------------------------------------------------------------------------------- { LE_FATAL_IF(serviceRef == NULL, "Service doesn't exist. Make sure service is started before setting handlers"); LE_FATAL_IF(serviceRef->serverThread != le_thread_GetCurrent(), "Service (%s:%s) not owned by calling thread.", serviceRef->id.name, le_msg_GetProtocolIdStr(serviceRef->id.protocolRef)); // Create the node. SessionEventHandler_t* closeEventPtr = le_mem_ForceAlloc(HandlerEventPoolRef); // Initialize the node. closeEventPtr->handler = handlerFunc; closeEventPtr->contextPtr = contextPtr; closeEventPtr->link = LE_DLS_LINK_INIT; closeEventPtr->listPtr = &serviceRef->closeListPtr; // Add the node to the head of the list by passing in the node's link. le_dls_Stack(&serviceRef->closeListPtr, &closeEventPtr->link); // Need to return a unique reference that will be used by the remove function. closeEventPtr->ref = le_ref_CreateRef(HandlersRefMap, &closeEventPtr->link); return closeEventPtr->ref; }
//-------------------------------------------------------------------------------------------------- le_msg_ServiceRef_t le_msg_CreateService ( le_msg_ProtocolRef_t protocolRef, ///< [in] Reference to the protocol to be used. const char* serviceName ///< [in] The service instance name. ) //-------------------------------------------------------------------------------------------------- { // Must lock the mutex to prevent races between different threads trying to offer the // same service at the same time, or one thread trying to delete a service while another // tries to create it, or accessing the Service List hashmap while another thread // is updating it. LOCK // Get a Service object. Service_t* servicePtr = GetService(protocolRef, serviceName); // If the Service object already has a server thread, then it means that this service // is already being offered by someone else in this very process. LE_FATAL_IF(servicePtr->serverThread != NULL, "Duplicate service (%s:%s) offered in same process.", serviceName, le_msg_GetProtocolIdStr(protocolRef)); servicePtr->serverThread = le_thread_GetCurrent(); UNLOCK return servicePtr; }
//-------------------------------------------------------------------------------------------------- void le_msg_DeleteService ( le_msg_ServiceRef_t serviceRef ///< [in] Reference to the service. ) //-------------------------------------------------------------------------------------------------- { LE_FATAL_IF(serviceRef->serverThread != le_thread_GetCurrent(), "Attempted to delete service (%s:%s) not owned by thread.", serviceRef->id.name, le_msg_GetProtocolIdStr(serviceRef->id.protocolRef)); // If the service is still advertised, hide it. le_msg_HideService(serviceRef); // Close any remaining open sessions. CloseAllSessions(serviceRef); // NOTE: Lock the mutex here to prevent a race between this thread dropping ownership // of the service and another thread trying to offer the same service. This is very // unlikely to ever happen, but just in case, make sure it fails with a sensible // ("duplicate") log message, instead of just quietly messing up the hashmap or something. LOCK // Clear out the server thread reference. serviceRef->serverThread = NULL; // Release the server's hold on the object. le_mem_Release(serviceRef); UNLOCK }
//-------------------------------------------------------------------------------------------------- void AdvertiseService ( void ) { LE_DEBUG("======= Starting Server %s ========", SERVICE_INSTANCE_NAME); le_msg_ProtocolRef_t protocolRef; // Create the server data pool _ServerDataPool = le_mem_CreatePool("ServerData", sizeof(_ServerData_t)); // Create safe reference map for handler references. // The size of the map should be based on the number of handlers defined for the server. // Don't expect that to be more than 2-3, so use 3 as a reasonable guess. _HandlerRefMap = le_ref_CreateMap("ServerHandlers", 3); // Start the server side of the service protocolRef = le_msg_GetProtocolRef(PROTOCOL_ID_STR, sizeof(_Message_t)); _ServerServiceRef = le_msg_CreateService(protocolRef, SERVICE_INSTANCE_NAME); le_msg_SetServiceRecvHandler(_ServerServiceRef, ServerMsgRecvHandler, NULL); le_msg_AdvertiseService(_ServerServiceRef); // Register for client sessions being closed le_msg_AddServiceCloseHandler(_ServerServiceRef, CleanupClientData, NULL); // Need to keep track of the thread that is registered to provide this service. _ServerThreadRef = le_thread_GetCurrent(); }
// A thread "main" function which creates a series of sems. static void* ThreadCreateSem ( void* context ) { char semNameBuffer[LIMIT_MAX_SEMAPHORE_NAME_BYTES] = {0}; LE_INFO("Thread [%s] has started. Waiting on a semaphore.", le_thread_GetMyName()); le_mutex_Lock(SemIndexMutexRef); snprintf(semNameBuffer, LIMIT_MAX_SEMAPHORE_NAME_BYTES, "[%s]Sem%ld", le_thread_GetMyName(), SemCreateIdx); le_sem_Ref_t sem = le_sem_Create(semNameBuffer, 0); SemRefArray[SemCreateIdx] = (SemRef_t){le_thread_GetCurrent(), sem}; SemCreateIdx++; le_mutex_Unlock(SemIndexMutexRef); LE_INFO("In thread [%s], about to wait sem", le_thread_GetMyName()); // notify the calling thread that this thread is about to wait on its sema. le_sem_Post(SemaRef); le_sem_Wait(sem); LE_INFO("In thread [%s], sema is posted", le_thread_GetMyName()); le_event_RunLoop(); return NULL; }
// Delete all mutexes for the first thread. static void DelAllMutexesFor1stThread ( void* param1, void* param2 ) { LE_INFO("DelAllMutexesFor1stThread in thread [%s]", le_thread_GetMyName()); // Determine if this is the "1st" thread on the thread list. If so, delete all mutexes. if (le_thread_GetCurrent() == ThreadRefArray[0]) { LE_INFO("This thread is the 1st thread in the thread list - deleting all mutexes."); DelMutexes(0, 0); } }
//-------------------------------------------------------------------------------------------------- void le_msg_SetServiceRecvHandler ( le_msg_ServiceRef_t serviceRef, ///< [in] Reference to the service. le_msg_ReceiveHandler_t handlerFunc,///< [in] Handler function. void* contextPtr ///< [in] Opaque pointer value to pass to the handler. ) //-------------------------------------------------------------------------------------------------- { LE_FATAL_IF(serviceRef->serverThread != le_thread_GetCurrent(), "Service (%s:%s) not owned by calling thread.", serviceRef->id.name, le_msg_GetProtocolIdStr(serviceRef->id.protocolRef)); serviceRef->recvHandler = handlerFunc; serviceRef->recvContextPtr = contextPtr; }
// Delete all mutexes for a thread in the middle. static void DelAllMutexesForMidThread ( void* param1, void* param2 ) { LE_INFO("DelAllMutexesForMidThread in thread [%s]", le_thread_GetMyName()); long midIdx = ThreadNum / 2; // Determine if this is the "mid" thread on the thread list. If so, delete all mutexes. if (le_thread_GetCurrent() == ThreadRefArray[midIdx]) { LE_INFO("This thread is the mid thread in the thread list - deleting all mutexes."); DelMutexes(0, 0); } }
//-------------------------------------------------------------------------------------------------- __attribute__((unused)) static void SendMsgToClient ( le_msg_MessageRef_t msgRef ///< [in] Reference to the message. ) { /* * If called from a thread other than the server thread, queue the message onto the server * thread. This is necessary to allow async response/handler functions to be called from any * thread, whereas messages to the client can only be sent from the server thread. */ if ( le_thread_GetCurrent() != _ServerThreadRef ) { le_event_QueueFunctionToThread(_ServerThreadRef, SendMsgToClientQueued, msgRef, NULL); } else { le_msg_Send(msgRef); } }
//-------------------------------------------------------------------------------------------------- BugTestRef_t AddBugTest ( const char* newPathPtr, ///< [IN] BugTestFunc_t handlerPtr, ///< [IN] void* contextPtr ///< [IN] ) { le_msg_MessageRef_t _msgRef; le_msg_MessageRef_t _responseMsgRef; _Message_t* _msgPtr; // Will not be used if no data is sent/received from server. __attribute__((unused)) uint8_t* _msgBufPtr; BugTestRef_t _result; // Range check values, if appropriate if ( strlen(newPathPtr) > 512 ) LE_FATAL("strlen(newPathPtr) > 512"); // Create a new message object and get the message buffer _msgRef = le_msg_CreateMsg(GetCurrentSessionRef()); _msgPtr = le_msg_GetPayloadPtr(_msgRef); _msgPtr->id = _MSGID_AddBugTest; _msgBufPtr = _msgPtr->buffer; // Pack the input parameters _msgBufPtr = PackString( _msgBufPtr, newPathPtr ); // The input parameters are stored in the client data object, and it is // a pointer to this object that is passed down. // Create a new client data object and fill it in _ClientData_t* _clientDataPtr = le_mem_ForceAlloc(_ClientDataPool); _clientDataPtr->handlerPtr = (le_event_HandlerFunc_t)handlerPtr; _clientDataPtr->contextPtr = contextPtr; _clientDataPtr->callersThreadRef = le_thread_GetCurrent(); contextPtr = _clientDataPtr; _msgBufPtr = PackData( _msgBufPtr, &contextPtr, sizeof(void*) ); // Send a request to the server and get the response. LE_DEBUG("Sending message to server and waiting for response"); _responseMsgRef = le_msg_RequestSyncResponse(_msgRef); // It is a serious error if we don't get a valid response from the server LE_FATAL_IF(_responseMsgRef == NULL, "Valid response was not received from server"); // Process the result and/or output parameters, if there are any. _msgPtr = le_msg_GetPayloadPtr(_responseMsgRef); _msgBufPtr = _msgPtr->buffer; // Unpack the result first _msgBufPtr = UnpackData( _msgBufPtr, &_result, sizeof(_result) ); // Put the handler reference result into the client data object, and // then return a safe reference to the client data object as the reference. _clientDataPtr->handlerRef = (le_event_HandlerRef_t)_result; _LOCK _result = le_ref_CreateRef(_HandlerRefMap, _clientDataPtr); _UNLOCK // Unpack any "out" parameters // Release the message object, now that all results/output has been copied. le_msg_ReleaseMsg(_responseMsgRef); return _result; }