signals and wait for event.

signals and wait for event.

Post by Sean Burk » Sun, 22 Jun 2003 07:09:08












> >> > The usual solution involves having the signal handler notify the
> main
> >> > thread that an event needs handling. The main thread then handles
> the
> >> > event synchronously relative to its other work. One of the ways to
> do
> >> > this is a simple atomic counter shared by the signal handler and
> main
> >> > line loop.  Alternatively, use a pipe or socket that the signal
> >> > handler stuffs a byte into which will cause the main line loop to be
> >> > awakened from a select() or poll().

> >> ok, i just coded working version with the pipe method.
> >> after i stuff a byte in a pipe, how do i empty it? issue a read?
> >> also what happens if i do not read from it and keep writing to it from
> >> signal handler? a memory leak?

> > Then the pipe will fill. You should make the pipe
> > non-blocking, so that your signal-handler won't
> > block writing to the pipe.

> Yes, i figured that out.

> But now i have run in bigger problem, if you have followed the thread
> then you know that the program i write processes data sets and more can
> arrive at any time. As the data processing takes reasonable time after
> getting the first data set my program only executes that one (processes)
> and the notification pipe method wont work - only the code of data
> processing is executed and it's not waiting for select() to return, so as
> a new data set arrives, a write to pipe is issued (from signal handler),
> but as there is no select(), the program just continues processing the
> data set and does not add the next one to the queue.
> Processing can take hours, data sets are small (< 512 bytes), new ones
> can arrive each minute.

Pipes will usually buffer at least 4K, so you can fit at least
eight data sets into it. (The buffer size might be configurable
too.) If your code is single-threaded, your data-processing loop
must empty the pipe at regular intervals to avoid overflow.
I don't expect that a once-per-minute nonblocking read would be
impractical.

If your code is multithreaded, then you can have a thread whose
sole task is to read data from the pipe, and put it into a work
queue. That's assuming that you have to get the original
notification asynchronously via a signal in the first place.

-SEan

 
 
 

signals and wait for event.

Post by Valentin Nechaye » Sun, 22 Jun 2003 18:50:36



>> How is this notification pipe created?

pipe()

PK> [continuing myself]
PK> So, from what i have found out, i create usual pipe(2) and make a write to
PK> it in a signal handler, while there is a select(2) waiting for data to
PK> apperar on pipe (is this called 'to wait pipe to unblock'? if not, how is
PK> it called?). Am i right?

You are right.

-netch-

 
 
 

signals and wait for event.

Post by Valentin Nechaye » Sun, 22 Jun 2003 18:55:05


PK> ok, i just coded working version with the pipe method.
PK> after i stuff a byte in a pipe, how do i empty it? issue a read?

Yes, explicit read(), until pipe becomes empty, while signals are blocked.
To do this properly, both pipe ends should be set non-blocking: read end -
to fail with EAGAIN when pipe is empty, write end - to not block when
pipe buffer is full (this may happen with extremely huge signal rate).

PK> also what happens if i do not read from it and keep writing to it from
PK> signal handler? a memory leak?

No, your program will become simple CPU hog: it won't sleep on select(),
but continue immediately.

-netch-

 
 
 

signals and wait for event.

Post by Valentin Nechaye » Sun, 22 Jun 2003 19:02:31


PK> Yes, i figured that out.
PK> But now i have run in bigger problem, if you have followed the thread
PK> then you know that the program i write processes data sets and more can
PK> arrive at any time. As the data processing takes reasonable time after
PK> getting the first data set my program only executes that one (processes)
PK> and the notification pipe method wont work - only the code of data
PK> processing is executed and it's not waiting for select() to return, so as
PK> a new data set arrives, a write to pipe is issued (from signal handler),
PK> but as there is no select(), the program just continues processing the
PK> data set and does not add the next one to the queue.

You mixed some levels of logic. Earlier I thought your data processing is
organized as simple FIFO without any deposition of current processing:
when a data set begins to be processed, its processing continues until
full finish. Is it right? If it is, you have no reason to worry.
If dataset processing can be interrupted for processing of another dataset,
you should reorganize program logic, to some event-driven-automata structure
or to multithreaded program which process data sets simultaneously.

PK> Processing can take hours, data sets are small (< 512 bytes), new ones
PK> can arrive each minute.

You can organize input of data set in signal handler. As signal handler can
use only async-signal-safe functions, memory for data sets should be
preallocated and available for signal handler in special pool.

-netch-

 
 
 

signals and wait for event.

Post by Valentin Nechaye » Sun, 22 Jun 2003 21:57:44


PK> I meant blocking signals inside a signal handler just after it executes
PK> and unblock just before it ends it's execution, so if any other signals
PK> arrive whileexecuting a signal handler they'd block.

Yes, this is done by signal handling metaframe in kernel.

PK> Is this possible, if so, then malloc() is safe, isnt it, because signals
PK> are blocked and the signal handler code can never be interrupted?

No. Consider malloc() updates heap control structures. In this moment
it is interrupted and signal handler calls malloc also. Second updating
can see heap control structures inconsistent, or leave in state which first
updating will treat as inconsistent.

So, I say again - preallocate nesessary number of buffers, and call
maintenance routine periodically when processing dataset.

PK> I am doing it by pipe method, but what is unclear to me is what happens
PK> right after a signal handler is called, is everything (registers etc)
PK> pushed to the stack and after the signal handler executes, everything is
PK> popped from the stack and the code flow continues as nothing happened?

Yes. But memory can't be pushed. ;)

-netch-

 
 
 

signals and wait for event.

Post by Nils O. Sel?sda » Sun, 22 Jun 2003 06:39:30


Quote:> Hello,

>  i have this question:

>  My program processes large sets of data (it might process them for
> days), if a new data set arrives, a signal is sent to the program, a
> signal handler takes place and adds the new data set to the queue
> (dinamically allocated) and increases (int) in_queue variable. So, there
> can be more thousand data sets added for processing while processing the
> current (in_queue is used for checking if maximum data sets in queue are
> not exceeded).

>  As soon as a data set is processed, the program decreases in_queue
> variable and if there are more data sets in the queue processes them, but
> if not it should wait until a new data set arrives and start processing
> it.

>  How should i implement the wait for new data?

If you have access to the program that delivers the signal, it would probably
be most appropriate to modify it to open, say, a connection to a unix
domain socket, and send a notification through it. Then your program
act as a server, and can select() on the filedescriptor.

select will anyway return if a signal is delivered, and you could check
for a flag the signal handler sets. This will have a slight race condition,
thus pselect is needed. But, pselect is emulated on Linux and suffers from the
race condition anyway. Read the manpage pselect.

If the only thing you need is to wait for a signal, there is sigwait/sigsuspend
and probably others. Use sigsuspend if you only need to wait for a signal.

Quote:

>  As i understand Linux does not support pselect() syscall (i havent ever
> used it on Linux, so does it support or not?).
> (Can i emulate pselect() with select() syscall?).
>  If it supported, I'd pselect() until desired signal event occurs and
> start processing the queue (am I right?).

>  Or maybe use a spinlock? while (!in_queue); But spinlocks are very cpu
> intensive, arent they?
>  (And as in_queue is increased by the signal handler, should it be
> defined volitale?)

volatile sig_atomic_t in_queue = 0;

Quote:

>  Or any other method?

--

System Developer, UtelSystems a/s
w w w . u t e l s y s t e m s . c o m