//-------------------------------------------------------------------------------------------------- void le_antenna_Init ( void ) { // Create safe reference map for antenna references. AntennaRefMap = le_ref_CreateMap("AntennaRef", LE_ANTENNA_MAX); memset( AntennaCtx, 0, LE_ANTENNA_MAX*sizeof(AntennaCtx_t) ); pa_antenna_AddStatusHandler ( AntennaStatus ); // Init the context le_antenna_Type_t antenna; for (antenna = LE_ANTENNA_PRIMARY_CELLULAR; antenna < LE_ANTENNA_MAX; antenna++) { char eventName[32]; snprintf(eventName, sizeof(eventName), "AntennaStatus_%d", antenna); AntennaCtx[antenna].antennaType = antenna; AntennaCtx[antenna].antennaRef = le_ref_CreateRef(AntennaRefMap, &AntennaCtx[antenna]); AntennaCtx[antenna].statusEventId = le_event_CreateId( eventName, sizeof(pa_antenna_StatusInd_t)); AntennaCtx[antenna].statusEventHandlerRef = NULL; } }
static void Handle_AddTestAHandler ( le_msg_MessageRef_t _msgRef ) { // Get the message buffer pointer uint8_t* _msgBufPtr = ((_Message_t*)le_msg_GetPayloadPtr(_msgRef))->buffer; // Needed if we are returning a result or output values uint8_t* _msgBufStartPtr = _msgBufPtr; // Unpack the input parameters from the message void* contextPtr; _msgBufPtr = UnpackData( _msgBufPtr, &contextPtr, sizeof(void*) ); // Create a new server data object and fill it in _ServerData_t* serverDataPtr = le_mem_ForceAlloc(_ServerDataPool); serverDataPtr->clientSessionRef = le_msg_GetSession(_msgRef); serverDataPtr->contextPtr = contextPtr; serverDataPtr->handlerRef = NULL; serverDataPtr->removeHandlerFunc = NULL; contextPtr = serverDataPtr; // Define storage for output parameters // Call the function TestAHandlerRef_t _result; _result = AddTestAHandler ( AsyncResponse_AddTestAHandler, contextPtr ); // Put the handler reference result and a pointer to the associated remove function // into the server data object. This function pointer is needed in case the client // is closed and the handlers need to be removed. serverDataPtr->handlerRef = (le_event_HandlerRef_t)_result; serverDataPtr->removeHandlerFunc = (RemoveHandlerFunc_t)RemoveTestAHandler; // Return a safe reference to the server data object as the reference. _LOCK _result = le_ref_CreateRef(_HandlerRefMap, serverDataPtr); _UNLOCK // Re-use the message buffer for the response _msgBufPtr = _msgBufStartPtr; // Pack the result first _msgBufPtr = PackData( _msgBufPtr, &_result, sizeof(_result) ); // Pack any "out" parameters // Return the response LE_DEBUG("Sending response to client session %p : %ti bytes sent", le_msg_GetSession(_msgRef), _msgBufPtr-_msgBufStartPtr); le_msg_Respond(_msgRef); }
//-------------------------------------------------------------------------------------------------- le_mrc_ScanInformation_Ref_t le_mrc_GetFirstCellularNetworkScan ( le_mrc_ScanInformation_ListRef_t scanInformationListRef ///< [IN] The list of scan information. ) { pa_mrc_ScanInformation_t* nodePtr; le_dls_Link_t* linkPtr; le_mrc_ScanInformationList_t* scanInformationListPtr = le_ref_Lookup(ScanInformationListRefMap, scanInformationListRef); if (scanInformationListPtr == NULL) { LE_KILL_CLIENT("Invalid reference (%p) provided!", scanInformationListRef); return NULL; } linkPtr = le_dls_Peek(&(scanInformationListPtr->paScanInformationList)); if (linkPtr != NULL) { nodePtr = CONTAINER_OF(linkPtr, pa_mrc_ScanInformation_t, link); scanInformationListPtr->currentLink = linkPtr; le_mrc_ScanInformationSafeRef_t* newScanInformationPtr = le_mem_ForceAlloc(ScanInformationSafeRefPool); newScanInformationPtr->safeRef = le_ref_CreateRef(ScanInformationRefMap,nodePtr); newScanInformationPtr->link = LE_DLS_LINK_INIT; le_dls_Queue(&(scanInformationListPtr->safeRefScanInformationList),&(newScanInformationPtr->link)); return (le_mrc_ScanInformation_Ref_t)newScanInformationPtr->safeRef; } else { return NULL; } }
//-------------------------------------------------------------------------------------------------- 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_cellnet_RequestObjRef_t le_cellnet_Request ( void ) { uint32_t command = REQUEST_COMMAND; le_event_Report(CommandEvent, &command, sizeof(command)); // Need to return a unique reference that will be used by Release. return le_ref_CreateRef(RequestRefMap, (void*)1); }
//-------------------------------------------------------------------------------------------------- le_event_FdMonitorRef_t le_event_CreateFdMonitor ( const char* name, ///< [in] Name of the object (for diagnostics). int fd ///< [in] File descriptor to be monitored for events. ) //-------------------------------------------------------------------------------------------------- { // Get a pointer to the thread-specific event loop data record. event_PerThreadRec_t* perThreadRecPtr = thread_GetEventRecPtr(); // Allocate the object. FdMonitor_t* fdMonitorPtr = le_mem_ForceAlloc(FdMonitorPool); // Initialize the object. fdMonitorPtr->link = LE_DLS_LINK_INIT; fdMonitorPtr->fd = fd; fdMonitorPtr->threadRecPtr = perThreadRecPtr; memset(fdMonitorPtr->handlerArray, 0, sizeof(fdMonitorPtr->handlerArray)); // To start with, no events are in the set to be monitored. They will be added as handlers // are registered for them. (Although, EPOLLHUP and EPOLLERR will always be monitored // regardless of what flags we specify). We use epoll in "level-triggered mode". fdMonitorPtr->epollEvents = 0; // Assume that the event should wake up the system; can be changed later. fdMonitorPtr->wakeUp = true; // Copy the name into it. if (le_utf8_Copy(fdMonitorPtr->name, name, sizeof(fdMonitorPtr->name), NULL) == LE_OVERFLOW) { LE_WARN("FD Monitor object name '%s' truncated to '%s'.", name, fdMonitorPtr->name); } LOCK // Create a safe reference for the object. fdMonitorPtr->safeRef = le_ref_CreateRef(FdMonitorRefMap, fdMonitorPtr); // Add it to the thread's FD Monitor list. le_dls_Queue(&perThreadRecPtr->fdMonitorList, &fdMonitorPtr->link); // Tell epoll(7) to start monitoring this fd. struct epoll_event ev; ev.events = fdMonitorPtr->epollEvents; ev.data.ptr = fdMonitorPtr->safeRef; if (epoll_ctl(perThreadRecPtr->epollFd, EPOLL_CTL_ADD, fd, &ev) == -1) { LE_FATAL("epoll_ctl(ADD) failed for fd %d. errno = %d (%m)", fd, errno); } UNLOCK return fdMonitorPtr->safeRef; }
//-------------------------------------------------------------------------------------------------- static ThreadObj_t* CreateThread ( const char* name, ///< [in] Name of the thread. le_thread_MainFunc_t mainFunc, ///< [in] The thread's main function. void* context ///< [in] Value to pass to mainFunc when it is called. ) { // Create a new thread object. ThreadObj_t* threadPtr = le_mem_ForceAlloc(ThreadPool); // Copy the name. We will make the names unique by adding the thread ID later so we allow any // string as the name. LE_WARN_IF(le_utf8_Copy(threadPtr->name, name, sizeof(threadPtr->name), NULL) == LE_OVERFLOW, "Thread name '%s' has been truncated to '%s'.", name, threadPtr->name); // Initialize the pthreads attribute structure. LE_ASSERT(pthread_attr_init(&(threadPtr->attr)) == 0); // Make sure when we create the thread it takes it attributes from the attribute object, // as opposed to inheriting them from its parent thread. if (pthread_attr_setinheritsched(&(threadPtr->attr), PTHREAD_EXPLICIT_SCHED) != 0) { LE_CRIT("Could not set scheduling policy inheritance for thread '%s'.", name); } // By default, Legato threads are not joinable (they are detached). if (pthread_attr_setdetachstate(&(threadPtr->attr), PTHREAD_CREATE_DETACHED) != 0) { LE_CRIT("Could not set the detached state for thread '%s'.", name); } threadPtr->isJoinable = false; threadPtr->isStarted = false; threadPtr->mainFunc = mainFunc; threadPtr->context = context; threadPtr->destructorList = LE_SLS_LIST_INIT; threadPtr->threadHandle = 0; memset(&threadPtr->mutexRec, 0, sizeof(threadPtr->mutexRec)); memset(&threadPtr->semaphoreRec, 0, sizeof(threadPtr->semaphoreRec)); memset(&threadPtr->eventRec, 0, sizeof(threadPtr->eventRec)); memset(&threadPtr->timerRec, 0, sizeof(threadPtr->timerRec)); // Create a safe reference for this object. Lock(); threadPtr->safeRef = le_ref_CreateRef(ThreadRefMap, threadPtr); Unlock(); return threadPtr; }
//-------------------------------------------------------------------------------------------------- le_mrc_ScanInformation_ListRef_t le_mrc_PerformCellularNetworkScan ( le_mrc_Rat_t ratMask ///< [IN] Technology mask ) { le_result_t result; le_mrc_ScanInformationList_t* newScanInformationListPtr = NULL; uint32_t networkScan = 0; newScanInformationListPtr = le_mem_ForceAlloc(ScanInformationListPool); newScanInformationListPtr->paScanInformationList = LE_DLS_LIST_INIT; newScanInformationListPtr->safeRefScanInformationList = LE_DLS_LIST_INIT; newScanInformationListPtr->currentLink = NULL; if (ratMask == LE_MRC_RAT_ALL) { networkScan |= PA_MRC_METWORK_MASK_GSM; networkScan |= PA_MRC_METWORK_MASK_UTMS; networkScan |= PA_MRC_METWORK_MASK_LTE; networkScan |= PA_MRC_METWORK_MASK_TD_SCDMA; } else { if (ratMask&LE_MRC_RAT_GSM) { networkScan |= PA_MRC_METWORK_MASK_GSM; } if (ratMask&LE_MRC_RAT_UTMS) { networkScan |= PA_MRC_METWORK_MASK_UTMS; } if (ratMask&LE_MRC_RAT_LTE) { networkScan |= PA_MRC_METWORK_MASK_LTE; } if (ratMask&LE_MRC_RAT_TC_SCDMA) { networkScan |= PA_MRC_METWORK_MASK_LTE; } } result = pa_mrc_PerformNetworkScan(networkScan,PA_MRC_SCAN_PLMN, &(newScanInformationListPtr->paScanInformationList)); if (result != LE_OK) { le_mem_Release(newScanInformationListPtr); return NULL; } return le_ref_CreateRef(ScanInformationListRefMap, newScanInformationListPtr); }
//-------------------------------------------------------------------------------------------------- le_event_FdHandlerRef_t le_event_SetFdHandler ( le_event_FdMonitorRef_t monitorRef, ///< [in] Reference to the File Descriptor Monitor object. le_event_FdEventType_t eventType, ///< [in] The type of event to be reported to this handler. le_event_FdHandlerFunc_t handlerFunc ///< [in] The handler function. ) //-------------------------------------------------------------------------------------------------- { LE_ASSERT(handlerFunc != NULL); // Look up the File Descriptor Monitor object using the safe reference provided. // Note that the safe reference map is shared by all threads in the process, so it // must be protected using the mutex. The File Descriptor Monitor objects, on the other // hand, are only allowed to be accessed by the one thread that created them, so it is // safe to unlock the mutex after doing the safe reference lookup. LOCK FdMonitor_t* monitorPtr = le_ref_Lookup(FdMonitorRefMap, monitorRef); UNLOCK LE_FATAL_IF(monitorPtr == NULL, "File Descriptor Monitor %p doesn't exist!", monitorRef); LE_FATAL_IF(thread_GetEventRecPtr() != monitorPtr->threadRecPtr, "FD Monitor '%s' (fd %d) is owned by another thread.", monitorPtr->name, monitorPtr->fd); // Get a pointer to the Handler object in the appropriate spot for this type of event in the // FD Monitor's array of handlers. Handler_t* handlerPtr = &(monitorPtr->handlerArray[eventType]); // Double check that no one has tried setting this handler yet. LE_FATAL_IF(handlerPtr->handlerFunc != NULL, "FD handler already set for event '%s' on FD Monitor '%s' (fd %d).", GetFdEventTypeName(eventType), monitorPtr->name, monitorPtr->fd); // Initialize the Handler object. handlerPtr->handlerFunc = handlerFunc; handlerPtr->contextPtr = NULL; handlerPtr->monitorPtr = monitorPtr; LOCK handlerPtr->safeRef = le_ref_CreateRef(HandlerRefMap, handlerPtr); UNLOCK // Enable the monitoring of this event. EnableFdMonitoring(monitorPtr, eventType); return handlerPtr->safeRef; }
//-------------------------------------------------------------------------------------------------- le_result_t mqtt_CreateSession ( const char* brokerURIPtr, ///< [IN] The URI of the MQTT broker to connect to. Should be in /// the form protocol://host:port. eg. tcp://1.2.3.4:1883 or /// ssl://example.com:8883 const char* clientIdPtr, ///< [IN] Any unique string. If a client connects to an MQTT /// broker using the same clientId as an existing session, then /// the existing session will be terminated. mqtt_SessionRef_t* sessionRefPtr ///< [OUT] The created session if the return result is LE_OK ) { mqtt_Session* s = le_mem_ForceAlloc(MQTTSessionPoolRef); LE_ASSERT(s); memset(s, 0, sizeof(*s)); const MQTTClient_connectOptions initConnOpts = MQTTClient_connectOptions_initializer; memcpy(&(s->connectOptions), &initConnOpts, sizeof(initConnOpts)); const MQTTClient_SSLOptions initSslOpts = MQTTClient_SSLOptions_initializer; memcpy(&(s->sslOptions), &initSslOpts, sizeof(initSslOpts)); s->sslOptions.trustStore = SslCaCertsPathPtr; const int createResult = MQTTClient_create( &(s->client), brokerURIPtr, clientIdPtr, MQTTCLIENT_PERSISTENCE_NONE, NULL); if (createResult != MQTTCLIENT_SUCCESS) { LE_ERROR("Couldn't create MQTT session. Paho error code: %d", createResult); le_mem_Release(s); return LE_FAULT; } le_msg_SessionRef_t clientSession = mqtt_GetClientSessionRef(); s->clientSession = clientSession; *sessionRefPtr = le_ref_CreateRef(SessionRefMap, s); LE_ASSERT(MQTTClient_setCallbacks( s->client, *sessionRefPtr, &ConnectionLostHandler, &MessageArrivedHandler, NULL) == MQTTCLIENT_SUCCESS); return LE_OK; }
//-------------------------------------------------------------------------------------------------- le_cfg_IteratorRef_t ni_CreateRef ( ni_IteratorRef_t iteratorRef ///< The iterator to generate a reference for. ) //-------------------------------------------------------------------------------------------------- { LE_ASSERT(iteratorRef != NULL); LE_ASSERT(iteratorRef->reference == NULL); iteratorRef->reference = le_ref_CreateRef(IteratorRefMap, iteratorRef); LE_DEBUG("Created a new reference <%p> for iterator <%p>.", iteratorRef->reference, iteratorRef); return iteratorRef->reference; }
//-------------------------------------------------------------------------------------------------- le_avdata_AssetInstanceRef_t le_avdata_Create ( const char* assetName ///< [IN] ) { // Get the client's credentials. pid_t pid; uid_t uid; if (le_msg_GetClientUserCreds(le_avdata_GetClientSessionRef(), &uid, &pid) != LE_OK) { LE_KILL_CLIENT("Could not get credentials for the client."); return NULL; } // Look up the process's application name. char appName[LE_LIMIT_APP_NAME_LEN+1]; le_result_t result = le_appInfo_GetName(pid, appName, sizeof(appName)); LE_FATAL_IF(result == LE_OVERFLOW, "Buffer too small to contain the application name."); // TODO: Should this be LE_KILL_CLIENT instead? LE_FATAL_IF(result != LE_OK, "Could not get app name"); // Create an instance of the asset assetData_InstanceDataRef_t instRef; int instanceId; LE_ASSERT( assetData_CreateInstanceByName(appName, assetName, -1, &instRef) == LE_OK ); LE_ASSERT( instRef != NULL ); LE_ASSERT( assetData_GetInstanceId(instRef, &instanceId) == LE_OK ); LE_PRINT_VALUE("%i", instanceId); // Return a safe reference for the instance InstanceRefData_t* instRefDataPtr = le_mem_ForceAlloc(InstanceRefDataPoolRef); instRefDataPtr->clientSessionRef = le_avdata_GetClientSessionRef(); instRefDataPtr->instRef = instRef; instRef = le_ref_CreateRef(InstanceRefMap, instRefDataPtr); return instRef; }
//-------------------------------------------------------------------------------------------------- le_pm_WakeupSourceRef_t le_pm_NewWakeupSource(uint32_t opts, const char *tag) { WakeupSource_t *ws; Client_t *cl; char name[LEGATO_WS_NAME_LEN]; if (!tag || *tag == '\0' || strlen(tag) > LE_PM_TAG_LEN) { LE_KILL_CLIENT("Error: Tag value is invalid or NULL."); return NULL; } // Find and validate client record cl = to_Client_t(le_hashmap_Get(PowerManager.clients, le_pm_GetClientSessionRef())); // Check if identical wakeup source already exists for this client sprintf(name, LEGATO_WS_NAME_FORMAT, tag, cl->pid); // Lookup wakeup source by name ws = (WakeupSource_t*)le_hashmap_Get(PowerManager.locks, name); if (ws) { LE_KILL_CLIENT("Error: Tag '%s' already exists.", tag); return NULL; } // Allocate and populate wakeup source record (exits on error) ws = (WakeupSource_t*)le_mem_ForceAlloc(PowerManager.lpool); ws->cookie = PM_WAKEUP_SOURCE_COOKIE; strcpy(ws->name, name); ws->taken = LE_OFF; ws->pid = cl->pid; ws->wsref = le_ref_CreateRef(PowerManager.refs, ws); // Store record in table of wakeup sources if (le_hashmap_Put(PowerManager.locks, ws->name, ws)) LE_FATAL("Error adding wakeup source '%s'.", ws->name); LE_INFO("Created new wakeup source '%s' for pid %d.", ws->name, ws->pid); return (le_pm_WakeupSourceRef_t)ws->wsref; }
//-------------------------------------------------------------------------------------------------- static le_mcc_Call_t* CreateCallObject ( const char* destinationPtr, int16_t id, le_mcc_Event_t event, le_mcc_TerminationReason_t termination, int32_t terminationCode ) { le_mcc_Call_t* callPtr = NULL; // New call callPtr = (le_mcc_Call_t*)le_mem_ForceAlloc(MccCallPool); if (!callPtr) { LE_ERROR("callPtr null !!!!"); return NULL; } le_utf8_Copy(callPtr->telNumber, destinationPtr, sizeof(callPtr->telNumber), NULL); callPtr->callId = id; callPtr->event = event; callPtr->termination = termination; callPtr->terminationCode = terminationCode; callPtr->clirStatus = PA_MCC_DEACTIVATE_CLIR; callPtr->inProgress = false; callPtr->refCount = 1; callPtr->sessionRefList=LE_DLS_LIST_INIT; // Create a Safe Reference for this Call object. callPtr->callRef = le_ref_CreateRef(MccCallRefMap, callPtr); // Update reference count UpdateReferenceCount(callPtr); return callPtr; }
//-------------------------------------------------------------------------------------------------- le_avdata_RequestSessionObjRef_t le_avdata_RequestSession ( void ) { le_result_t result = LE_OK; // If this is a duplicate request send the existing reference. le_ref_IterRef_t iterRef = le_ref_GetIterator(AvSessionRequestRefMap); while (le_ref_NextNode(iterRef) == LE_OK) { if (le_ref_GetValue(iterRef) == le_avdata_GetClientSessionRef()) { LE_DEBUG("Duplicate session request from client."); return (le_avdata_RequestSessionObjRef_t) le_ref_GetSafeRef(iterRef); } } le_timer_Stop(SessionReleaseTimerRef); // Ask the avc server to pass the request to control app or to initiate a session. result = avcServer_RequestSession(); // If the fresh request fails, return NULL. if (result != LE_OK) { return NULL; } // Need to return a unique reference that will be used by release. Use the client session ref // as the data, since we need to delete the ref when the client closes. le_avdata_RequestSessionObjRef_t requestRef = le_ref_CreateRef(AvSessionRequestRefMap, le_avdata_GetClientSessionRef()); return requestRef; }
//-------------------------------------------------------------------------------------------------- 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; }
//-------------------------------------------------------------------------------------------------- le_fdMonitor_Ref_t le_fdMonitor_Create ( const char* name, ///< [in] Name of the object (for diagnostics). int fd, ///< [in] File descriptor to be monitored for events. le_fdMonitor_HandlerFunc_t handlerFunc, ///< [in] Handler function. short events ///< [in] Initial set of events to be monitored. ) //-------------------------------------------------------------------------------------------------- { // Get a pointer to the thread-specific event loop data record. event_PerThreadRec_t* perThreadRecPtr = thread_GetEventRecPtr(); // Allocate the object. FdMonitor_t* fdMonitorPtr = le_mem_ForceAlloc(FdMonitorPool); // Initialize the object. fdMonitorPtr->link = LE_DLS_LINK_INIT; fdMonitorPtr->fd = fd; fdMonitorPtr->epollEvents = PollToEPoll(events) | EPOLLWAKEUP; // Non-deferrable by default. fdMonitorPtr->isAlwaysReady = false; fdMonitorPtr->threadRecPtr = perThreadRecPtr; fdMonitorPtr->handlerFunc = handlerFunc; fdMonitorPtr->contextPtr = NULL; // Copy the name into it. if (le_utf8_Copy(fdMonitorPtr->name, name, sizeof(fdMonitorPtr->name), NULL) == LE_OVERFLOW) { LE_WARN("FD Monitor object name '%s' truncated to '%s'.", name, fdMonitorPtr->name); } LOCK // Create a safe reference for the object. fdMonitorPtr->safeRef = le_ref_CreateRef(FdMonitorRefMap, fdMonitorPtr); // Add it to the thread's FD Monitor list. le_dls_Queue(&perThreadRecPtr->fdMonitorList, &fdMonitorPtr->link); // Tell epoll(7) to start monitoring this fd. struct epoll_event ev; memset(&ev, 0, sizeof(ev)); ev.events = fdMonitorPtr->epollEvents; ev.data.ptr = fdMonitorPtr->safeRef; if (epoll_ctl(perThreadRecPtr->epollFd, EPOLL_CTL_ADD, fd, &ev) == -1) { if (errno == EPERM) { LE_DEBUG("fd %d doesn't support epoll(), assuming always readable and writeable.", fd); fdMonitorPtr->isAlwaysReady = true; // If either EPOLLIN or EPOLLOUT are enabled, queue up the handler for this now. uint32_t epollEvents = fdMonitorPtr->epollEvents & (EPOLLIN | EPOLLOUT); if (epollEvents != 0) { fdMon_Report(fdMonitorPtr->safeRef, epollEvents); } } else { LE_FATAL("epoll_ctl(ADD) failed for fd %d. errno = %d (%m)", fd, errno); } } UNLOCK return fdMonitorPtr->safeRef; }