OR-Tools  9.0
gscip_message_handler.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 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"
22 #include "ortools/base/logging.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 
41 namespace operations_research {
42 namespace internal {
43 namespace {
44 
45 // Equivalent to SCIP_DECL_MESSAGEHDLRFREE(SCIPMessageHandlerFree).
46 SCIP_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.
54 void 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).
89 void 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).
95 void 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).
101 void SCIPMessageHandlerWarning(SCIP_MESSAGEHDLR* const handler, FILE*,
102  const char* const message) {
103  SCIPMessageHandlerPrinter(GScipMessageType::kWarningMessage, handler,
104  message);
105 }
106 
107 // Release the input message handler.
108 //
109 // This function is a wrapper around SCIPmessagehdlrRelease which, in addition
110 // to releasing the handler, also resets the pointer to it, thus has a pointer
111 // on pointer argument. We can't use that as a deleter for a unique_ptr as in
112 // MessageHandlerPtr since we need a function that a pointer argument.
113 void ReleaseSCIPMessageHandler(SCIP_MESSAGEHDLR* handler) {
114  if (handler != nullptr) {
115  CHECK_EQ(SCIPmessagehdlrRelease(&handler), SCIP_OKAY);
116  }
117 }
118 
119 } // namespace
120 
121 MessageHandlerPtr CaptureMessageHandlerPtr(SCIP_MESSAGEHDLR* const handler) {
122  if (handler != nullptr) {
123  SCIPmessagehdlrCapture(handler);
124  }
125  return {handler, ReleaseSCIPMessageHandler};
126 }
127 
128 absl::StatusOr<MessageHandlerPtr> MakeSCIPMessageHandler(
129  const GScipMessageHandler gscip_message_handler) {
130  // We use a unique_ptr here to make sure we delete the data if
131  // SCIPmessagehdlrCreate() fails.
132  auto data = std::make_unique<SCIP_MessagehdlrData>(gscip_message_handler);
133  SCIP_MESSAGEHDLR* message_handler = nullptr;
135  SCIPmessagehdlrCreate(&message_handler,
136  /*bufferedoutput=*/true,
137  /*filename=*/nullptr,
138  /*quiet=*/false,
139  /*messagewarning=*/SCIPMessageHandlerWarning,
140  /*messagedialog=*/SCIPMessageHandlerDialog,
141  /*messageinfo=*/SCIPMessageHandlerInfo,
142  /*messagehdlrfree=*/SCIPMessageHandlerFree,
143  /*messagehdlrdata=*/data.get()));
144 
145  // SCIPmessagehdlrCreate() succeeded, we disable the deletion of the data by
146  // the unique_ptr since the ownership has been transferred to SCIP.
147  data.release();
148 
149  return MessageHandlerPtr{message_handler, ReleaseSCIPMessageHandler};
150 }
151 
153  const MessageHandlerPtr& handler)
154  : handler_(handler) {}
155 
157  if (handler_ != nullptr) {
158  // Note that SCIPmessagehdlrGetData is a macro in optimized builds and a
159  // function in debug ones. Hence here we assign the result to a variable
160  // instead of chaining the calls.
161  SCIP_MessagehdlrData* const data = SCIPmessagehdlrGetData(handler_.get());
162  data->disabled = true;
163  }
164 }
165 
166 } // namespace internal
167 } // namespace operations_research
#define CHECK(condition)
Definition: base/logging.h:498
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:705
#define LOG(severity)
Definition: base/logging.h:423
#define ABSL_DIE_IF_NULL
Definition: base/logging.h:41
Handler handler_
Definition: interval.cc:429
const int ERROR
Definition: log_severity.h:32
absl::StatusOr< MessageHandlerPtr > MakeSCIPMessageHandler(const GScipMessageHandler gscip_message_handler)
MessageHandlerPtr CaptureMessageHandlerPtr(SCIP_MESSAGEHDLR *const handler)
std::unique_ptr< SCIP_MESSAGEHDLR, void(*)(SCIP_MESSAGEHDLR *)> MessageHandlerPtr
Collection of objects used to extend the Constraint Solver library.
std::function< void(GScipMessageType type, absl::string_view message)> GScipMessageHandler
#define RETURN_IF_SCIP_ERROR(x)
std::atomic< bool > disabled
SCIP_MessagehdlrData(const operations_research::GScipMessageHandler gscip_message_handler)
const operations_research::GScipMessageHandler gscip_message_handler
std::string message
Definition: trace.cc:398