Usrp2 dtor can throw!

Hi all,
the usrp2 destructor can throw an exeption due the fact that while
destroying the
implementation ( usrp2::impl::~impl() ) a stop_bg() is performed.

The stop_bg implementation is:

void
usrp2::impl::stop_bg()
{
d_bg_running = false;
d_bg_pending_cond.notify_one(); // FIXME: check if needed
d_rx_tg.join_all();
}

indeed the boost::thread_group::join_all is an interruption point for
boost thread.
This can lead to a crash in case an user thread (using boost threads)
receives an
interruption while a stack unwinding is already occurring and an usrp2
is destroyed.

There are two ways to correct the problem:

  1. Instanziate a boost::this_thread::disable_interruption inside the
    stop_bg()
  2. or do a try{ } catch() { } inside the impl destructor.

This is very dangerous because normaly the user code acquire a usrp
instance
with a boost::shared_ptr, I guess this was done to reliefe the user to
perform an
explicit delete, however due this bug the user is forced to do:

usrp2::usrp2::sptr myDevice = usrp2::usrp2::make(“eth1”, “”, 1024*1024)

try {
myDevice.reset();
}
catch(…) {
}

Regards
Gaetano M.

I dont think that this is an issue. Are you actually seeing exceptions
thrown at deconstruction time?

There is nothing that would cause the dtor to get interrupted AFAIK. The
only way this would be an issue is when thread “A” calls interrupt() on
thread “B” when “B” is blocking in the join_all call within the
usrp2::impl::~impl(). Which could happen if you had a usrp2::impl sptr
count reset to 0 at the exit of thread “B”.

On the other hand, its possible for boost::thread_interruption to be
thrown in a thread when the scheduler shuts down. This is due to the
gr-scheduler calling interrupt_all() on the thread group. If thats the
case, then the usrp2::impl thread body is probably missing a disable
interruption or a try/catch. If you are seeing an exception thrown,
maybe this is the problem?

In any case, putting a boost::this_thread::disable_interruption at the
first line of the dtor wouldnt hurt to do. :slight_smile:

-josh

On Sat, Jan 15, 2011 at 8:34 PM, Josh B. [email protected] wrote:

I dont think that this is an issue. Are you actually seeing exceptions
thrown at deconstruction time?

It is a very issue because it was for us and I digged this due to our
application
experiencing crash.

There is nothing that would cause the dtor to get interrupted AFAIK. The
only way this would be an issue is when thread “A” calls interrupt() on
thread “B” when “B” is blocking in the join_all call within the
usrp2::impl::~impl(). Which could happen if you had a usrp2::impl sptr
count reset to 0 at the exit of thread “B”.

Consider this code snipset:

boost::thread::operator()() {
usrp2::usrp2::sptr myDevice = usrp2::usrp2::make(…)

boost::thread::sleep(…)
}

if a boost thread running that code gets an interrupt while sleeping, it
throws an exception (boost::thread_interrupted) due the fact that sleep
is an interruption point for boost. At this point the stack unwinding
starts
the destruction of the smartpointer myDevice calling then the destructor
of usrp2::usrp2::impl performing a thread_group::join_all (another
interruption
point), at this point if the thread gets another interrupt the
thread_group::join_all
throws another exception while a stack unwinding is already going on =>
program aborts.

To rub salt into wound consider that boost (I believe corrected only
on 1.45) was
affected by the bug #2330 and thread under some circumstances just
ignore
interrupt (even if passing from an interruption point), so some
application
(like our one) in order to be sure to not stuck for ever on a join
after an interrupt
does instead a timed_join and reissuing the interrupt in case the join
times out.

In any case, putting a boost::this_thread::disable_interruption at the
first line of the dtor wouldnt hurt to do. :slight_smile:

I would suggest a try catch instead for two reasons, first of all a
DTOR should not
throw ever (even next c++ standard has the requirement to check at
compile time of a
DTOR can throw) and disable interruption can have as effect a delay in
the thread
exiting if the thread_group::join all inside the usrp2::impl::stop_bg()
doesn’t
terminate quick enough (or may be never).

Regards
Gaetano M.