OR-Tools  9.1
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 } // namespace
108 
109 void ReleaseSCIPMessageHandler::operator()(SCIP_MESSAGEHDLR* handler) const {
110  if (handler != nullptr) {
111  CHECK_EQ(SCIPmessagehdlrRelease(&handler), SCIP_OKAY);
112  }
113 }
114 
115 MessageHandlerPtr CaptureMessageHandlerPtr(SCIP_MESSAGEHDLR* const handler) {
116  if (handler != nullptr) {
117  SCIPmessagehdlrCapture(handler);
118  }
119  return MessageHandlerPtr(handler);
120 }
121 
122 absl::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 
147  const MessageHandlerPtr& handler)
148  : handler_(handler) {}
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
#define CHECK(condition)
Definition: base/logging.h:491
MessageHandlerPtr CaptureMessageHandlerPtr(SCIP_MESSAGEHDLR *const handler)
const int ERROR
Definition: log_severity.h:32
SCIP_MessagehdlrData(const operations_research::GScipMessageHandler gscip_message_handler)
#define LOG(severity)
Definition: base/logging.h:416
absl::StatusOr< MessageHandlerPtr > MakeSCIPMessageHandler(const GScipMessageHandler gscip_message_handler)
Handler handler_
Definition: interval.cc:429
const operations_research::GScipMessageHandler gscip_message_handler
std::string message
Definition: trace.cc:398
#define CHECK_EQ(val1, val2)
Definition: base/logging.h:698
#define RETURN_IF_SCIP_ERROR(x)
std::unique_ptr< SCIP_MESSAGEHDLR, ReleaseSCIPMessageHandler > MessageHandlerPtr
std::atomic< bool > disabled
Collection of objects used to extend the Constraint Solver library.
#define ABSL_DIE_IF_NULL
Definition: base/logging.h:41
std::function< void(GScipMessageType type, absl::string_view message)> GScipMessageHandler