Safely Suspend Process

Hello,

If this is not the proper place for this question then my apologies
and please /kindly/ redirect me to the right place.

I am looking for a method to suspend the process and insure I do
not miss a signal that is supposed to wake the process back up.
The short amount of time between checking if a signal has fired
and suspending a process can be enough to miss a signal and forever
put the process to sleep. Typically, the process would be woken
by an alarm from a timer, but there are other signals that may
also fire from time to time.

My solution is the function shown below. It masks all signals,
checks a flag to see if a signal has been handled, then uses a
single function to unmask signals and suspend the process.
The unmasking that follows the sigsuspend function is used to
insure that signals are unmasked even if sigsuspend fails.
The flag value is normally zero and will have one or more bits
set if a signal has been handled. These are set in my signal handler.

This should work fine, but only if sigsuspend is prevents a signal
from being handled between the time it modifies the signal mask until
it suspends the process. The manual does not clearly state this one
way or the other. I am wondering if anyone can say with certainty that
this solution will or will not work.

Thanks in advance.

// ==================================================
void suspend( u_int flag )
{
sigset_t setallsignals, normal;

sigprocmask( SIG_BLOCK, &setallsignals, &normal );

if( !flag )
sigsuspend( &normal );

sigprocmask( SIG_SETMASK, &normal, NULL );
}

Can’t way for sue your method will work but
won’t blocking on a Receive achieve what you want?

Getting a signal while RECEIVE blocked and you have a
signal handler in place will cause the following:
-process is unblocked
-signal handler handles the signal
-Receive (or Send) returns with an error

“Paul N. Leonard” wrote:

Hello,

If this is not the proper place for this question then my apologies
and please /kindly/ redirect me to the right place.

I am looking for a method to suspend the process and insure I do
not miss a signal that is supposed to wake the process back up.
The short amount of time between checking if a signal has fired
and suspending a process can be enough to miss a signal and forever
put the process to sleep. Typically, the process would be woken
by an alarm from a timer, but there are other signals that may
also fire from time to time.

My solution is the function shown below. It masks all signals,
checks a flag to see if a signal has been handled, then uses a
single function to unmask signals and suspend the process.
The unmasking that follows the sigsuspend function is used to
insure that signals are unmasked even if sigsuspend fails.
The flag value is normally zero and will have one or more bits
set if a signal has been handled. These are set in my signal handler.

This should work fine, but only if sigsuspend is prevents a signal
from being handled between the time it modifies the signal mask until
it suspends the process. The manual does not clearly state this one
way or the other. I am wondering if anyone can say with certainty that
this solution will or will not work.

Thanks in advance.

// ==================================================
void suspend( u_int flag )
{
sigset_t setallsignals, normal;

sigprocmask( SIG_BLOCK, &setallsignals, &normal );

if( !flag )
sigsuspend( &normal );

sigprocmask( SIG_SETMASK, &normal, NULL );
}

That could work, but it assumes that I and awaiting a message. I am
really just wating for a time period to expire. Even waiting for a
message, though, I could still miss the signal between the time I
check for the flag and the point that I call Receive(). If the signal
fires and is handled after I check the flag, then when I call Receive()
I will be there forever, won’t I?

Alex Cellarius wrote:

Can’t way for sue your method will work but
won’t blocking on a Receive achieve what you want?

Getting a signal while RECEIVE blocked and you have a
signal handler in place will cause the following:
-process is unblocked
-signal handler handles the signal
-Receive (or Send) returns with an error

“Paul N. Leonard” wrote:

That could work, but it assumes that I and awaiting a message. I am

In your case, the message will never come, the signal will
“break” you out of the suspended (RECEIVE block state).

really just wating for a time period to expire. Even waiting for a
message, though, I could still miss the signal between the time I
check for the flag and the point that I call Receive(). If the signal
fires and is handled after I check the flag, then when I call Receive()
I will be there forever, won’t I?

The signal handler is set up some time before you enter the Receive.
The OS shouldn’t miss the signal.
On 2nd thought, I think this type of window of failure will exist
no matter what method you choose…
Perhaps this why some people avoid using signals?

You could presumably also set up a timer to wake you out of a
potential deadlock situation, in which case the Receive could
serve another purpose. (Receiving the timer’s proxy).
(Fire a timer some time after the longest expected delay)

Yeah, that’s what I was afraid of. I was hoping to avoid the band-aid
approach of another signal to break me out of the situation. Oh well.
Thanks!

Alex Cellarius wrote:

“Paul N. Leonard” wrote:

That could work, but it assumes that I and awaiting a message. I am

In your case, the message will never come, the signal will
“break” you out of the suspended (RECEIVE block state).

really just wating for a time period to expire. Even waiting for a
message, though, I could still miss the signal between the time I
check for the flag and the point that I call Receive(). If the signal
fires and is handled after I check the flag, then when I call Receive()
I will be there forever, won’t I?

The signal handler is set up some time before you enter the Receive.
The OS shouldn’t miss the signal.
On 2nd thought, I think this type of window of failure will exist
no matter what method you choose…
Perhaps this why some people avoid using signals?

You could presumably also set up a timer to wake you out of a
potential deadlock situation, in which case the Receive could
serve another purpose. (Receiving the timer’s proxy).
(Fire a timer some time after the longest expected delay)

Previously, Alex Cellarius wrote in qdn.public.qnx4:

“Paul N. Leonard” wrote:

That could work, but it assumes that I and awaiting a message. I am

In your case, the message will never come, the signal will
“break” you out of the suspended (RECEIVE block state).

really just wating for a time period to expire. Even waiting for a
message, though, I could still miss the signal between the time I
check for the flag and the point that I call Receive(). If the signal
fires and is handled after I check the flag, then when I call Receive()
I will be there forever, won’t I?

The signal handler is set up some time before you enter the Receive.
The OS shouldn’t miss the signal.
On 2nd thought, I think this type of window of failure will exist
no matter what method you choose…

There’s methods that don’t have the race condition, one of which is to use
sigsetjmp() and siglongjmp(), Stevens beats this topic to death in
his “Advanced Programming in the Unix Envrionment”, in the chapter on
signals, as I recall.

Basically, set up a jmpbuf, and then set the alarm, and call the blocking
function. From inside the sig handler call longjmp. That way if you’re
caught in the window you’ll still longjmp out instead of blocking forever.

You could also call a different blocking function, say, select(). select()
has a timeout, as well as being unblocked by a signal. Also, though I
can’t produce this stuff off the top of my head, the posix signal calls
are supposed to have a sigwait, or some combination of calls, that if
used in the correct way can avoid race condtions, I think Stevens goes
over them as well.

… Hmm, no sigwait() in the QNX4 ref manual, guess they didn’t
implement it.

Perhaps this why some people avoid using signals?

You could presumably also set up a timer to wake you out of a
potential deadlock situation, in which case the Receive could
serve another purpose. (Receiving the timer’s proxy).
(Fire a timer some time after the longest expected delay)

I’ll second the vote for this.

The nice thing about it is, is even if the proxy is triggered before
you call Receive() it’s not lost, it’ll be waiting in the queue and
Receive()'ll just return right away. You can even combine them,
have the signal handler call Trigger(), then it’ll both wake up the
Receive() (if it can) or cause the proxy to wake Receive() up. Remember
to clear any pending alarm proxies even if you get EINTRed from
Receive().

Anyhow, there’s a million posibilities. Did I mention writing a single
byte to a pipe from the signal handler, and selecting on that pipe?
Or…

Have fun,
Sam


Sam Roberts (sam@cogent.ca), Cogent Real-Time Systems (www.cogent.ca)
“News is very popular among its readers.” - RFC 977 (NNTP)

“Paul N. Leonard” wrote:

Yeah, that’s what I was afraid of. I was hoping to avoid the band-aid
approach of another signal to break me out of the situation. Oh well.

Just to be clear, I didn’t mean a signal based timer, but a QNX
timer, which you can set up to to send a canned message (proxy)
to your Receive loop, which you can then handle as if a message.

I suppose I was avoiding a proxy because of some idea about overhead,
but considering the problems using signals, the proxy looks better
and better. I’ll probably use zero length message proxys attached to
a qnx timer as you suggest. Using message queues with proxy notification
for other traffic rounds it out nicely.

Thanks for the input!

Alex Cellarius wrote:

“Paul N. Leonard” wrote:

Yeah, that’s what I was afraid of. I was hoping to avoid the band-aid
approach of another signal to break me out of the situation. Oh well.

Just to be clear, I didn’t mean a signal based timer, but a QNX
timer, which you can set up to to send a canned message (proxy)
to your Receive loop, which you can then handle as if a message.

Proxies don’t have more overhead then signals, particularly 0-length
ones. They are heavily optimized because they are QNX’s way of
communicating between interrupt service routines and the main driver,
what would be lower and upper half ISRs in a Unixy kernel.

Sam

Previously, Paul N. Leonard wrote in qdn.public.qnx4:

I suppose I was avoiding a proxy because of some idea about overhead,
but considering the problems using signals, the proxy looks better
and better. I’ll probably use zero length message proxys attached to
a qnx timer as you suggest. Using message queues with proxy notification
for other traffic rounds it out nicely.

Thanks for the input!

Alex Cellarius wrote:

“Paul N. Leonard” wrote:

Yeah, that’s what I was afraid of. I was hoping to avoid the band-aid
approach of another signal to break me out of the situation. Oh well.

Just to be clear, I didn’t mean a signal based timer, but a QNX
timer, which you can set up to to send a canned message (proxy)
to your Receive loop, which you can then handle as if a message.


Sam Roberts (sam@cogent.ca), Cogent Real-Time Systems (www.cogent.ca)
“News is very popular among its readers.” - RFC 977 (NNTP)

Paul N. Leonard <paull@ifsreg.com> wrote:

I suppose I was avoiding a proxy because of some idea about overhead,
but considering the problems using signals, the proxy looks better
and better. I’ll probably use zero length message proxys attached to
a qnx timer as you suggest. Using message queues with proxy notification
for other traffic rounds it out nicely.

Proxy are probably lower in overhead than signals as far as delivery
goes – delivering a signal implies two extra context shifts (jump
to signal handler, return from signal handler).

For timer notification, you are almost always better using a proxy
and blocking on Receive() – you are guaranteed receipt of the proxy,
so there are no race conditions.

If you are getting a signal from some other source, and want to guarantee
that you will not end up missing it, something like the following will
work.


pid_t signal_proxy;

void signal_handler()
{
Trigger(signal_proxy );
}

void main()
{

signal( SIG_USR1, signal_handler );

sigprocmask( UNMASK… );
/* probably need better error checking */
while (pid != signal_proxy)
pid = Receive(signal_proxy, … );
sigprocmask( MASK… );


}

-David