1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.
Jip J. Dekker fad1b07018 Squashed 'software/minizinc/' content from commit 4f10c8205
git-subtree-dir: software/minizinc
git-subtree-split: 4f10c82056ffcb1041d7ffef29d77a7eef92cf76
2021-06-16 14:06:46 +10:00

106 lines
2.7 KiB
C++

/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
* Main authors:
* Jason Nguyen <jason.nguyen@monash.edu>
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#pragma once
#ifdef _WIN32
#define NOMINMAX // Ensure the words min/max remain available
#include <Windows.h>
#undef ERROR
#include <sstream>
#include <thread>
namespace MiniZinc {
// Listens for a message on the named pipe \\.\pipe\minizinc-PID
// Triggers a Ctrl+C when an empty message is received.
class InterruptListener {
public:
static InterruptListener& run() {
static InterruptListener instance;
return instance;
}
InterruptListener(InterruptListener const&) = delete;
void operator=(InterruptListener const&) = delete;
~InterruptListener() {
SetConsoleCtrlHandler(CtrlHandler, FALSE);
SetEvent(hEvents[0]);
thread.join();
CloseHandle(hNamedPipe);
CloseHandle(hEvents[0]);
CloseHandle(hEvents[1]);
}
private:
std::thread thread;
HANDLE hNamedPipe;
InterruptListener() {
// Setup events
hEvents[0] = CreateEvent(NULL, FALSE, FALSE, NULL); // Signalled when thread needs to exit
hEvents[1] = CreateEvent(NULL, FALSE, FALSE, NULL); // Signalled on pipe events
// Setup a named pipe so that the IDE can trigger an interrupt
std::stringstream ss;
ss << "\\\\.\\pipe\\minizinc-" << GetCurrentProcessId();
std::string pipeName = ss.str();
hNamedPipe = CreateNamedPipe(pipeName.c_str(), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE, 1, 0, 0, 0, NULL);
if (hEvents[0] && hEvents[1] && hNamedPipe) {
SetConsoleCtrlHandler(CtrlHandler, TRUE);
thread = std::thread(&InterruptListener::listen, this);
}
}
void listen() {
OVERLAPPED ol;
// Connect pipe
ZeroMemory(&ol, sizeof(OVERLAPPED));
ol.hEvent = hEvents[1];
ConnectNamedPipe(hNamedPipe, &ol);
DWORD ev = WaitForMultipleObjects(2, &hEvents[0], FALSE, INFINITE);
if (ev - WAIT_OBJECT_0 == 0) {
return;
}
// Listen for pings on pipe
while (true) {
ZeroMemory(&ol, sizeof(OVERLAPPED));
ol.hEvent = hEvents[1];
ReadFile(hNamedPipe, NULL, 0, NULL, &ol);
DWORD ev = WaitForMultipleObjects(2, &hEvents[0], FALSE, INFINITE);
if (ev - WAIT_OBJECT_0 == 0) {
return;
}
GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0);
}
}
static HANDLE hEvents[2];
static BOOL WINAPI CtrlHandler(DWORD fdwCtrlType) {
// Tell thread to stop
SetEvent(hEvents[0]);
return FALSE;
}
};
HANDLE InterruptListener::hEvents[2];
} // namespace MiniZinc
#endif