An app needs to be able to set callbacks on various events. The events can be any of:
-
A UTC time has been reached
-
Data has arrived at a file descriptor
-
A child process has completed.
I need to write a function that will dispatch the events. The app will run on an embedded platform and should take reasonable steps to minimise CPU utilisation.
One approach would be a busy loop:
#define MAX_EVENT 10
typedef enum tagEventType {EV_DATA, EV_CHILD, EV_TIME} tEventType;
typedef void(*tEventCallback)(int);
typedef struct tagEvent
{
int sequence;
tEventType type;
tEventCallback callback;
time_t time;
int fd;
pid_t pid;
} tEvent;
static tEvent eventsTable[MAX_EVENT];
static void processEvents(void)
{
int i;
for ( i=0; i<MAX_EVENT; ++i )
{
if ( eventsTable[i].sequence > 0 )
{
switch(eventsTable[i].type)
{
case EV_DATA:
if ( checkForDataUsingPoll( eventsTable[i].fd) )
{
eventsTable[i].callback(eventsTable[i].sequence);
}
break;
case EV_CHILD:
if ( kill(eventsTable[i].pid, 0) == -1 )
{
eventsTable[i].callback(eventsTable[i].sequence);
eventsTable[i].sequence = 0;
}
break;
case EV_TIME:
{
if ( time(NULL) > eventsTable[i].time )
{
eventsTable[i].callback(eventsTable[i].sequence);
eventsTable[i].sequence = 0;
}
}
break;
}
}
}
}
int main( int argc, char* argv[] )
{
signal(SIGCHLD, SIG_IGN);
while(1)
{
processEvents();
usleep(1000);
}
return 0;
}
checkForDataUsingPoll() uses poll() with a timeout of zero to check whether data has arrived at the file descriptor. I’ve omitted it for brevity.
Is there a way of doing this which avoids the busy loop? Some mixture of poll, signals, and alarm perhaps?
For file descriptors, there is
poll(which you already use) orselectorepollor libevent. You can also check theSIGIOsignal, or the functions prefixed withaio_.For the time, you can check the
alarmsystem call.For termination of child processes, check the
SIGCHLDsignal.Edit To answer the comment: For the signals, you don’t really have to do anything, the signal handlers you set will be called automatically by the system when they occur. If they happen set a flag and possible other variables to inform your program what happened.
When a signal is received,
pollwill return with an error anderrnoset toEINTR. If that is the case, check the flags set by the signal handlers to see what happened, and call whatever functions you need. If it was an alarm, then you have to restart the alarm for the next event. Then callpollagain, waiting for the next event to occur.Unless you have other things to do, you can even call
pollwith an infinite timeout. It will return on signals or file descriptor ready.