abort process if too many select errors. Prevents error logs from filling log partition. after 90 select errors the log level will be increased for the next calls. after 100 select errors the process aborts (will be restarted by systemd). TODO: inspect sockets to find the bad one.
190 lines
4.5 KiB
C
190 lines
4.5 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)
|
|
{
|
|
static int selectErrorCount=0;
|
|
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 */
|
|
if (selectErrorCount)
|
|
selectErrorCount--;
|
|
_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));
|
|
selectErrorCount++;
|
|
/* TODO: walk through all sockets to find the bad one */
|
|
if (selectErrorCount==90) {
|
|
/* increase log level */
|
|
DBG_ERROR(AQH_LOGDOMAIN, "Increasing log level to INFO");
|
|
GWEN_Logger_SetLevel(AQH_LOGDOMAIN, GWEN_LoggerLevel_Info);
|
|
}
|
|
else if (selectErrorCount==100) {
|
|
DBG_ERROR(AQH_LOGDOMAIN, "Aborting due to too many SELECT errors, will be restarted by systemd");
|
|
abort();
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
/* no fd became active (TODO: maybe signal deep idle objects?) */
|
|
if (selectErrorCount)
|
|
selectErrorCount--;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|