Messages in this thread | | | Date | 29 Jul 2006 02:56:12 -0400 | From | linux@horizon ... | Subject | Re: A better interface, perhaps: a timed signal flag |
| |
> 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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |