From be0a5da9d57c80fd304d54e8f88c388363269b85 Mon Sep 17 00:00:00 2001 From: Christophe Geuzaine <cgeuzaine@uliege.be> Date: Mon, 23 May 2022 19:50:11 +0200 Subject: [PATCH] OpenMP forbids leaving block via exception: catch exceptions inside the block, and throw the last error outside the block (cf. #1941) --- src/geo/GModelIO_MSH4.cpp | 13 +++++++++++-- src/mesh/Generator.cpp | 21 ++++++++++++++++++--- src/mesh/meshGRegionHxt.cpp | 21 +++++++++++++++------ 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/src/geo/GModelIO_MSH4.cpp b/src/geo/GModelIO_MSH4.cpp index 0fd59119e2..54222d9a17 100644 --- a/src/geo/GModelIO_MSH4.cpp +++ b/src/geo/GModelIO_MSH4.cpp @@ -15,6 +15,7 @@ #include <string> #include <cstdlib> #include <limits> +#include <stdexcept> #include "GmshDefines.h" #include "OS.h" @@ -2847,6 +2848,7 @@ int GModel::_writePartitionedMSH4(const std::string &baseName, double version, { int nthreads = CTX::instance()->numThreads; if(!nthreads) nthreads = Msg::GetMaxThreads(); + bool exceptions = false; #pragma omp parallel for num_threads(nthreads) for(std::size_t part = 1; part <= getNumPartitions(); part++) { std::ostringstream sstream; @@ -2860,10 +2862,17 @@ int GModel::_writePartitionedMSH4(const std::string &baseName, double version, else { Msg::Info("Writing partition %d in file '%s'", part, sstream.str().c_str()); } - _writeMSH4(sstream.str(), version, binary, saveAll, saveParametric, - scalingFactor, false, part); + try { // OpenMP forbids leaving block via exception + _writeMSH4(sstream.str(), version, binary, saveAll, saveParametric, + scalingFactor, false, part); + } + catch(...) { + exceptions = true; + } } + if(exceptions) throw std::runtime_error(Msg::GetLastError()); + return 1; } diff --git a/src/mesh/Generator.cpp b/src/mesh/Generator.cpp index 4e542c2878..5f87235687 100644 --- a/src/mesh/Generator.cpp +++ b/src/mesh/Generator.cpp @@ -5,6 +5,8 @@ #include <stdlib.h> #include <stack> +#include <stdexcept> + #include "GmshConfig.h" #include "GmshMessage.h" #include "Numeric.h" @@ -378,12 +380,18 @@ static void Mesh1D(GModel *m) } int nPending = 0; + bool exceptions = false; #pragma omp parallel for schedule(dynamic) num_threads(nthreads) for(size_t K = 0; K < temp.size(); K++) { int localPending = 0; GEdge *ed = temp[K]; if(ed->meshStatistics.status == GEdge::PENDING) { - ed->mesh(true); + try{ // OpenMP forbids leaving block via exception + ed->mesh(true); + } + catch(...){ + exceptions = true; + } #pragma omp atomic capture { ++nPending; @@ -392,7 +400,7 @@ static void Mesh1D(GModel *m) } if(!nIter) Msg::ProgressMeter(localPending, false, "Meshing 1D..."); } - + if(exceptions) throw std::runtime_error(Msg::GetLastError()); if(!nPending) break; if(nIter++ > CTX::instance()->mesh.maxRetries) break; } @@ -525,6 +533,7 @@ static void Mesh2D(GModel *m) } int nPending = 0; + bool exceptions = false; std::vector<GFace *> temp; temp.insert(temp.begin(), f.begin(), f.end()); #pragma omp parallel for schedule(dynamic) num_threads(nthreads) @@ -532,7 +541,12 @@ static void Mesh2D(GModel *m) int localPending = 0; if(temp[K]->meshStatistics.status == GFace::PENDING) { backgroundMesh::current()->unset(); - temp[K]->mesh(true); + try{ // OpenMP forbids leaving block via exception + temp[K]->mesh(true); + } + catch(...) { + exceptions = true; + } #pragma omp atomic capture { ++nPending; @@ -541,6 +555,7 @@ static void Mesh2D(GModel *m) } if(!nIter) Msg::ProgressMeter(localPending, false, "Meshing 2D..."); } + if(exceptions) throw std::runtime_error(Msg::GetLastError()); if(!nPending) break; // iter == 2 is for meshing re-parametrized surfaces; after that, we // serialize (self-intersections of 1D meshes are not thread safe)! diff --git a/src/mesh/meshGRegionHxt.cpp b/src/mesh/meshGRegionHxt.cpp index a399ee5b8d..f45064bf0c 100644 --- a/src/mesh/meshGRegionHxt.cpp +++ b/src/mesh/meshGRegionHxt.cpp @@ -5,6 +5,7 @@ #include <map> #include <set> +#include <stdexcept> #include "GmshConfig.h" #include "meshGRegionHxt.h" @@ -55,6 +56,7 @@ static HXTStatus nodalSizesCallBack(double *pts, uint32_t *volume, HXT_INFO("Computing %smesh sizes...", useInterpolatedSize ? "interpolated " : ""); int nthreads = getNumThreads(); + bool exceptions = false; #pragma omp parallel for schedule(dynamic) num_threads(nthreads) for(size_t i = 0; i < numPts; i++) { if(volume[i] < 0 || volume[i] >= allGR->size()) { @@ -62,14 +64,21 @@ static HXTStatus nodalSizesCallBack(double *pts, uint32_t *volume, continue; } GRegion *gr = (*allGR)[volume[i]]; - double lc = BGM_MeshSizeWithoutScaling(gr, 0, 0, pts[4 * i + 0], - pts[4 * i + 1], pts[4 * i + 2]); - if(useInterpolatedSize && pts[4 * i + 3] > 0.0) - pts[4 * i + 3] = std::min(pts[4 * i + 3], std::min(lcGlob, lc)); - else - pts[4 * i + 3] = std::min(lcGlob, lc); + try{ // OpenMP forbids leaving block via exception + double lc = BGM_MeshSizeWithoutScaling(gr, 0, 0, pts[4 * i + 0], + pts[4 * i + 1], pts[4 * i + 2]); + if(useInterpolatedSize && pts[4 * i + 3] > 0.0) + pts[4 * i + 3] = std::min(pts[4 * i + 3], std::min(lcGlob, lc)); + else + pts[4 * i + 3] = std::min(lcGlob, lc); + } + catch(...) { + exceptions = true; + } } + if(exceptions) throw std::runtime_error(Msg::GetLastError()); + HXT_INFO("Done computing %smesh sizes", useInterpolatedSize ? "interpolated " : ""); return HXT_STATUS_OK; -- GitLab