/**************************************************************************** * This file is part of the project AqHome. * AqHome (c) by 2025 Martin Preuss, all rights reserved. * * The license for this file can be found in the file COPYING which you * should have received along with this file. ****************************************************************************/ #ifdef HAVE_CONFIG_H # include #endif #include "./eventloop_p.h" #include "./fdobject.h" #include #include #include #include #include #include /* ------------------------------------------------------------------------------------------------ * forward declarations * ------------------------------------------------------------------------------------------------ */ static int _sampleFdsIntoSet(AQH_OBJECT_LIST2 *ol, fd_set *fds, int mode); static void _markReadyFdObjects(AQH_OBJECT_LIST2 *ol, fd_set *fds, int mode); static void _signalReadyFdObjects(AQH_OBJECT_LIST2 *ol); /* ------------------------------------------------------------------------------------------------ * code * ------------------------------------------------------------------------------------------------ */ void AQH_EventLoop_Run(AQH_EVENT_LOOP *eventLoop, int timeoutInMillisecs) { fd_set fdRead; fd_set fdWrite; int highestFd=-1; int rv; FD_ZERO(&fdRead); FD_ZERO(&fdWrite); highestFd=_sampleFdsIntoSet(eventLoop->fdObjectList, &fdRead, AQH_FDOBJECT_FDMODE_READ); rv=_sampleFdsIntoSet(eventLoop->fdObjectList, &fdWrite, AQH_FDOBJECT_FDMODE_WRITE); highestFd=(rv>highestFd)?rv:highestFd; if (highestFd>-1) { struct timeval tv; tv.tv_sec=timeoutInMillisecs/1000; tv.tv_usec=(timeoutInMillisecs%1000)*1000; rv=select(highestFd+1, &fdRead, &fdWrite, NULL, &tv); if (rv>0) { /* some fds became active */ _markReadyFdObjects(eventLoop->fdObjectList, &fdRead, AQH_FDOBJECT_FDMODE_READ); _markReadyFdObjects(eventLoop->fdObjectList, &fdWrite, AQH_FDOBJECT_FDMODE_WRITE); _signalReadyFdObjects(eventLoop->fdObjectList); } else if (rv<0) { if (errno!=EINTR) { /* error */ DBG_ERROR(AQH_LOGDOMAIN, "Error on SELECT: %d (%s)", errno, strerror(errno)); } } else { /* no fd became active (TODO: maybe signal deep idle objects?) */ } } } int _sampleFdsIntoSet(AQH_OBJECT_LIST2 *ol, fd_set *fds, int mode) { AQH_OBJECT_LIST2_ITERATOR *it; int highestFd=-1; it=AQH_Object_List2_First(ol); if (it) { AQH_OBJECT *o; o=AQH_Object_List2Iterator_Data(it); while(o) { int m; m=AQH_FdObject_GetFdMode(o); if (m==mode) { int fd; fd=AQH_FdObject_GetFd(o); if (fd>-1) { highestFd=(fd>highestFd)?fd:highestFd; FD_SET(fd, fds); } } o=AQH_Object_List2Iterator_Next(it); } AQH_Object_List2Iterator_free(it); } return highestFd; } void _markReadyFdObjects(AQH_OBJECT_LIST2 *ol, fd_set *fds, int mode) { AQH_OBJECT_LIST2_ITERATOR *it; it=AQH_Object_List2_First(ol); if (it) { AQH_OBJECT *o; o=AQH_Object_List2Iterator_Data(it); while(o) { int m; m=AQH_FdObject_GetFdMode(o); if (m==mode) { int fd; fd=AQH_FdObject_GetFd(o); if (FD_ISSET(fd, fds)) AQH_Object_AddFlags(o, AQH_OBJECT_FLAGS_FIRE); } o=AQH_Object_List2Iterator_Next(it); } AQH_Object_List2Iterator_free(it); } } void _signalReadyFdObjects(AQH_OBJECT_LIST2 *ol) { AQH_OBJECT_LIST2_ITERATOR *it; it=AQH_Object_List2_First(ol); if (it) { AQH_OBJECT *o; o=AQH_Object_List2Iterator_Data(it); while(o) { if (AQH_Object_GetFlags(o) & AQH_OBJECT_FLAGS_FIRE) { AQH_Object_SubFlags(o, AQH_OBJECT_FLAGS_FIRE); AQH_Object_EmitSignal(o, AQH_FDOBJECT_SIGNAL_ISREADY, 0, NULL); } o=AQH_Object_List2Iterator_Next(it); } AQH_Object_List2Iterator_free(it); } }