opc source code
This commit is contained in:
173
third_party/open62541/arch/eventloop_posix_select.c
vendored
Normal file
173
third_party/open62541/arch/eventloop_posix_select.c
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
/* 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) */
|
||||
Reference in New Issue
Block a user