Files
softbus_OPC/third_party/open62541/arch/eventloop_posix_select.c
2026-06-09 17:27:24 +08:00

174 lines
5.3 KiB
C

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
*/
#include "eventloop_posix.h"
#if !defined(UA_HAVE_EPOLL)
UA_StatusCode
UA_EventLoopPOSIX_registerFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
UA_LOCK_ASSERT(&el->elMutex, 1);
UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
"Registering fd: %u", (unsigned)rfd->fd);
/* Realloc */
UA_RegisteredFD **fds_tmp = (UA_RegisteredFD**)
UA_realloc(el->fds, sizeof(UA_RegisteredFD*) * (el->fdsSize + 1));
if(!fds_tmp) {
return UA_STATUSCODE_BADOUTOFMEMORY;
}
el->fds = fds_tmp;
/* Add to the last entry */
el->fds[el->fdsSize] = rfd;
el->fdsSize++;
return UA_STATUSCODE_GOOD;
}
UA_StatusCode
UA_EventLoopPOSIX_modifyFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
/* Do nothing, it is enough if the data was changed in the rfd */
UA_LOCK_ASSERT(&el->elMutex, 1);
return UA_STATUSCODE_GOOD;
}
void
UA_EventLoopPOSIX_deregisterFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
UA_LOCK_ASSERT(&el->elMutex, 1);
UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
"Unregistering fd: %u", (unsigned)rfd->fd);
/* Find the entry */
size_t i = 0;
for(; i < el->fdsSize; i++) {
if(el->fds[i] == rfd)
break;
}
/* Not found? */
if(i == el->fdsSize)
return;
if(el->fdsSize > 1) {
/* Move the last entry in the ith slot and realloc. */
el->fdsSize--;
el->fds[i] = el->fds[el->fdsSize];
UA_RegisteredFD **fds_tmp = (UA_RegisteredFD**)
UA_realloc(el->fds, sizeof(UA_RegisteredFD*) * el->fdsSize);
/* if realloc fails the fds are still in a correct state with
* possibly lost memory, so failing silently here is ok */
if(fds_tmp)
el->fds = fds_tmp;
} else {
/* Remove the last entry */
UA_free(el->fds);
el->fds = NULL;
el->fdsSize = 0;
}
}
static UA_FD
setFDSets(UA_EventLoopPOSIX *el, fd_set *readset, fd_set *writeset, fd_set *errset) {
UA_LOCK_ASSERT(&el->elMutex, 1);
FD_ZERO(readset);
FD_ZERO(writeset);
FD_ZERO(errset);
UA_FD highestfd = UA_INVALID_FD;
for(size_t i = 0; i < el->fdsSize; i++) {
UA_FD currentFD = el->fds[i]->fd;
/* Add to the fd_sets */
if(el->fds[i]->listenEvents & UA_FDEVENT_IN)
FD_SET(currentFD, readset);
if(el->fds[i]->listenEvents & UA_FDEVENT_OUT)
FD_SET(currentFD, writeset);
/* Always return errors */
FD_SET(currentFD, errset);
/* Highest fd? */
if(currentFD > highestfd || highestfd == UA_INVALID_FD)
highestfd = currentFD;
}
return highestfd;
}
UA_StatusCode
UA_EventLoopPOSIX_pollFDs(UA_EventLoopPOSIX *el, UA_DateTime listenTimeout) {
UA_assert(listenTimeout >= 0);
UA_LOCK_ASSERT(&el->elMutex, 1);
fd_set readset, writeset, errset;
UA_FD highestfd = setFDSets(el, &readset, &writeset, &errset);
/* Nothing to do? */
if(highestfd == UA_INVALID_FD) {
UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
"No valid FDs for processing");
return UA_STATUSCODE_GOOD;
}
struct timeval tmptv = {
#ifndef _WIN32
(time_t)(listenTimeout / UA_DATETIME_SEC),
(suseconds_t)((listenTimeout % UA_DATETIME_SEC) / UA_DATETIME_USEC)
#else
(long)(listenTimeout / UA_DATETIME_SEC),
(long)((listenTimeout % UA_DATETIME_SEC) / UA_DATETIME_USEC)
#endif
};
UA_UNLOCK(&el->elMutex);
int selectStatus = UA_select(highestfd+1, &readset, &writeset, &errset, &tmptv);
UA_LOCK(&el->elMutex);
if(selectStatus < 0) {
/* We will retry, only log the error */
UA_LOG_SOCKET_ERRNO_WRAP(
UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
"Error during select: %s", errno_str));
return UA_STATUSCODE_GOOD;
}
/* Loop over all registered FD to see if an event arrived. Yes, this is why
* select is slow for many open sockets. */
for(size_t i = 0; i < el->fdsSize; i++) {
UA_RegisteredFD *rfd = el->fds[i];
/* The rfd is already registered for removal. Don't process incoming
* events any longer. */
if(rfd->dc.callback)
continue;
/* Event signaled for the fd? */
short event = 0;
if(FD_ISSET(rfd->fd, &readset)) {
event = UA_FDEVENT_IN;
} else if(FD_ISSET(rfd->fd, &writeset)) {
event = UA_FDEVENT_OUT;
} else if(FD_ISSET(rfd->fd, &errset)) {
event = UA_FDEVENT_ERR;
} else {
continue;
}
UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
"Processing event %u on fd %u", (unsigned)event,
(unsigned)rfd->fd);
/* Call the EventSource callback */
rfd->eventSourceCB(rfd->es, rfd, event);
/* The fd has removed itself */
if(i == el->fdsSize || rfd != el->fds[i])
i--;
}
return UA_STATUSCODE_GOOD;
}
#endif /* !defined(UA_HAVE_EPOLL) */