Generated on for Gecode by doxygen 1.15.0
blackbox-dll.cpp
Go to the documentation of this file.
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Contributing authors:
4 * Mikael Zayenz Lagerkvist <lagerkvist@gecode.dev>
5 *
6 * Copyright:
7 * Jip J. Dekker, 2026
8 *
9 * This file is part of Gecode, the generic constraint
10 * development environment:
11 * http://www.gecode.dev
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining
14 * a copy of this software and associated documentation files (the
15 * "Software"), to deal in the Software without restriction, including
16 * without limitation the rights to use, copy, modify, merge, publish,
17 * distribute, sublicense, and/or sell copies of the Software, and to
18 * permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be
22 * included in all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 *
32 */
33
34#include <atomic>
35#include <cstddef>
36#include <cstdint>
37#include <cstring>
38#include <fstream>
39#include <set>
40#include <string>
41
42#ifdef _WIN32
43#include <windows.h>
44#define GECODE_BLACKBOX_EXPORT __declspec(dllexport)
45#define GECODE_BLACKBOX_CALL __stdcall
46#else
47#include <cerrno>
48#include <fcntl.h>
49#include <unistd.h>
50#if defined(__GNUC__) || defined(__clang__)
51#define GECODE_BLACKBOX_EXPORT __attribute__((visibility("default")))
52#else
53#define GECODE_BLACKBOX_EXPORT
54#endif
55#define GECODE_BLACKBOX_CALL
56#endif
57
58namespace {
59
60 enum class Mode { normal, nan };
61
62 struct Instance {
63 const Mode mode;
64 const std::string log;
65 const unsigned int id;
66
67 Instance(const char** args, size_t n_args, unsigned int id0)
68 : mode((n_args > 0) && (std::strcmp(args[0], "nan") == 0)
69 ? Mode::nan : Mode::normal),
70 log((n_args > 1) ? args[1] : ""), id(id0) {}
71 Instance(const Instance& other, unsigned int id0)
72 : mode(other.mode), log(other.log), id(id0) {}
73 };
74
75 std::atomic<unsigned int> next_id(0);
76
77 unsigned int
78 instance_id(void) {
79 return next_id.fetch_add(1, std::memory_order_relaxed) + 1;
80 }
81
82 void
83 record(const std::string& log, const std::string& event, unsigned int id) {
84 if (log.empty()) {
85 return;
86 }
87 const std::string line = event + " " + std::to_string(id) + "\n";
88#ifdef _WIN32
89 HANDLE file = CreateFileA(log.c_str(), FILE_APPEND_DATA,
90 FILE_SHARE_READ | FILE_SHARE_WRITE |
91 FILE_SHARE_DELETE,
92 nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
93 nullptr);
94 if (file == INVALID_HANDLE_VALUE) {
95 return;
96 }
97 DWORD written;
98 (void)WriteFile(file, line.data(), static_cast<DWORD>(line.size()),
99 &written, nullptr);
100 (void)CloseHandle(file);
101#else
102 int fd;
103 do {
104 fd = open(log.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0600);
105 } while ((fd == -1) && (errno == EINTR));
106 if (fd == -1) {
107 return;
108 }
109 ssize_t n;
110 do {
111 n = write(fd, line.data(), line.size());
112 } while ((n == -1) && (errno == EINTR));
113 (void)close(fd);
114#endif
115 }
116
117 bool
118 has_two_starts(const std::string& log) {
119 std::ifstream in(log.c_str());
120 std::set<unsigned int> ids;
121 std::string event;
122 unsigned int id;
123 while (in >> event >> id) {
124 if (event == "start") {
125 ids.insert(id);
126 }
127 }
128 return ids.size() >= 2;
129 }
130
131 void
132 wait_for_peer(const std::string& log, unsigned int id) {
133 for (unsigned int i = 0; i < 500; ++i) {
134 if (has_two_starts(log)) {
135 return;
136 }
137#ifdef _WIN32
138 Sleep(10);
139#else
140 usleep(10000);
141#endif
142 }
143 record(log, "timeout", id);
144 }
145
146}
147
149fzn_init(const char** args, size_t n_args) {
150 Instance* instance = new Instance(args, n_args, instance_id());
151 record(instance->log, "init", instance->id);
152 return instance;
153}
154
156fzn_clone(void* value) {
157 Instance* instance = new Instance(*static_cast<Instance*>(value),
158 instance_id());
159 record(instance->log, "clone", instance->id);
160 return instance;
161}
162
164fzn_free(void* value) {
165 Instance* instance = static_cast<Instance*>(value);
166 record(instance->log, "free", instance->id);
167 delete instance;
168}
169
171fzn_blackbox(void* value, const int64_t* int_input, size_t n_int_input,
172 const double* float_input, size_t n_float_input,
173 int64_t* int_output, size_t n_int_output,
174 double* float_output, size_t n_float_output) {
175 const Instance* instance = static_cast<const Instance*>(value);
176 if (!instance->log.empty() && (n_int_input > 0)) {
177 record(instance->log, "start", instance->id);
178 wait_for_peer(instance->log, instance->id);
179 record(instance->log, "ready", instance->id);
180 }
181 for (size_t i = 0; i < n_int_output; ++i) {
182 int_output[i] = (n_int_input == 0)
183 ? 1
184 : int_input[i % n_int_input];
185 }
186 for (size_t i = 0; i < n_float_output; ++i) {
187 if (instance->mode == Mode::nan) {
188 const uint64_t nan = UINT64_C(0x7ff8000000000000);
189 std::memcpy(&float_output[i], &nan, sizeof(nan));
190 } else {
191 float_output[i] = (n_float_input == 0)
192 ? 0.0 : float_input[i % n_float_input];
193 }
194 }
195}
196
197// STATISTICS: test-flatzinc
#define GECODE_BLACKBOX_CALL
GECODE_BLACKBOX_EXPORT void GECODE_BLACKBOX_CALL fzn_free(void *value)
GECODE_BLACKBOX_EXPORT void *GECODE_BLACKBOX_CALL fzn_init(const char **args, size_t n_args)
GECODE_BLACKBOX_EXPORT void *GECODE_BLACKBOX_CALL fzn_clone(void *value)
#define GECODE_BLACKBOX_EXPORT
GECODE_BLACKBOX_EXPORT void GECODE_BLACKBOX_CALL fzn_blackbox(void *value, const int64_t *int_input, size_t n_int_input, const double *float_input, size_t n_float_input, int64_t *int_output, size_t n_int_output, double *float_output, size_t n_float_output)