[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference clt::cma

Title:DECthreads Conference
Moderator:PTHRED::MARYSTEON
Created:Mon May 14 1990
Last Modified:Fri Jun 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:1553
Total number of notes:9541

1539.0. "Problem with embeded PTHREAD TRY blocks and C++ destructors" by ANNECY::LAROCHE_P (Ne Suze que si l'on Sancerre) Mon May 05 1997 12:51

Hello,

I have a strange behaviour with C++ objects destructors and embedded PTHREAD TRY
blocks. In some cases, the destructor associated with a given object is called 
TWICE!

This happens on the following environment:

- DIGITAL UNIX V4.0B
- DEC C++ V5.5-004

To demonstrate this, I am building and executing the following code
(build is done like that: cxx -O0 -threads -o tryTest tryTest.cxx):

--------------------------------------------------------------------------------
//
// tryTest.cxx
//

//
// Include files
//

#include <pthread.h>
#include <pthread_exception.h>
#include <iostream.h>

//
// Dummy class
//

class CDummy
{
 public:
  CDummy  () { cout << "CDummy object (" << this << ") constructor called" << endl;};
  ~CDummy () { cout << "CDummy object (" << this << ") destructor  called" << endl;};
};

void main ()
{
  TRY
  {
    //
    // Allocate automatic dummy object to demonstrate double destruction
    //

    CDummy aDummy;

    TRY
    {
      //
      // Generate PTHREAD exception
      //

      RAISE (pthread_cancel_e);
    }
    CATCH_ALL
    {
      cerr << "Inner PTHREAD exception caught" << endl;
    }
    ENDTRY
  }
  CATCH_ALL
  {
    cerr << "Outer PTHREAD exception caught" << endl;
  }
  ENDTRY
}

-------------------------------------------------------------------------------

This program outputs the following text:

CDummy object (0x11ffff100) constructor called
CDummy object (0x11ffff100) destructor  called
Inner PTHREAD exception caught
CDummy object (0x11ffff100) destructor  called

So the destructor is called twice.

Does someone have an idea on how to avoid this problem?

Thank you in advance,
Pierre

T.RTitleUserPersonal
Name
DateLines
1539.1Looks like a C++ problem to me...WTFN::SCALESDespair is appropriate and inevitable.Mon May 05 1997 15:5119
.0> CDummy object (0x11ffff100) constructor called
.0> CDummy object (0x11ffff100) destructor  called
.0> Inner PTHREAD exception caught
.0> CDummy object (0x11ffff100) destructor  called
.0> 
.0> So the destructor is called twice.
.0> 
.0> Does someone have an idea on how to avoid this problem?

It looks like the destructor is being called prematurely (and is then called
-again- at the _right_ time) since the destructor output shows up before the
CATCH_ALL output.  I'd suggest that this is a C++ problem, and that you should
pursue it with the C++ folks.  (You might also try adding a RERAISE to your
inner CATCH_ALL or replace it with a FINALLY and see if that affects the
behavior; I do hope that you're not actually CATCH'ing cancel's without
reraising them in your application...)


				Webb
1539.2Topic cross-posted into C_PLUS_PLUS conferenceANNECY::LAROCHE_PNe Suze que si l&#039;on SancerreTue May 06 1997 03:569
re: .1

I will cross-post this problem into the C_PLUS_PLUS conference.

By the way, in my application, the exception I am currently catching is not
pthread_cancel_e. I just used this exception to demonstrate the problem.

Thanks for your answer,
Pierre
1539.3DCETHD::BUTENHOFDave Butenhof, DECthreadsTue May 06 1997 09:1817
Note that the local CDummy is declared INSIDE the TRY block, and thus should
be destroyed whenever that block is exited. Because raising an exception IS
an exit from the block, I would expect to see the destructor run prior to the
CATCH. Interestingly, our new (4.0) TRY/CATCH/ENDTRY macros, which use the
builtin exception support for DEC C, are loops. At first, I wondered if that
could be the cause of the double-destruct. But, of course, it should have
resulted in a double construct, too, in that case, and it didn't.
Furthermore, C++ doesn't support the C exception syntax, and our headers
therefore use the old portable setjmp/longjmp macros when invoked in C++ (I
think). Even more interestingly, I tried moving the declaration out of the
TRY block, and the behavior was the same.

I don't have any idea what could cause this. Even if it IS a problem with the
TRY/CATCH macros, I think the C++ folks are going to have to help figure out
what's going on.

	/dave
1539.4Does pthread_exc_raise_np cause longjmp to be executed?DECC::KAOTue May 13 1997 12:4068
For every automatic object that has a destructor, DEC C++ creates an implicit
exception handler.  This makes sure the destructors will be called for local
variables when the stack is unwound either by a C++ thrown exception or a
call to "longjmp".

The combination of setjmp and longjmp shall work fine for C++ objects without
special treatment.  Otherwise it is a bug to the DEC C++ compiler or exception
runtime libraries.  (On the other hand, this example .0, compiled with 
"-nocleanup" works fine, however it is not recommended)

I tried to simulate this case with setjmp and longjmp, but failed.
My example works fine (See below).  Could you check what happened after the
routine "pthread_exc_raise_np" was called?  Does DECthread perform its own
stack unwind other than longjmp?

Shi-Jung


/* cpp3561b.cxx */
#include "setjmp.h"
extern jmp_buf myjmpbuf;

void raise_longjmp() {
  longjmp(myjmpbuf,0);
  return;
}

/* cpp3561a.cxx */
#include "setjmp.h"
extern "C" {extern int printf(const char *, ...);}
//
// Dummy class
//
jmp_buf myjmpbuf;
class CDummy
{
 public:
  CDummy  () { printf("CDummy constructor called. %0x\n",this);}
  ~CDummy () { printf("CDummy distructor called. %0x\n",this);}
};

extern void raise_longjmp();

void main ()
{

  if (!setjmp(myjmpbuf)) {

    CDummy aDummy;

    if (!setjmp(myjmpbuf)) {
      raise_longjmp();
    } else {
      printf("Inner PTHREAD exception caught.\n");
    }

  } else {
      printf("Outer PTHREAD exception caught.\n");
  }
}

shijun.zko.dec.com> $CEXE/deccxx_driver cpp3561a.cxx cpp3561b.cxx
cpp3561a.cxx:
cpp3561b.cxx:
shijunom> a.out
CDummy constructor called. 1fffefc0
Inner PTHREAD exception caught.
CDummy distructor called. 1fffefc0
1539.5DCETHD::BUTENHOFDave Butenhof, DECthreadsMon May 19 1997 09:4310
Prior to Digital UNIX 4.0, we always used longjmp. As of 4.0, for C
compilation we use the try/except extensions. Since C++ doesn't support them,
we have to continue using longjmp for TRY/CATCH clauses compiled under C++.
The "catch" is in dealing with nested frames that mix use of try/except and
setjmp/longjmp. There are cases where it's possible for something to get
missed -- particularly when an "intermediate" frame has a native exception
handler without the bookkeeping that we use for try/except-based TRY/CATCH
blocks.

	/dave