Reputation: 2117
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?
Upvotes: 1
Views: 694
Reputation: 409136
For file descriptors, there is poll
(which you already use) or select
or epoll
or libevent. You can also check the SIGIO
signal, or the functions prefixed with aio_
.
For the time, you can check the alarm
system call.
For termination of child processes, check the SIGCHLD
signal.
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, poll
will return with an error and errno
set to EINTR
. 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 call poll
again, waiting for the next event to occur.
Unless you have other things to do, you can even call poll
with an infinite timeout. It will return on signals or file descriptor ready.
Upvotes: 1