Skip to content

Commit

Permalink
Abort when exception is uncaught.
Browse files Browse the repository at this point in the history
  • Loading branch information
gassmoeller committed Oct 20, 2022
1 parent 8695e98 commit 68c5b83
Showing 1 changed file with 55 additions and 21 deletions.
76 changes: 55 additions & 21 deletions source/base/mpi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,46 @@ namespace Utilities



namespace internal
{
namespace CollectiveMutexImplementation
{
/**
* Abort, should there be an exception being processed (see the error
* message).
*/
void
check_exception()
{
#ifdef DEAL_II_WITH_MPI
# if __cpp_lib_uncaught_exceptions >= 201411
// std::uncaught_exception() is deprecated in c++17
if (std::uncaught_exceptions() != 0)
# else
if (std::uncaught_exception() == true)
# endif
{
std::cerr
<< "---------------------------------------------------------\n"
<< "An exception was thrown inside a section of the program\n"
<< "guarded by a CollectiveMutex.\n"
<< "Because a CollectiveMutex guards critical communication\n"
<< "handling the exception would likely\n"
<< "deadlock because only the current process is aware of the\n"
<< "exception. To prevent this deadlock, the program will be\n"
<< "aborted.\n"
<< "---------------------------------------------------------"
<< std::endl;

MPI_Abort(MPI_COMM_WORLD, 1);
}
#endif
}
} // namespace CollectiveMutexImplementation
} // namespace internal



CollectiveMutex::CollectiveMutex()
: locked(false)
, request(MPI_REQUEST_NULL)
Expand All @@ -1089,6 +1129,10 @@ namespace Utilities

CollectiveMutex::~CollectiveMutex()
{
// First check if this destructor is called during exception handling
// if so, abort.
internal::CollectiveMutexImplementation::check_exception();

Assert(
!locked,
ExcMessage(
Expand Down Expand Up @@ -1138,38 +1182,28 @@ namespace Utilities
{
(void)comm;

// First check if this function is called during exception handling
// if so, abort. This can happen if a ScopedLock is destroyed.
internal::CollectiveMutexImplementation::check_exception();

Assert(
locked,
ExcMessage(
"Error: MPI::CollectiveMutex needs to be locked before unlock()"));

// Only communicate with other processes if there is no uncaught
// exception to avoid a deadlock.
#ifdef DEAL_II_WITH_MPI
# if __cpp_lib_uncaught_exceptions >= 201411
// std::uncaught_exception() is deprecated in c++17
if (std::uncaught_exceptions() == 0 && comm != MPI_COMM_SELF)
# else
if (std::uncaught_exception() == false && comm != MPI_COMM_SELF)
# endif
{
// TODO: For now, we implement this mutex with a blocking barrier
// in the lock and unlock. It needs to be tested, if we can move
// to a nonblocking barrier (code disabled below):
// TODO: For now, we implement this mutex with a blocking barrier
// in the lock and unlock. It needs to be tested, if we can move
// to a nonblocking barrier (code disabled below):
# if 0
const int ierr = MPI_Ibarrier(comm, &request);
AssertThrowMPI(ierr);
const int ierr = MPI_Ibarrier(comm, &request);
AssertThrowMPI(ierr);
# else
const int ierr = MPI_Barrier(comm);
AssertThrowMPI(ierr);
const int ierr = MPI_Barrier(comm);
AssertThrowMPI(ierr);
# endif
}
#endif

// Unlock the mutex in either case. Either we successfully
// synchronized processes in the barrier, or we want to
// continue to unwind the stack without throwing exceptions
// in the destructor of this class.
locked = false;
}

Expand Down

0 comments on commit 68c5b83

Please sign in to comment.