Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > robust clean-up with SIGTERM (was Re: Again, how to write a cleanup function for a module in C )

Reply
Thread Tools

robust clean-up with SIGTERM (was Re: Again, how to write a cleanup function for a module in C )

 
 
Jane Austine
Guest
Posts: n/a
 
      08-13-2003
I'm writing a cgi script. The user can push the stop button at any
moment while the page is loading, and the apache will raise SIGTERM
and then SIGKILL in 3 secs. And the garbage is not collected
automatically when the signals are raised. It's an abnormal
termination.

I need to clean up a few things(like closing the db connection) before
the interpreter terminates.

How do I?

And according to Alex's suggestions... (see my questions below)

"Alex Martelli" <(E-Mail Removed)> wrote:

[snip]
>
> Are you implying that atexit doesn't? Run the following script:
>
> import atexit
> def f(*args):
> print 'f',args
> atexit.register(f,'goo','bar','baz')
> 1/0
>
> The output I see for it is as follows:
>
> [alex@lancelot src]$ python2.2 a.py
> Traceback (most recent call last):
> File "a.py", line 5, in ?
> 1/0
> ZeroDivisionError: integer division or modulo by zero
> f ('goo', 'bar', 'baz')
> [alex@lancelot src]$
>
>
> Signals are nastier -- by default they terminate the process
> WITHOUT cleanup. For example, if instead of the 1/0 you have
> at the end of the script:
>
> import os, signal
> os.kill(os.getpid(), signal.SIGIO)
>
> then f won't get run. Easy solution (won't work all of the
> time, but, pretty often): handle the signal to turn it into
> an exception! e.g. change the above two lines to:
>
> import os, signal
> def sig2exc(sig, frm): raise SystemError(sig)
> signal.signal(signal.SIGIO, sig2exc)
> os.kill(os.getpid(), signal.SIGIO)
>
> and f will again execute.
>
>

[snip]
>
> So, handle the signal, and make the program die "cleanly" with the
> exception of your choice -- THEN, cleanup code DOES run.
>

[snip]

This "signal to exception translation" looks nice. But Alex said
"won't work all of the time, but, pretty often". I am afraid to use
this method if its safety is not guaranteed. I wonder in what cases it
does not work, and how I can make it work always.
 
Reply With Quote
 
 
 
 
Changjune Kim
Guest
Posts: n/a
 
      08-15-2003
Though I'm not Alex Martelli, hope this helps: (look at the end of this
post)

"Jane Austine" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> I'm writing a cgi script. The user can push the stop button at any
> moment while the page is loading, and the apache will raise SIGTERM
> and then SIGKILL in 3 secs. And the garbage is not collected
> automatically when the signals are raised. It's an abnormal
> termination.
>
> I need to clean up a few things(like closing the db connection) before
> the interpreter terminates.
>
> How do I?
>
> And according to Alex's suggestions... (see my questions below)
>
> "Alex Martelli" <(E-Mail Removed)> wrote:
>
> [snip]
> >
> > Are you implying that atexit doesn't? Run the following script:
> >
> > import atexit
> > def f(*args):
> > print 'f',args
> > atexit.register(f,'goo','bar','baz')
> > 1/0
> >
> > The output I see for it is as follows:
> >
> > [alex@lancelot src]$ python2.2 a.py
> > Traceback (most recent call last):
> > File "a.py", line 5, in ?
> > 1/0
> > ZeroDivisionError: integer division or modulo by zero
> > f ('goo', 'bar', 'baz')
> > [alex@lancelot src]$
> >
> >
> > Signals are nastier -- by default they terminate the process
> > WITHOUT cleanup. For example, if instead of the 1/0 you have
> > at the end of the script:
> >
> > import os, signal
> > os.kill(os.getpid(), signal.SIGIO)
> >
> > then f won't get run. Easy solution (won't work all of the
> > time, but, pretty often): handle the signal to turn it into
> > an exception! e.g. change the above two lines to:
> >
> > import os, signal
> > def sig2exc(sig, frm): raise SystemError(sig)
> > signal.signal(signal.SIGIO, sig2exc)
> > os.kill(os.getpid(), signal.SIGIO)
> >
> > and f will again execute.
> >
> >

> [snip]
> >
> > So, handle the signal, and make the program die "cleanly" with the
> > exception of your choice -- THEN, cleanup code DOES run.
> >

> [snip]
>
> This "signal to exception translation" looks nice. But Alex said
> "won't work all of the time, but, pretty often". I am afraid to use
> this method if its safety is not guaranteed. I wonder in what cases it
> does not work, and how I can make it work always.


When signals are generated successively in a very short time, python
interpreter might screw up some of them. Basically, the interpreter checks
every checkinterval(default 100) if it has pending signal handler calls,
and process them. When a signal is generated, it registers the signal and
put its handler on the pending calls. As you can see there are potential
race conditions.

Check signalmodule.c and ceval.c.

I don't have a good idea on making signal handling always safe &
guaranteed. Maybe someone else can help?

 
Reply With Quote
 
 
 
 
Donn Cave
Guest
Posts: n/a
 
      08-16-2003
Quoth "Changjune Kim" <(E-Mail Removed)>:
[ ... re why signal handling may not be 100% reliable ]

| When signals are generated successively in a very short time, python
| interpreter might screw up some of them. Basically, the interpreter checks
| every checkinterval(default 100) if it has pending signal handler calls,
| and process them. When a signal is generated, it registers the signal and
| put its handler on the pending calls. As you can see there are potential
| race conditions.
|
| Check signalmodule.c and ceval.c.
|
| I don't have a good idea on making signal handling always safe &
| guaranteed. Maybe someone else can help?

Well, there are ways to defer signal delivery while you process
the signals that have already been delivered -

/* (untested) */
sigset_t mask, prev_mask;
sigfillset(&mask);
sigprocmask(SIG_SETMASK, &mask, &prev_mask);
/* All signals now blocked. */
... process state from signal deliveries
sigprocmask(SIG_SETMASK, &prev_mask, 0);

and you can set a signal handler up such that signals are blocked
while it executes -

sa.sa_handler = signal_handler;
sa.sa_flags = 0;
sigfillset(&sa.sa_mask);
sigaction(SIGTERM, &sa, 0);

This assumes signal handling per POSIX 1003.1, which may be part
of the reason if Python isn't trying to do it. Then there are
some naturally intrinsic problems with signal handling in Python
that make delivery unreliable in a different way - your signal
handler may be invoked much later than the signal is delivered.
(And of course if you're using threads, there are more problems.)
That's only relevant to the present question because, given the
unavoidable weaknesses in Python signal handling, it may not be
worth even a slight headache from platforms that don't support
POSIX signal handling or don't support it correctly.

Donn Cave, http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: How include a large array? Edward A. Falk C Programming 1 04-04-2013 08:07 PM
C API: module cleanup function Mr.M Python 6 01-30-2010 03:02 PM
Is the subprocess module robust enough in 2.4? skip@pobox.com Python 0 02-05-2009 04:20 PM
write a function such that when ever i call this function in some other function .it should give me tha data type and value of calling function parameter komal C++ 6 01-25-2005 11:13 AM
Using write function within email Module to write get_payload to afile. Chuck Amadi Python 0 06-22-2004 12:13 PM



Advertisments