Files
aqhomecontrol/aqhome/events2/eventloop_select.c
2025-02-27 14:08:44 +01:00

174 lines
4.0 KiB
C

/****************************************************************************
* 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 <config.h>
#endif
#include "./eventloop_p.h"
#include "./fdobject.h"
#include <gwenhywfar/debug.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <errno.h>
#include <string.h>
/* ------------------------------------------------------------------------------------------------
* 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);
}
}