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

PTHREADS: Longjmp()'ing from cleanup handlers

0 views
Skip to first unread message

Davlet Panech

unread,
Feb 13, 2002, 11:40:47 AM2/13/02
to
Hi,

Is it legal to use longjmp from within a pthread cancellation cleanup
handler? I am trying to get the cancellation points to effectively
*return* to the caller function, for example:

void return_from_cleanup( void *p )
{
longjmp ( *( jmp_buf * )p, 1 );
}

void thread_func( void * )
{
jmp_buf buf;
/* ... */
if ( setjmp( buf ) == 0 ) {
pthread_cleanup_push( &return_from_cleanup, &buf );
pthread_cond_wait( /* ... */ );
pthread_cleanup_pop( 0 );
} else {
/* handle cancellation here */
}
/* ... */
}

It seems to work OK on my machine, but I was wondering if this is
portable.

Thank you,
D.P.

Casper H.S. Dik

unread,
Feb 13, 2002, 12:06:39 PM2/13/02
to
Davlet Panech <Davlet...@Tellabs.com> writes:

> if ( setjmp( buf ) == 0 ) {
> pthread_cleanup_push( &return_from_cleanup, &buf );
> pthread_cond_wait( /* ... */ );
> pthread_cleanup_pop( 0 );
> } else {
> /* handle cancellation here */
> }
> /* ... */
>}

>It seems to work OK on my machine, but I was wondering if this is
>portable.


It may work but it will never work reliably.

Avoid setjmp/longjmp at all cost.

Casper
--
Expressed in this posting are my opinions. They are in no way related
to opinions held by my employer, Sun Microsystems.
Statements on Sun products included here are not gospel and may
be fiction rather than truth.

Davlet Panech

unread,
Feb 13, 2002, 3:58:52 PM2/13/02
to
"Casper H.S. Dik" wrote:
>
> Davlet Panech <Davlet...@Tellabs.com> writes:
>
> > if ( setjmp( buf ) == 0 ) {
> > pthread_cleanup_push( &return_from_cleanup, &buf );
> > pthread_cond_wait( /* ... */ );
> > pthread_cleanup_pop( 0 );
> > } else {
> > /* handle cancellation here */
> > }
> > /* ... */
> >}
>
> >It seems to work OK on my machine, but I was wondering if this is
> >portable.
>
> It may work but it will never work reliably.

Why? Is there anything in POSIX or C standards that prevent this from
working? Do you know of any systems where it might fail? Believe me
I have good reasons to do this.

>
> Avoid setjmp/longjmp at all cost.

It's not like I have a lot of choice.

D.P.

Casper H.S. Dik

unread,
Feb 14, 2002, 4:02:42 AM2/14/02
to
Davlet Panech <Davlet...@Tellabs.com> writes:

Note: PLEASE configure your newdsreader not to send email
and post. I hate to reply twice.

>Why? Is there anything in POSIX or C standards that prevent this from
>working? Do you know of any systems where it might fail? Believe me
>I have good reasons to do this.

Yes. Longjump" invokes undefined behaviour.

>> Avoid setjmp/longjmp at all cost.

>It's not like I have a lot of choice.


Well, you're longjumping in a cancelled thread.

The thread is supposed to *die*. You keep it alive by
longjumping out of the cleanup code. This doesn't
strike you as risky?

Alexander Terekhov

unread,
Feb 14, 2002, 4:40:33 AM2/14/02
to
Davlet Panech <Davlet...@Tellabs.com> wrote in message news:<3C6AD38C...@Tellabs.com>...

> "Casper H.S. Dik" wrote:
> >
> > Davlet Panech <Davlet...@Tellabs.com> writes:
> >
> > > if ( setjmp( buf ) == 0 ) {
> > > pthread_cleanup_push( &return_from_cleanup, &buf );
> > > pthread_cond_wait( /* ... */ );
> > > pthread_cleanup_pop( 0 );
> > > } else {
> > > /* handle cancellation here */
> > > }
> > > /* ... */
> > >}
>
> > >It seems to work OK on my machine, but I was wondering if this is
> > >portable.
> >
> > It may work but it will never work reliably.
>
> Why? Is there anything in POSIX or C standards that prevent this from
> working?

http://www.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_09.html#tag_02_09_05_03

"A cancelation cleanup handler cannot exit via longjmp() or
siglongjmp()."

> Do you know of any systems where it might fail? Believe me
> I have good reasons to do this.
>
> >
> > Avoid setjmp/longjmp at all cost.
>
> It's not like I have a lot of choice.

What do you mean? Do you want to stop unwinding process or
do something like that? I guess you would need something
along the lines of standard pthread_cancel_e exception
and a mechanism to *re-enable*[1] cancelation once you
just eat cancel exception - stop cancel/unwinding process.

regards,
alexander.

[1] It is not clear to me whether pthread_setcancelstate()
is supposed to do it if invoked (with PTHREAD_CANCEL_ENABLE)
*during* unwinding; I mean implementations which already have
published _cancel_e (and _exit_e) exceptions, which would
allow to catch and just eat them -- do not re-throw. Also,
since cancelation could be "raised" from some async-cancel-
region, I guess, you would need to restore PTHREAD_CANCEL_DEFERRED
TYPE prior to setting the STATE, unless it is done for you
by the implementation on "raise" operation.

Hmm... Gurus, are there any chances that some day you will
finally produce some standard *C++*-Pthreads/POSIX bindings
that would define things like that?!

David Butenhof

unread,
Feb 14, 2002, 7:04:38 AM2/14/02
to
Davlet Panech wrote:

> Is it legal to use longjmp from within a pthread cancellation cleanup
> handler? I am trying to get the cancellation points to effectively
> *return* to the caller function, for example:

Sorry, but if you want to "finalize" (catch and continue) a cancellation,
you need a correct and rational implementation of POSIX threads that
implements cancellation as an EXCEPTION that can be caught. (E.g., with a
C++ 'catch(...)', though having a standard name for the exception would be
even better.)

The POSIX standard specifically prohibits longjmp() from a cleanup handler.
Like many other illegal/nonstandard/nonportable practices, you may well
find one or more implementations where it isn't immediately obvious that it
fails to work. That doesn't mean its a good idea.

Let's put it this way:

Many years ago, on an icy road at the end of a New England blizzard, I
momentarily lost control of my car. It went off the road into the median;
down a small hill and up the larger center hill, then back down... and came
to rest, completely undamaged (though with a somewhat shaken driver) at the
edge of the road. I drove off. Despite my total success in this little
experiment, (and the rather impressive set of tire tracks that remained
visible for weeks), I have never felt tempted to repeat it. I was and have
remained completely confident that my experience was NOT standard or
"portable"... ;-)

/------------------[ David.B...@compaq.com ]------------------\
| Compaq Computer Corporation POSIX Thread Architect |
| My book: http://www.awl.com/cseng/titles/0-201-63392-2/ |
\-----[ http://home.earthlink.net/~anneart/family/dave.html ]-----/

Davlet Panech

unread,
Feb 14, 2002, 9:45:10 AM2/14/02
to
"Casper H.S. Dik" wrote:
>
> Davlet Panech <Davlet...@Tellabs.com> writes:
>
> Note: PLEASE configure your newdsreader not to send email
> and post. I hate to reply twice.

Sorry about that.

>
> >Why? Is there anything in POSIX or C standards that prevent this from
> >working? Do you know of any systems where it might fail? Believe me
> >I have good reasons to do this.
>
> Yes. Longjump" invokes undefined behaviour.
>
> >> Avoid setjmp/longjmp at all cost.
>
> >It's not like I have a lot of choice.
>
> Well, you're longjumping in a cancelled thread.
>
> The thread is supposed to *die*. You keep it alive by
> longjumping out of the cleanup code. This doesn't
> strike you as risky?

All right, it does now. Perhaps I should explain what I am trying to do.
I am trying to implement thread cancellation in C++ such that a
cancellation
request results in a C++ exception in the thread being cancelled. I
can't throw
exceptions from cancellation handlers because such exceptions would have
to propagate through PTHREADs code, and there is no telling what might
happen
in that case.

I guess using PTHREAD cancellation for this is a bad idea after all.

I also considered using signals:
- Each thread has a (boolean) `cancelled' flag associated with it
- Each thread "agrees" to check this flag before making any blocking
system calls
- Cancelling a thread means setting the flag and sending a signal to
the thread
being cancelled
- Each thread has to watch for EINTR error code returned by the system
functions
to detect a cancellation request
- Threads should not alter the settings for the signal used to deliver
the cancellation
requests

Obviously this is more restrictive than the native PTHREAD cancellation;
there are also
race conditions that have to be dealt with, but that's the general idea.

Comments/suggestions?

D.P.

Davlet Panech

unread,
Feb 14, 2002, 9:49:57 AM2/14/02
to
Alexander Terekhov wrote:
>
> Davlet Panech <Davlet...@Tellabs.com> wrote in message news:<3C6AD38C...@Tellabs.com>...
> > "Casper H.S. Dik" wrote:
> > >
> > > Davlet Panech <Davlet...@Tellabs.com> writes:
> > >
> > > > if ( setjmp( buf ) == 0 ) {
> > > > pthread_cleanup_push( &return_from_cleanup, &buf );
> > > > pthread_cond_wait( /* ... */ );
> > > > pthread_cleanup_pop( 0 );
> > > > } else {
> > > > /* handle cancellation here */
> > > > }
> > > > /* ... */
> > > >}
> >
> > > >It seems to work OK on my machine, but I was wondering if this is
> > > >portable.
> > >
> > > It may work but it will never work reliably.
> >
> > Why? Is there anything in POSIX or C standards that prevent this from
> > working?
>
> http://www.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_09.html#tag_02_09_05_03
>
> "A cancelation cleanup handler cannot exit via longjmp() or
> siglongjmp()."

OK thanks for the link.

>
> > Do you know of any systems where it might fail? Believe me
> > I have good reasons to do this.
> >
> > >
> > > Avoid setjmp/longjmp at all cost.
> >
> > It's not like I have a lot of choice.
>
> What do you mean? Do you want to stop unwinding process or
> do something like that?

Yes.

> I guess you would need something
> along the lines of standard pthread_cancel_e exception

What is pthread_cancel_e? If there is such a thing I don't
have it on my machine.

> and a mechanism to *re-enable*[1] cancelation once you
> just eat cancel exception - stop cancel/unwinding process.

Yes, there is a number of issues involved, but first I need
a reliable way to throw an exception in response to a cancellation
request.


>
> regards,
> alexander.
>
> [1] It is not clear to me whether pthread_setcancelstate()
> is supposed to do it if invoked (with PTHREAD_CANCEL_ENABLE)
> *during* unwinding; I mean implementations which already have
> published _cancel_e (and _exit_e) exceptions, which would
> allow to catch and just eat them -- do not re-throw. Also,
> since cancelation could be "raised" from some async-cancel-
> region, I guess, you would need to restore PTHREAD_CANCEL_DEFERRED
> TYPE prior to setting the STATE, unless it is done for you
> by the implementation on "raise" operation.
>

Could you give me some references to this "cancel_e" thing? I've never
heard of it so I don't know what you are talking about.

> Hmm... Gurus, are there any chances that some day you will
> finally produce some standard *C++*-Pthreads/POSIX bindings
> that would define things like that?!

Thanks,
D.P.

Alexander Terekhov

unread,
Feb 14, 2002, 1:09:53 PM2/14/02
to
Davlet Panech <Davlet...@Tellabs.com> wrote in message news:<3C6BCE95...@Tellabs.com>...
[...]

> OK thanks for the link.

I have a LOT of them; Net.Generation (sort of ;-))
BTW, complete POSIX.1-2001/SUSv3 PDF links are here:

http://groups.google.com/groups?as_umsgid=c29b5e33.0202050156.2013e97d%40posting.google.com

> > > Do you know of any systems where it might fail? Believe me
> > > I have good reasons to do this.
> > >
> > > >
> > > > Avoid setjmp/longjmp at all cost.
> > >
> > > It's not like I have a lot of choice.
> >
> > What do you mean? Do you want to stop unwinding process or
> > do something like that?
>
> Yes.

I think that you just can't PORTABLY do it.

> > I guess you would need something
> > along the lines of standard pthread_cancel_e exception
>
> What is pthread_cancel_e? If there is such a thing I don't
> have it on my machine.

I guess that you could find it here:

http://www.testdrive.compaq.com

Gee! Is there something like THIS from IBM/SUN/HP/...
It is just GREAT!

> > and a mechanism to *re-enable*[1] cancelation once you
> > just eat cancel exception - stop cancel/unwinding process.
>
> Yes, there is a number of issues involved, but first I need
> a reliable way to throw an exception in response to a cancellation
> request.

Why not just let the thread terminate AS REQUESTED? Or you
could just implement your own "stop" or whatever synchronization
protocol (well, you would have some problems with non-cond.wait
BLOCKING calls, but it MIGHT be acceptable for you, oder?).

> > [1] It is not clear to me whether pthread_setcancelstate()
> > is supposed to do it if invoked (with PTHREAD_CANCEL_ENABLE)
> > *during* unwinding; I mean implementations which already have
> > published _cancel_e (and _exit_e) exceptions, which would
> > allow to catch and just eat them -- do not re-throw. Also,
> > since cancelation could be "raised" from some async-cancel-
> > region, I guess, you would need to restore PTHREAD_CANCEL_DEFERRED
> > TYPE prior to setting the STATE, unless it is done for you
> > by the implementation on "raise" operation.
> >
>
> Could you give me some references to this "cancel_e" thing?

Sure, that's sort of Butenhof's PWPT[1] the *2nd* volume
(and its free): ;-)

http://www.tru64unix.compaq.com/docs/base_doc/DOCUMENTATION/V51_PDF/ARH9RBTE.PDF

regards,
alexander.

[1] Must read: http://www.awl.com/cseng/titles/0-201-63392-2/

David Butenhof

unread,
Feb 15, 2002, 8:35:21 AM2/15/02
to
Davlet Panech wrote:

> "Casper H.S. Dik" wrote:
>>
>> The thread is supposed to *die*. You keep it alive by
>> longjumping out of the cleanup code. This doesn't
>> strike you as risky?
>
> All right, it does now. Perhaps I should explain what I am trying to do.
> I am trying to implement thread cancellation in C++ such that a
> cancellation
> request results in a C++ exception in the thread being cancelled. I
> can't throw
> exceptions from cancellation handlers because such exceptions would have
> to propagate through PTHREADs code, and there is no telling what might
> happen
> in that case.

In a CORRECT implementation of pthreads and C++, the system already does
what you want. That is, cancellation raises an exception that will properly
invoke all nested POSIX cleanup handlers as well as any C++ catch clauses
and object destructors, even when they are interleaved on the stack.

There's simply no other way to do this reliably, safely, or portably. If
you're working with a "busted" implementation (unfortunately, that means
one that blindly and literally follows the minimum requirements of the two
separate standards without having given any thought to how they work
together... which is all too common), then you're just stuck. Any attempt
to "improve" your situation will just make it worse.

> I guess using PTHREAD cancellation for this is a bad idea after all.

Well, yes and no. If you're only trying to make sure that object
destructors run on cancellation, then you're just trying to work around a
bug in the implementation; what you expect is reasonable, but you can't do
it correctly or safely by yourself.

On the other hand, if your intent is to use cancellation to implement the
ability to generate an arbitrary cross-thread C++ exception, that's off
base. C++ doesn't support asynchronous exceptions in the first place, and
you'll probably end up in deep water even on a correct implementation.

> I also considered using signals:
> - Each thread has a (boolean) `cancelled' flag associated with it
> - Each thread "agrees" to check this flag before making any blocking
> system calls
> - Cancelling a thread means setting the flag and sending a signal to
> the thread
> being cancelled
> - Each thread has to watch for EINTR error code returned by the system
> functions
> to detect a cancellation request

Beware that you might cause C/C++ runtime functions (like stdio or I/O
streams) to take an unexpected EINTR. In theory, all code that calls
interruptible functions MUST correctly handle EINTR... but in practice most
don't. You'd need to block the signal except around your own direct calls
to syscalls that can return EINTR.

> - Threads should not alter the settings for the signal used to deliver
> the cancellation
> requests
>
> Obviously this is more restrictive than the native PTHREAD cancellation;
> there are also
> race conditions that have to be dealt with, but that's the general idea.
>
> Comments/suggestions?

Yeah. Suggestion: forget the whole thing. ;-)

Alexander Terekhov

unread,
Feb 15, 2002, 6:43:01 PM2/15/02
to
Davlet Panech <Davlet...@Tellabs.com> wrote in message news:<3C6BCD76...@Tellabs.com>...

[...cancellation using signals...]

> Comments/suggestions?

First of all I have a question.

What is your platform?

Maybe that is Linux (linuxthreads/glibc/g++)?

If so, I would *suggest* that join the "plea" and
just add some HEAT/PRESSURE/whatever here: ;-)

http://sources.redhat.com/ml/libc-alpha/2002-02/msg00110.html

Also, you might want to take a look at pthreads-win32:

http://sources.redhat.com/pthreads-win32

and its way of doing C++ exception-based cancel/exit[1].

As for signal based cancel, AFAICT you would need
something along the lines of *pselect* (blocking
calls with signal masks) to prevent race conditions.

Perhaps you could just somehow "overload" (you won't need
to change all your predicates then) pthread_cond_wait and
pthread_cond_timedwait calls and raise exception using
something along the lines of:

http://groups.google.com/groups?as_umsgid=3B0BA709.973337EB%40web.de

regards,
alexander.

[1] I am actually NOT sure whether pthreads-win32 does
everything correctly/right. In particular, I am still
in total darkness with respect to behavior inside catch
handlers (during cancel), std::uncaught_exception(),
etc. Hopefully Mr.Butenhof will soon clarify all these
issues in the "Threads and exceptions" thread! ;-)

0 new messages