views:

36

answers:

1

I am currently using select() to act as a timer. I have network receive operations which occur within a loop, and every few seconds a processing operation needs to occur.

As a result, the select() statement's timeout constantly changes -- decreasing to zero over time and then restarting at 3.

rv = select(selectmonitor+1, &readnet, NULL, NULL, &helper.timeout());

As things come in on the network, the statement is repeated and the value passed to it by helper.timeout() decreases. Eventually, the value will either be equal to zero or the system will timeout, which will result in the processing function executing. However, I've noticed that this is quite resource intensive -- the value for helper.timeout() must be constantly calculated. When I am trying to receive a few thousand packets a second, the time it takes for this operation to be done results in packet loss.

My new idea is using SIGALRM to resolve this. This would allow me to set a timer once and then react when it is set off. However, I'm confused as to how it will affect my program. When SIGALRM 'goes off', it will run a function which I specify. However, how will it interrupt my existing code? And once the function is done, how will my existing code (within the while statement) resume?

Also, it would appear its impossible to set the SIGALRM signal to call a function within a class? Is this correct? I imagine I can call a function, which can in turn call a function within a class..

Thanks for any assistance ahead of time.

+1  A: 

Use your SIGALRM handler to set a flag variable.

Use sigaction instead of signal to set your signal handler. Do not set the SA_RESTART flag. With SA_RESTART not set your select statement will be interrupted by the signal. Your select will return -1 and errno will be EINTR.

Since the signal might happen while your other code is executing you will want to check the flag variable too, probably right before going into the select.

I was just reminded that this pattern can result in missing the signal, if it happens just after checking the flag and just before entering the select.

To avoid that, you need to use sigprocmask to block the SIGALRM signal before entering the while loop. Then you use pselect instead of select. By giving pselect a signal mask with SIGALRM unmasked, the signal will end up always interrupting during the select instead of happening at any other time.

Zan Lynx
To add to that, using signals(which alarm() does) could cause a lot of other system calls to "fail" and set errno to EINTR too if the alarm goes off while the system call is performed - which should be taken care of
nos
@Zan -- Your answer is slightly confusing: " Do not use the SA_RESTART flag, and your select statement will be interrupted by the signal". Are you saying if I don't use the SA_RESTART flag, my select statement will be interrupted? Or are those two separate things.
BSchlinker
@nos -- Are you suggesting that the previous method of using select() to schedule the timeouts is better?
BSchlinker
@BSchlinker: If you specify SA_RESTART then most system calls will never return -1 and EINTR because they will be automatically restarted.
Zan Lynx
@BSchlinker , Not really - but I am saying signal handling is usally troublesome - if you need something "better" I'd suggest taking a look at the manpage for `timerfd_create` if you can do with something linux specific
nos
+1 for recommending `pselect`
bstpierre