Re: A better interface, perhaps: a timed signal flag

From: linux
Date: Sat Jul 29 2006 - 03:50:57 EST


> If we had such an interface, then the application would look like
> this:
>
> volatile int flag = 0;
>
> register_timout(&time_val, &flag);
> while (work to do) {
> do_a_bit_of_work();
> if (flag)
> break;
> }
>
> Finally, a note about tickless designs. Very often such applications
> don't need a constantly ticking design. For example, the X server
> only needs to have the memory location incremented while it is
> processing events; if the laptop is idle, there's no reason to have
> the RTC generating interrupts and incrementing memory locations.
> Similarly, the Metronome garbage collector would only need to poll to
> see if the timeout has expired while the garbage collector is running,
> which is _not_ all of the time.
>
> Yes, you could use ioctl's to start and stop the RTC interrupt
> handler, but that's just ugly, and points out that maybe the interface
> should not be one of programming the RTC interrupt frequency directly,
> but rather one of "increment this flag after X units of
> (CPU/wallclock) time, and I don't care how it is implemented at the
> hardware level."

Actually, unless you want the kernel to have to poll the timeout_flag
periodically, it's more like:

volatile bool timeout_flag = false, armed_flag = false;

register_timout(&time_val, &flag);
while (work to do) {
if (!armed_flag) {
rearm_timeout();
armed_flag = true;
}
do_a_bit_of_work();
if (timeout_flag) {
armed_flag = false;
timeout_flag = false;
break;
}
}

Personally, I use setitimer() for this. You can maintain the flags in
software, and be slightly lazy about disarming it. If you get a signal
while you shouldn't be armed, *then* disarm the timer in the kernel.
Likewise, when rearming, set the user-disarmed flag and chec if kernel-level
rearming is required.

volatile bool timeout_flag = false, armed_flag = false, sys_armed_flag = false;

void
sigalrm(int sig)
{
(void)sig;
if (!armed_flag) {
static const struct itimerval it_zero = {{0,0},{0,0}};
if (sys_armed_flag)
warn_unexpected_sigalrm();
setitimer(ITIMER_REAL, &it_zero, 0);

} else if (timeout_flag)
warn_gc_is_slow();
else
timeout_flag = true;
}

void
arm_timer()
{
static const struct itimerval it_interval = { time_val, time_val };

armed_flag = true;
if (!sys_armed_flag) {
setitimer(ITIMER_REAL, &it_interval, 0);
sys_armed_flag = true;
}
}

main_loop()
{
signal(SIGALRM, sigalrm);

while (work to do) {
arm_timer();
do_a_bit_of_work();
if (timeout_flag) {
gc();
armed_flag = false;
timeout_flag = false;
}
}
}

... where only do_a_bit_of_work can prompt the need for more gc() calls.
This really tries to minimize the number of system calls.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/