Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions cpp/src/branch_and_bound/mip_node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <dual_simplex/types.hpp>

#include <utilities/hashing.hpp>
#include <utilities/logger.hpp>
#include <utilities/omp_helpers.hpp>

#include <cmath>
Expand Down Expand Up @@ -44,18 +45,29 @@ class mip_node_t {
{
// Iterative teardown to avoid stack overflow on deep trees.
// Detach all descendants breadth-first, then destroy them as leaves.
std::vector<std::unique_ptr<mip_node_t>> nodes;
for (auto& c : children) {
if (c) { nodes.push_back(std::move(c)); }
}
// nodes.size() grows so that this loop only terminates when only leaves remain
for (size_t i = 0; i < nodes.size(); ++i) {
for (auto& c : nodes[i]->children) {
// vector::push_back can throw bad_alloc; the catch-all keeps the destructor
// exception-free. Under OOM, any not-yet-detached descendants are destroyed
// via the recursive unique_ptr chain in `children` as this frame unwinds.
try {
std::vector<std::unique_ptr<mip_node_t>> nodes;
for (auto& c : children) {
if (c) { nodes.push_back(std::move(c)); }
}
}
// nodes.size() grows so that this loop only terminates when only leaves remain
for (size_t i = 0; i < nodes.size(); ++i) {
for (auto& c : nodes[i]->children) {
if (c) { nodes.push_back(std::move(c)); }
}
}

// scope-exit ensure destruction of all detached leaves
// scope-exit ensure destruction of all detached leaves
} catch (const std::exception& e) {
CUOPT_LOG_ERROR(
"mip_node_t destructor: iterative teardown failed (%s); falling back to "
"recursive unique_ptr destruction.",
e.what());
} catch (...) {
}
}

mip_node_t(mip_node_t&&) = default;
Expand Down
44 changes: 43 additions & 1 deletion cpp/src/grpc/client/grpc_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,49 @@ grpc_client_t::grpc_client_t(const std::string& server_address) : impl_(std::mak
chunked_array_threshold_bytes_ = config_.max_message_bytes * 3 / 4;
}

grpc_client_t::~grpc_client_t() { stop_log_streaming(); }
grpc_client_t::~grpc_client_t()
{
// The destructor must not propagate exceptions AND must not leave a joinable
// std::thread alive — a joinable thread's destructor calls std::terminate.
// We inline a noexcept variant of stop_log_streaming() here so that on any
// failure we still detach the thread before its destructor runs.
stop_logs_.store(true);
try {
std::lock_guard<std::mutex> lk(log_context_mutex_);
if (active_log_context_) {
static_cast<grpc::ClientContext*>(active_log_context_)->TryCancel();
}
} catch (const std::exception& e) {
CUOPT_LOG_ERROR(
"grpc_client_t destructor: TryCancel/lock failed (%s); proceeding to "
"join/detach.",
e.what());
} catch (...) {
// Best-effort cancel; fall through to join/detach the thread.
}
std::unique_ptr<std::thread> t;
std::swap(t, log_thread_);
if (t && t->joinable()) {
try {
t->join();
} catch (const std::exception& e) {
CUOPT_LOG_ERROR("grpc_client_t destructor: log-thread join failed (%s); detaching.",
e.what());
// join failed (e.g., std::system_error). Detach so the local
// unique_ptr's destructor doesn't terminate on the joinable thread.
try {
t->detach();
} catch (const std::exception& e2) {
CUOPT_LOG_ERROR(
"grpc_client_t destructor: detach also failed (%s); thread may "
"terminate the process on unique_ptr destruction.",
e2.what());
} catch (...) {
}
} catch (...) {
}
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

bool grpc_client_t::connect()
{
Expand Down
15 changes: 11 additions & 4 deletions cpp/src/mip_heuristics/feasibility_jump/fj_cpu.cu
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,17 @@ class timing_raii_t {

~timing_raii_t()
{
auto end_time = std::chrono::high_resolution_clock::now();
auto duration =
std::chrono::duration_cast<std::chrono::duration<double>>(end_time - start_time_);
times_vec_.push_back(duration.count());
// vector::push_back can throw bad_alloc; the catch-all keeps the destructor
// exception-free. Losing one timing sample under OOM is acceptable.
try {
auto end_time = std::chrono::high_resolution_clock::now();
auto duration =
std::chrono::duration_cast<std::chrono::duration<double>>(end_time - start_time_);
times_vec_.push_back(duration.count());
} catch (const std::exception& e) {
CUOPT_LOG_ERROR("timing_raii_t destructor: failed to record sample (%s).", e.what());
} catch (...) {
}
}

private:
Expand Down
Loading