Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

signal handling in Unix Forths

3 views
Skip to first unread message

Krishna Myneni

unread,
Aug 31, 2004, 12:09:49 AM8/31/04
to

I am designing an interface in kForth for signal
handling --- I have a pressing need to run a
task periodically (about every 50 ms) in the
background and I can use the SIGALRM signal to
accomplish this. Thus far, I'm considering an
interface of the form

FORTH-SIGNAL ( n xt -- xtold )

This would install the Forth word specified by xt
to be the handler for signal number n, and return
the old handler xt. The handler itself would be
any word of the form

HANDLER-NAME ( n -- )

where n is the signal number passed to the word
by the actual underlying handler (coded in C).
A single Forth handler could process multiple signal
numbers if desired, using a CASE structure for
example. Or different Forth handlers can be used for
different numbers. The word FORTH-SIGNAL would
install the xt for the specified signal number
by placing the xt in a table to be used by the
actual signal handler function which calls the
appropriate word based on the table. FORTH-SIGNAL
call the system function signal() to install the
actual C handler.

This is my first cut at a solution for non-native
Forths under UNIX. I notice there is a signals-ext.c
file for pfe, but there doesn't appear to be a Forth
interface to get at the handler (maybe I missed it),
and I haven't studied the gforth code yet to see if
a Forth interface to signals is implemented. I'm
looking for feedback on the signals interface design
in Forth from others with experience in this.

It occurs to me that CATCH and THROW can be implemented
in source easily using the signals interface and assigning
a handler to one of the user defined signals. Of course
this means also implementing a word which can raise
a signal (RAISE, copying the system C interface
function raise()).

Krishna Myneni

Krishna Myneni

unread,
Aug 31, 2004, 11:15:03 AM8/31/04
to
Krishna Myneni wrote:
>
> I am designing an interface in kForth for signal
> handling --- I have a pressing need to run a
> task periodically (about every 50 ms) in the
> background and I can use the SIGALRM signal to
> accomplish this. ...

Following is sample C code which illustrates the
use of the SIGALRM signal to execute code periodically
while the main prog continues its execution:

/*
sigtest.c

Test installation and use of a signal handler -- KM 8/29/04

Build: gcc -o sigtest sigtest.c
*/

#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>

static void handler (int);

volatile int counter = 0;

int main()
{
struct itimerval v, vold;
int e;
signal (SIGALRM, handler); // install new handler for SIGALRM

v.it_interval.tv_sec = 1; // 1 second timer
v.it_interval.tv_usec = 0;
v.it_value.tv_sec = 1; // initial timer value; timer counts down
v.it_value.tv_usec = 0;

e = setitimer (ITIMER_REAL, &v, &vold);
// printf ("\nsetitimer returned %d", e);

// Wait for the timer to trigger the signal handler a few times

while (counter < 5) ;

return 0;
}

// The signal handler

static void handler (int signum)
{
printf ("\nReceived signal %d", signum);
++counter;
}

Anton Ertl

unread,
Aug 31, 2004, 10:46:47 AM8/31/04
to
Krishna Myneni <krishn...@compuserve.com> writes:
>
>I am designing an interface in kForth for signal
>handling --- I have a pressing need to run a
>task periodically (about every 50 ms) in the
>background and I can use the SIGALRM signal to
>accomplish this.

I wonder if it would not be better to just use another (Unix) thread
or (Forth) task to do such things. The result would be more general
than trying to use an interrupt handler model with signals.

Note that the Unix standards severely restrict what can be done in a
signal handler, so it's easy to become non-standard when using signal
handlers, and you typically only notice that when it breaks on some
system.

>and I haven't studied the gforth code yet to see if
>a Forth interface to signals is implemented.

Gforth just translates Unix/C signals into Forth exceptions (i.e., it
THROWS), with a fixed signal-exception mapping. No interface for
other usage of signals is provided.

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
EuroForth 2004: http://www.complang.tuwien.ac.at/anton/euroforth2004/
Deadline (refereed): August 28, 2004; Conference: November 19-21, 2004

Russell McManus

unread,
Aug 31, 2004, 11:08:06 AM8/31/04
to
an...@mips.complang.tuwien.ac.at (Anton Ertl) writes:

> I wonder if it would not be better to just use another (Unix) thread
> or (Forth) task to do such things. The result would be more general
> than trying to use an interrupt handler model with signals.
>
> Note that the Unix standards severely restrict what can be done in a
> signal handler, so it's easy to become non-standard when using signal
> handlers, and you typically only notice that when it breaks on some
> system.

To extend this point, the standard trick in Unix when receiving a
signal is to have a special pipe available into which one writes the
signal number. Then you can include the read half of the pipe in a
select or poll loop, and process the signal in a normal user context.

Of course, if your application already has a poll or select loop, then
you don't need SIGALRM to wake up periodically; you can just use the
timeout feature of these system calls.

-russ

Bernd Paysan

unread,
Aug 31, 2004, 11:17:54 AM8/31/04
to
Russell McManus wrote:
> Of course, if your application already has a poll or select loop, then
> you don't need SIGALRM to wake up periodically; you can just use the
> timeout feature of these system calls.

One thing I hate about Unix is that these guys never get it right what a
timeout really means. A timeout is a deadline, i.e. an absolute time
reference. What you give to usleep or select is a delta time. If it returns
for other reasons before the time has expired, usleep and select update the
delta time argument, so when you call it again (after an infinitesimal
timestep), you are supposed to be woken up at the original timeout.
However, there is no such thing as an infinitesimal timestep, so in
reality, resuming an interrupted timeout means waking up later.

What I do now is to use a delta that will sleep at least one OS tick less
than the desired timeout, and use gettimeofday() to busy-wait for the point
in time when I really want to wake up. After resuming, I use gettimeofday
to recalculate the delta I still have to sleep. This sort of works, but
here, we have a classic example of a broken interface.

--
Bernd Paysan
"If you want it done right, you have to do it yourself"
http://www.jwdt.com/~paysan/

Stefan Schmiedl

unread,
Aug 31, 2004, 1:17:44 PM8/31/04
to
On Mon, 30 Aug 2004 21:09:49 -0700,
Krishna Myneni <krishn...@compuserve.com> wrote:
>
> FORTH-SIGNAL ( n xt -- xtold )
>
> This would install the Forth word specified by xt
> to be the handler for signal number n, and return
> the old handler xt.

What's the rationale behind the stack sequence for calling this word?
I'd prefer ( xt n -- xt_old ), because it matches "use xt for
signal n" more closely.

And it would make it easier to define

: >SIGALRM ( xt -- old ) SIG_ALARM forth-signal ;
: >SIGKILL ( xt -- old ) ....

Just my 2 cents,
s.

Russell McManus

unread,
Aug 31, 2004, 3:55:25 PM8/31/04
to

Bernd Paysan <bernd....@gmx.de> writes:

> One thing I hate about Unix is that these guys never get it right
> what a timeout really means. A timeout is a deadline, i.e. an
> absolute time reference. What you give to usleep or select is a
> delta time. If it returns for other reasons before the time has
> expired, usleep and select update the delta time argument, so when
> you call it again (after an infinitesimal timestep), you are
> supposed to be woken up at the original timeout. However, there is
> no such thing as an infinitesimal timestep, so in reality, resuming
> an interrupted timeout means waking up later.
>
> What I do now is to use a delta that will sleep at least one OS tick
> less than the desired timeout, and use gettimeofday() to busy-wait
> for the point in time when I really want to wake up. After resuming,
> I use gettimeofday to recalculate the delta I still have to
> sleep. This sort of works, but here, we have a classic example of a
> broken interface.

I suppose I agree with you. However most of my programs do not worry
about timing on such a fine-grained level, so I can live with the
klunky interface. I just assume that things will be klunky when I'm
programming in a Unix environment.

It is mind boggling how difficult it is to multiplex the various sorts
of IPC that are available on Unix, signals being just one instance.
This to me is an even bigger wart. FreeBSD's kqueue is a definite
step in the right direction.

-russ

Mark Manning

unread,
Aug 31, 2004, 5:46:05 PM8/31/04
to
an...@mips.complang.tuwien.ac.at (Anton Ertl) wrote in message news:<2004Aug3...@mips.complang.tuwien.ac.at>...

> Krishna Myneni <krishn...@compuserve.com> writes:
> >
> >I am designing an interface in kForth for signal
> >handling --- I have a pressing need to run a
> >task periodically (about every 50 ms) in the
> >background and I can use the SIGALRM signal to
> >accomplish this.
>
> I wonder if it would not be better to just use another (Unix) thread
> or (Forth) task to do such things. The result would be more general
> than trying to use an interrupt handler model with signals.
>
> Note that the Unix standards severely restrict what can be done in a
> signal handler, so it's easy to become non-standard when using signal
> handlers, and you typically only notice that when it breaks on some
> system.
>
> >and I haven't studied the gforth code yet to see if
> >a Forth interface to signals is implemented.
>
> Gforth just translates Unix/C signals into Forth exceptions (i.e., it
> THROWS), with a fixed signal-exception mapping. No interface for
> other usage of signals is provided.
>
> - anton

throw is not a suitable substitute for a signaling system, a throw is
an abort and a signal does not need to be. you can for instance be
given a signal when your terminal size changes in X - is "user resized
me" an abort condition?

Signals are messages which may or may not be an abort; throws are
aborts PERIOD.

Krishna Myneni

unread,
Aug 31, 2004, 9:35:33 PM8/31/04
to

There's no particular rationale other than I was influenced
by the order of the args to the C system function signal().
You make a good argument for reversing the stack order which
I had proposed.

I plan to implement this very soon in kForth. The development
version will be announced when this feature is added and
tested.

Cheers,
Krishna

Krishna Myneni

unread,
Aug 31, 2004, 9:46:28 PM8/31/04
to
Anton Ertl wrote:
> Krishna Myneni <krishn...@compuserve.com> writes:
>
>>I am designing an interface in kForth for signal
>>handling --- I have a pressing need to run a
>>task periodically (about every 50 ms) in the
>>background and I can use the SIGALRM signal to
>>accomplish this.
>
>
> I wonder if it would not be better to just use another (Unix) thread
> or (Forth) task to do such things. The result would be more general
> than trying to use an interrupt handler model with signals.
>

I wasn't specific enough about the requirements. The "background" task
must be executed at a precise interval. So, for example, we may want
to run it every 50 ms, plus or minus 1 ms tolerance.

Use of a concurrent task or thread implies that the thread/task will
be polling for the correct time to act. Since we want periodic
execution with precision timing (the period should not vary by more
than 1 ms), polling is not adequate because task switching depends on
system load for a non real-time OS. I am presuming that signal handling
under UNIX (Linux in particular) behaves just like interrupt handling
and that the timing uncertainity for SIGALRM is therefore
negligible. To illustrate the problem with polling, try running two
instances of the code below, simultaneously. When one instance is run
with not much system load, the results are adequate (at least on my
machine). However, when two instances are run concurrently, the polling
method falls apart.


\ poll-test.4th
\
\ Demonstrate timing uncertainty with polling. Run "test"
\ simultaneously under two separate Forth tasks
\
\ KM, 08-31-04
\


10 constant INTERVAL \ 10 ms interval
fvariable mean
fvariable sdev

1024 constant SIZE
create time-intervals SIZE cells allot

: test
\ Repeatedly wait for interval to elapse and record
\ actual elapsed time
SIZE 0 DO
ms@
BEGIN
ms@ over -
INTERVAL >=
UNTIL
ms@ swap -
time-intervals i cells + !
LOOP

\ Show statistics on intervals

0
SIZE 0 DO time-intervals i cells + @ + LOOP
s>f SIZE s>f f/ fdup mean f!
cr ." Mean interval = " f. ." ms"

0e
SIZE 0 DO time-intervals i cells + @ s>f mean f@ f-
fdup f* f+ LOOP
SIZE 1- s>f f/ fsqrt fdup sdev f!
cr ." Standard deviation = " f. ." ms"
;

> Note that the Unix standards severely restrict what can be done in a
> signal handler, so it's easy to become non-standard when using signal
> handlers, and you typically only notice that when it breaks on some
> system.
>
>

Yes, I think that's the price to be paid in using a PC for precision
timing tasks.

Krishna

Krishna Myneni

unread,
Aug 31, 2004, 9:50:43 PM8/31/04
to

I don't know I would call this a broken interface --- it's just not
designed for precision timing tasks. As I noted in my reply to Anton,
polling is not a very predictable way to check for elapsed time. One
really needs to use an interrupt-driven method for tasks requiring
millisecond or better timing accuracy.

Krishna

Krishna Myneni

unread,
Aug 31, 2004, 11:40:31 PM8/31/04
to
Krishna Myneni wrote:
> ...I am presuming that signal handling
> under UNIX (Linux in particular) behaves just like interrupt handling
> and that the timing uncertainity for SIGALRM is therefore
> negligible. To illustrate the problem with polling, try running two
> instances of the code below, simultaneously. When one instance is run
> with not much system load, the results are adequate (at least on my
> machine). However, when two instances are run concurrently, the polling
> method falls apart.
>
> ...

Aaagh! It turns out my assumption that signals had the same latency
as interrupts under Linux turns out NOT to be true. See the code below.
Running two instances of this code simultaneously shows that the
signal handler latency is as dependent on system load as the polling
method. Therefore, I have to figure out a kForth interface for
installing a replacement timer interrupt handler, rather than just
a signal handler. This should get interesting!

Krishna

--
/*
sigtime.c

Determine timing accuracy of SIGALRM signal handler -- KM 8/31/04

Build: gcc -o sigtime sigtime.c -lm
*/

#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>

#include <math.h>

static void handler (int);

volatile int counter = 0;

struct timeval current_time;
struct timeval last_time;
#define SIZE 1024
int time_intervals[SIZE];

int main()
{
struct itimerval v, vold;

int e, i, sum;
double fsum, mean, dif, sdev;


signal (SIGALRM, handler); // install new handler for SIGALRM

v.it_interval.tv_sec = 0;
v.it_interval.tv_usec = 10000; // 10 ms timer
v.it_value.tv_sec = 0; // initial timer value; timer counts down
v.it_value.tv_usec = 10000;

e = setitimer (ITIMER_REAL, &v, &vold);
// printf ("\nsetitimer returned %d", e);

gettimeofday(&last_time, NULL);

// Wait for timing measurements to be completed

while (counter < SIZE) ;

// Print statistics of measured time intervals

sum = 0;
for (i = 0; i < SIZE; i++) sum += time_intervals[i];

mean = (double) sum/SIZE;
printf ("\nMean interval = %lf ms", mean);

fsum = 0.;
for (i = 0; i < SIZE; i++)
{
dif = mean - time_intervals[i];
fsum += dif*dif;
}
sdev = sqrt(fsum/(SIZE - 1));
printf ("\nStandard deviation = %lf ms", sdev);

return 0;
}

// The signal handler

static void handler (int signum)
{

int interval;
gettimeofday (&current_time, NULL);
interval = (1000*current_time.tv_sec + current_time.tv_usec/1000) -
(1000*last_time.tv_sec + last_time.tv_usec/1000);
last_time = current_time;
time_intervals[counter] = interval;
++counter;
}

Thomas Pornin

unread,
Sep 1, 2004, 3:33:14 AM9/1/04
to
According to Krishna Myneni <krishn...@compuserve.com>:

> I am presuming that signal handling under UNIX (Linux in particular)
> behaves just like interrupt handling

Not really. In usual UNIX systems, including Linux, signal delivery just
sets a flag in the structure corresponding to the signalled processed,
marking it as "runnable". When the scheduler has time, it will run the
process, by entering the signal handler. Note that several instances
of the same signal happening in short sequence will "merge".

If you want real-time features, I suggest you use a real-time OS. QNX,
for instance. There used to be patches for a "real-time Linux" ; at that
time, a real-time task was actually an interrupt-driven piece of code
living in kernel space. Maybe such patches still exist. Try to look for
"rtlinux".

Short of specific real-time feature, you will get no more precision
than the system tick count, and even if you get to that point you can
consider yourself happy. Recent Linux kernels (2.6+) have increased the
default tick frequency to 1000 Hz because the previous default frequency
(100 Hz) proved insufficient for optimal video rendering (average Linux
users have become picky about DVD playing and things like that).


> Yes, I think that's the price to be paid in using a PC for precision
> timing tasks.

It may be noted that the same Linux, on Alpha platform, always had a
default tick frequency of 1024 Hz. The 100 Hz frequency was motivated by
the fact that on low-end 16 MHz 80386 processors, handling 1000 timer
interrupts per second consumes a non-negligeable proportion of available
cpu power.


--Thomas Pornin

Anton Ertl

unread,
Sep 1, 2004, 4:07:08 AM9/1/04
to
i4...@mailcity.com (Mark Manning) writes:
>an...@mips.complang.tuwien.ac.at (Anton Ertl) wrote in message news:<2004Aug3...@mips.complang.tuwien.ac.at>...
>> Gforth just translates Unix/C signals into Forth exceptions (i.e., it
>> THROWS), with a fixed signal-exception mapping. No interface for
>> other usage of signals is provided.
>>
>> - anton
>
>throw is not a suitable substitute for a signaling system, a throw is
>an abort and a signal does not need to be. you can for instance be
>given a signal when your terminal size changes in X - is "user resized
>me" an abort condition?

Ok, Gforth does not translate all signals to THROWs, only some
(typically those where the default action terminates the process). In
particular, SIGWINCH just changes the result that FORM gives (without
notifying the Forth program explicitly; an EKEY event might be
appropriate). A number of other signals are ignored.

>Signals are messages which may or may not be an abort; throws are
>aborts PERIOD.

No. THROWs can be caught, and the program can continue to run.
THROWs do throw away some context of the current execution, though.

Anyway, the way Gforth deals with signals has been satisfactory until
now, and I don't see any real demand for anything more sophisticated.

Anton Ertl

unread,
Sep 1, 2004, 4:25:21 AM9/1/04
to
Krishna Myneni <krishn...@compuserve.com> writes:
>I wasn't specific enough about the requirements. The "background" task
>must be executed at a precise interval. So, for example, we may want
>to run it every 50 ms, plus or minus 1 ms tolerance.

That's probably not possible in a fully portable Unix program. You
may want to look at how the sound programming people solve this
problem (they have similar requirements); AFAIK even with their
programming tricks, not all Linux kernels provide low enough latency
(but the kernel developers are working on it).

Krishna Myneni

unread,
Sep 6, 2004, 10:12:08 AM9/6/04
to


After reading a bit about how the Linux kernel handles the hardware
timer interrupts (cf Understanding the Linux Kernel, by Bovet and
Cesati), and poking around in the 2.4.x kernel source code, I found
the timer interrupt handler. This is the routine which is executed
when the IRQ0 interrupt, generated by the 8259 timer chip in the PC,
is asserted. As you mentioned above, the 2.4.x kernels program the
8259 to generate the IRQ0 signal every 10 ms. This is the precision
hardware clock to which I would like to tie the execution of my Forth
handler. The RTLinux patches probably provide an elegant and
well-designed solution to this problem and I intend to look at them
in the future. Since the timer interrupt handler is such a system
sensitive piece of code, even writing a device-driver interface does
not appear to be feasable. A relatively simple solution may be to
patch the Linux kernel in the following manner:

1) The 8259 is programmed by the kernel init_IRQ() function for
1 ms ticks (i.e. IRQ0 interrupt is asserted at 1 ms intervals).
Of course this should not be necessary in the 2.6.x kernels.

2) The kernel provides a special timer, usable at any time by only
one process. The setitimer() system function is modified to have
another option for its first argument, ITIMER_SPECIAL, which
may be used to request the special timer. The setitimer() function
will not succeed if another process has already been granted
the special timer.

3) The timer interrupt handler is modified to execute the signal handler
for the special timer. This would be done after the other functions
of the interrupt handler are completed.

In this way, the timer signal handling is not relegated to the
so-called "bottom-half" kernel functions which are only executed
as time permits. Since this approach adds only one extra function
to the timer interrupt handler, it should not bring the system to a
screeching halt, provided that the user's signal handler is
well-written and executes in a fraction of a millisecond.
This minimal solution and seems doable, even to someone who has
no previous experience in modifying the Linux kernel code.
And it fits with the "it's my computer and I should be able to do
any damn thing I want with it" philosophy.

Krishna

Krishna Myneni

unread,
Sep 12, 2004, 7:59:48 AM9/12/04
to
Krishna Myneni wrote:
> ...

> I plan to implement this very soon in kForth. The development
> version will be announced when this feature is added and
> tested.
> ...

The latest kForth for Linux development snapshot, v1.2.10,
provides a basic signals interface:

FORTH-SIGNAL ( xt n -- xtold | install word as handler for sig n)
RAISE ( n -- ior | assert signal n )
SET-ITIMER ( type aval aoldval -- error | set up timer signals )
GET-ITIMER ( type aval -- error | get timer countdown count )

The development snapshot may be obtained from:

ftp://ccreweb.org/software/kforth/linux/develop/2004-09-10/

An example file, called signals-ex.4th, illustrates how to setup
Forth words as handlers, and to set up the timer signals, e.g.

\ ------------------

: WINDOW-HANDLER ( n -- )
DROP ." Window size changed!" CR
;

: TIMER-HANDLER ( n -- )
DROP CR TIME&DATE 2DROP DROP
. BL EMIT . BL EMIT . ;

CR .( Installing new handlers for SIGWINCH and SIGALRM)

' WINDOW-HANDLER SIGWINCH forth-signal drop
' TIMER-HANDLER SIGALRM forth-signal drop

CR .( Try resizing the console --- Use ESC to halt)

: TEST ( -- )
1000 1000 SET-TIMER \ Send SIGALRM to kForth every 1000 ms
BEGIN
KEY 27 =
UNTIL

SIG_IGN SIGALRM forth-signal DROP \ Stop sending SIGALRM

CR ." Exiting TEST -- handler for SIGWINCH is still active" CR
;

TEST

\ ------------

The word SET-TIMER, defined in signal.4th, is a simplified
interface to the SET-ITIMER function.

Although the signals interface doesn't solve my original
problem of running a handler at precise time intervals,
it does provide a solution for a number of other tasks.


Krishna Myneni

P.S. Thanks to Roelf Toxopeus for sending me similar
Forth source code he developed for MacOSX to give me
a go-by. I was lazy and used the signal() function
rather than sigaction() to implement FORTH-SIGNAL.
sigaction() is apparently POSIX correct.

0 new messages