/* * Select.cpp * * Created on: 13 May 2016 * Author: wentzelc */ // redA Libraries #include "SelectableCore.h" #include "TimingCore.h" #include "LogCore.h" // Standard C/C++ Libraries #include #include #include #include //--------------------------------------------------------------------------- extern char ProcessName[]; //--------------------------------------------------------------------------- // Create Select CSelect::CSelect( long SelectTimeout ) { // Clear List FirstHandle = NULL; // Clear Select sets FD_ZERO( &ReadTestFDS ); FD_ZERO( &WriteTestFDS ); // Reset maximum File Descriptor MaxFD = 0; // Set Timeout SetInterval( &Timeout, SelectTimeout ); // Show status LogMessage( dlLow, "%s: Select - Created", ProcessName ); } //--------------------------------------------------------------------------- // Destroy Select CSelect::~CSelect() { TSelectHandle * NextHandle; // Destroy handles while (FirstHandle) { NextHandle = FirstHandle->Next; free( FirstHandle ); FirstHandle = NextHandle; } // Show status LogMessage( dlLow, "%s: Select - Destroyed", ProcessName ); return; } //--------------------------------------------------------------------------- // Clear Select File Descriptors void CSelect::Clear() { // Clear Select sets FD_ZERO( &ReadTestFDS ); FD_ZERO( &WriteTestFDS ); // Reset maximum File Descriptor MaxFD = 0; } //--------------------------------------------------------------------------- // Add Select File Descriptor void CSelect::Add( int FD, bool Read, bool Write, CSelectableCore * Function ) { TSelectHandle ** Handle = NULL; // Check if Handle already exists Handle = &FirstHandle; while (*Handle && ((*Handle)->FD != FD)) { Handle = &((*Handle)->Next); } // Create if not exist if (!*Handle) { // Create *Handle = (TSelectHandle*)malloc( sizeof(TSelectHandle) ); memset( *Handle, 0, sizeof(TSelectHandle) ); // Set Parameters (*Handle)->FD = FD; (*Handle)->Function = Function; } // Add Read select if (Read && !(*Handle)->Read) { (*Handle)->Read = true; FD_SET( FD, &ReadTestFDS ); // Log event LogMessage( dlHigh, "Select: FD [%d] - Add Read", FD ); } // Add Write Select if (Write && !(*Handle)->Write) { (*Handle)->Write = true; FD_SET( FD, &WriteTestFDS ); // Log event LogMessage( dlHigh, "Select: FD [%d] - Add Write", FD ); } // Check Maximum File Handle if (MaxFD <= FD) MaxFD = FD+1; } //--------------------------------------------------------------------------- void CSelect::Remove( int FD, bool Read, bool Write ) { TSelectHandle ** Handle = NULL; // Check if Handle already exists Handle = &FirstHandle; while (*Handle && ((*Handle)->FD != FD)) { Handle = &((*Handle)->Next); } // Check if found if (!*Handle) return; // Remove from set for select read check if (Read && (*Handle)->Read) { (*Handle)->Read = false; FD_CLR( FD, &ReadTestFDS); // Log event LogMessage( dlHigh, "Select: FD [%d] - Remove Read", FD ); } // Remove from set for select write check if (Write && (*Handle)->Write) { (*Handle)->Write = false; FD_CLR( FD, &WriteTestFDS); // Log event LogMessage( dlHigh, "Select: FD [%d] - Remove Write", FD ); } // Handle will be removed in Test() if both Read & Write flags are false } //--------------------------------------------------------------------------- bool CSelect::Test() { TSelectHandle * Handle = NULL; TSelectHandle ** HandlePtr = NULL; int TestFD = 0; int Events = 0; // Set Test sets ReadFDS = ReadTestFDS; WriteFDS = WriteTestFDS; // Perform select Events = select( MaxFD, &ReadFDS, &WriteFDS, (fd_set*)NULL, &Timeout ); if (Events < 0) { LogMessage( dlHigh, "Select: Select operation failed" ); return false; } // Check all descriptors for events Handle = FirstHandle; while (Handle) { // Check if to remove from list if (!Handle->Read && !Handle->Write) { // Update Maximum Test FD if (Handle->FD == MaxFD-1) { for (TestFD = MaxFD-1; TestFD >= 0; TestFD--) { if (FD_ISSET( TestFD, &ReadTestFDS ) || FD_ISSET( TestFD, &WriteTestFDS )) { break; } } MaxFD = TestFD+1; } // Remove from list HandlePtr = &FirstHandle; while (*HandlePtr && (*HandlePtr != Handle)) HandlePtr = &((*HandlePtr)->Next); *HandlePtr = (*HandlePtr)->Next; // Destroy and go to next free( Handle ); Handle = *HandlePtr; continue; } else { // Check read Event if (FD_ISSET( Handle->FD, &ReadFDS ) && Handle->Function) { Handle->Function->Read( Handle->FD ); } // Check Write Event if (FD_ISSET( Handle->FD, &WriteFDS ) && Handle->Function) { Handle->Function->Write( Handle->FD ); } } // Next Handle = Handle->Next; } // return success return (bool)Events; } //---------------------------------------------------------------------------