Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
gscip_message_handler.cc
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <stdio.h>
17
18#include <atomic>
19#include <memory>
20
21#include "absl/status/statusor.h"
24#include "scip/pub_message.h"
25#include "scip/type_message.h"
26
27// This is an incomplete SCIP struct meant to be fully defined by SCIP users.
32
33 // This will be set to true by ScopedSCIPMessageHandlerDisabler when
34 // GScip::Solve() returns. We use an atomic here since SCIP can be
35 // multi-threaded.
36 std::atomic<bool> disabled = false;
37
39};
40
41namespace operations_research {
42namespace internal {
43namespace {
44
45// Equivalent to SCIP_DECL_MESSAGEHDLRFREE(SCIPMessageHandlerFree).
46SCIP_RETCODE SCIPMessageHandlerFree(SCIP_MESSAGEHDLR* const handler) {
47 SCIP_MessagehdlrData* const data = SCIPmessagehdlrGetData(handler);
48 delete data;
49 CHECK_EQ(SCIPmessagehdlrSetData(handler, nullptr), SCIP_OKAY);
50 return SCIP_OKAY;
51}
52
53// Shared function used by all three implementations below.
54void SCIPMessageHandlerPrinter(const GScipMessageType message_type,
55 SCIP_MESSAGEHDLR* const handler,
56 const char* const message) {
57 // Contrary to SCIP's documentation, the code of handleMessage() in
58 // src/scip/message.c never calls the handler functions when its input `msg`
59 // is NULL.
60 CHECK(message != nullptr);
61
62 SCIP_MessagehdlrData* const data = SCIPmessagehdlrGetData(handler);
63 if (data->disabled) {
64 LOG(ERROR) << "Unexpected SCIP message: " << message;
65 return;
66 }
67
68 // We ignore empty messages. The implementation of handleMessage() in
69 // src/scip/message.c calls this function with an empty message when the
70 // handler's buffer is flushed but was empty.
71 //
72 // This typically happenbs when the handler is freed since messagehdlrFree()
73 // calls messagePrintWarning(), messagePrintDialog() and messagePrintInfo()
74 // will NULL message just before calling the handler free function (which is
75 // SCIPMessageHandlerFree() above). So this function is usually called three
76 // times when the custom handler is freed. There is no need to redirect these
77 // useless calls to the gscip_message_handler user function.
78 //
79 // Note that we do this test only in the `!disabled` branch since we want to
80 // detect cases of unexpected calls even with empty messages in the other
81 // branch.
82 if (message[0] == '\0') {
83 return;
84 }
86}
87
88// Equivalent to SCIP_DECL_MESSAGEINFO(SCIPMessageHandlerInfo).
89void SCIPMessageHandlerInfo(SCIP_MESSAGEHDLR* const handler, FILE*,
90 const char* const message) {
91 SCIPMessageHandlerPrinter(GScipMessageType::kInfoMessage, handler, message);
92}
93
94// Equivalent to SCIP_DECL_MESSAGEDIALOG(SCIPMessageHandlerDialog).
95void SCIPMessageHandlerDialog(SCIP_MESSAGEHDLR* const handler, FILE*,
96 const char* const message) {
97 SCIPMessageHandlerPrinter(GScipMessageType::kDialogMessage, handler, message);
98}
99
100// Equivalent to SCIP_DECL_MESSAGEWARNING(SCIPMessageHandlerWarning).
101void SCIPMessageHandlerWarning(SCIP_MESSAGEHDLR* const handler, FILE*,
102 const char* const message) {
103 SCIPMessageHandlerPrinter(GScipMessageType::kWarningMessage, handler,
104 message);
105}
106
107} // namespace
108
109void ReleaseSCIPMessageHandler::operator()(SCIP_MESSAGEHDLR* handler) const {
110 if (handler != nullptr) {
111 CHECK_EQ(SCIPmessagehdlrRelease(&handler), SCIP_OKAY);
112 }
113}
114
115MessageHandlerPtr CaptureMessageHandlerPtr(SCIP_MESSAGEHDLR* const handler) {
116 if (handler != nullptr) {
117 SCIPmessagehdlrCapture(handler);
118 }
119 return MessageHandlerPtr(handler);
120}
121
122absl::StatusOr<MessageHandlerPtr> MakeSCIPMessageHandler(
123 const GScipMessageHandler gscip_message_handler) {
124 // We use a unique_ptr here to make sure we delete the data if
125 // SCIPmessagehdlrCreate() fails.
126 auto data = std::make_unique<SCIP_MessagehdlrData>(gscip_message_handler);
127 SCIP_MESSAGEHDLR* message_handler = nullptr;
129 SCIPmessagehdlrCreate(&message_handler,
130 /*bufferedoutput=*/true,
131 /*filename=*/nullptr,
132 /*quiet=*/false,
133 /*messagewarning=*/SCIPMessageHandlerWarning,
134 /*messagedialog=*/SCIPMessageHandlerDialog,
135 /*messageinfo=*/SCIPMessageHandlerInfo,
136 /*messagehdlrfree=*/SCIPMessageHandlerFree,
137 /*messagehdlrdata=*/data.get()));
138
139 // SCIPmessagehdlrCreate() succeeded, we disable the deletion of the data by
140 // the unique_ptr since the ownership has been transferred to SCIP.
141 data.release();
142
143 return MessageHandlerPtr(message_handler);
144}
145
149
151 if (handler_ != nullptr) {
152 // Note that SCIPmessagehdlrGetData is a macro in optimized builds and a
153 // function in debug ones. Hence here we assign the result to a variable
154 // instead of chaining the calls.
155 SCIP_MessagehdlrData* const data = SCIPmessagehdlrGetData(handler_.get());
156 data->disabled = true;
157 }
158}
159
160} // namespace internal
161} // namespace operations_research
absl::StatusOr< MessageHandlerPtr > MakeSCIPMessageHandler(const GScipMessageHandler gscip_message_handler)
Make a message handler for SCIP that calls the input function.
MessageHandlerPtr CaptureMessageHandlerPtr(SCIP_MESSAGEHDLR *const handler)
std::unique_ptr< SCIP_MESSAGEHDLR, ReleaseSCIPMessageHandler > MessageHandlerPtr
In SWIG mode, we don't want anything besides these top-level includes.
std::function< void(GScipMessageType type, absl::string_view message)> GScipMessageHandler
#define RETURN_IF_SCIP_ERROR(x)
This is an incomplete SCIP struct meant to be fully defined by SCIP users.
std::atomic< bool > disabled
const operations_research::GScipMessageHandler gscip_message_handler
SCIP_MessagehdlrData(const operations_research::GScipMessageHandler gscip_message_handler)
std::string message
Definition trace.cc:397