From 57c6048683b000285634777b64192978a6a4b8b2 Mon Sep 17 00:00:00 2001 From: Rene Gassmoeller Date: Thu, 20 Oct 2022 09:56:37 -0400 Subject: [PATCH] Abort when exception is uncaught. --- source/base/mpi.cc | 77 +++++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/source/base/mpi.cc b/source/base/mpi.cc index 605c00fffd..cb58254d59 100644 --- a/source/base/mpi.cc +++ b/source/base/mpi.cc @@ -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) @@ -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( @@ -1138,38 +1182,29 @@ 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; } -- 2.39.5