IXWebSocket/ixwebsocket/IXSelectInterruptPipe.cpp

151 lines
4.1 KiB
C++
Raw Permalink Normal View History

2019-03-15 02:37:38 +01:00
/*
2019-03-15 02:54:47 +01:00
* IXSelectInterruptPipe.cpp
2019-03-15 02:37:38 +01:00
* Author: Benjamin Sergeant
* Copyright (c) 2018-2019 Machine Zone, Inc. All rights reserved.
*/
//
// On UNIX we use pipes to wake up select. There is no way to do that
// on Windows so this file is compiled out on Windows.
2019-03-15 02:37:38 +01:00
//
#ifndef _WIN32
2019-03-15 02:37:38 +01:00
#include "IXSelectInterruptPipe.h"
2019-03-15 19:43:27 +01:00
#include <assert.h>
2019-09-23 19:25:23 +02:00
#include <errno.h>
#include <fcntl.h>
2019-03-15 02:37:38 +01:00
#include <sstream>
2019-09-23 19:25:23 +02:00
#include <string.h> // for strerror
#include <unistd.h> // for write
2019-03-15 02:37:38 +01:00
namespace ix
{
// File descriptor at index 0 in _fildes is the read end of the pipe
// File descriptor at index 1 in _fildes is the write end of the pipe
const int SelectInterruptPipe::kPipeReadIndex = 0;
const int SelectInterruptPipe::kPipeWriteIndex = 1;
SelectInterruptPipe::SelectInterruptPipe()
{
2019-03-15 19:41:57 +01:00
_fildes[kPipeReadIndex] = -1;
_fildes[kPipeWriteIndex] = -1;
2019-03-15 02:37:38 +01:00
}
SelectInterruptPipe::~SelectInterruptPipe()
{
::close(_fildes[kPipeReadIndex]);
::close(_fildes[kPipeWriteIndex]);
_fildes[kPipeReadIndex] = -1;
_fildes[kPipeWriteIndex] = -1;
}
bool SelectInterruptPipe::init(std::string& errorMsg)
{
std::lock_guard<std::mutex> lock(_fildesMutex);
2019-03-15 19:41:57 +01:00
// calling init twice is a programming error
assert(_fildes[kPipeReadIndex] == -1);
assert(_fildes[kPipeWriteIndex] == -1);
2019-03-15 02:37:38 +01:00
if (pipe(_fildes) < 0)
{
std::stringstream ss;
ss << "SelectInterruptPipe::init() failed in pipe() call"
<< " : " << strerror(errno);
errorMsg = ss.str();
return false;
}
if (fcntl(_fildes[kPipeReadIndex], F_SETFL, O_NONBLOCK) == -1)
{
std::stringstream ss;
ss << "SelectInterruptPipe::init() failed in fcntl(..., O_NONBLOCK) call"
2019-03-15 02:37:38 +01:00
<< " : " << strerror(errno);
errorMsg = ss.str();
_fildes[kPipeReadIndex] = -1;
_fildes[kPipeWriteIndex] = -1;
return false;
}
if (fcntl(_fildes[kPipeWriteIndex], F_SETFL, O_NONBLOCK) == -1)
{
std::stringstream ss;
ss << "SelectInterruptPipe::init() failed in fcntl(..., O_NONBLOCK) call"
2019-03-15 02:37:38 +01:00
<< " : " << strerror(errno);
errorMsg = ss.str();
_fildes[kPipeReadIndex] = -1;
_fildes[kPipeWriteIndex] = -1;
return false;
}
#ifdef F_SETNOSIGPIPE
if (fcntl(_fildes[kPipeWriteIndex], F_SETNOSIGPIPE, 1) == -1)
{
std::stringstream ss;
ss << "SelectInterruptPipe::init() failed in fcntl(.... F_SETNOSIGPIPE) call"
<< " : " << strerror(errno);
errorMsg = ss.str();
_fildes[kPipeReadIndex] = -1;
_fildes[kPipeWriteIndex] = -1;
return false;
}
if (fcntl(_fildes[kPipeWriteIndex], F_SETNOSIGPIPE, 1) == -1)
{
std::stringstream ss;
ss << "SelectInterruptPipe::init() failed in fcntl(..., F_SETNOSIGPIPE) call"
<< " : " << strerror(errno);
errorMsg = ss.str();
_fildes[kPipeReadIndex] = -1;
_fildes[kPipeWriteIndex] = -1;
return false;
}
#endif
2019-03-15 02:37:38 +01:00
return true;
}
bool SelectInterruptPipe::notify(uint64_t value)
{
std::lock_guard<std::mutex> lock(_fildesMutex);
2019-03-15 02:37:38 +01:00
int fd = _fildes[kPipeWriteIndex];
if (fd == -1) return false;
// we should write 8 bytes for an uint64_t
return write(fd, &value, sizeof(value)) == 8;
}
// TODO: return max uint64_t for errors ?
uint64_t SelectInterruptPipe::read()
{
std::lock_guard<std::mutex> lock(_fildesMutex);
2019-03-15 02:37:38 +01:00
int fd = _fildes[kPipeReadIndex];
uint64_t value = 0;
::read(fd, &value, sizeof(value));
2019-03-19 06:00:08 +01:00
2019-03-15 02:37:38 +01:00
return value;
}
bool SelectInterruptPipe::clear()
{
return true;
}
2019-03-15 19:41:57 +01:00
int SelectInterruptPipe::getFd() const
2019-03-15 02:37:38 +01:00
{
std::lock_guard<std::mutex> lock(_fildesMutex);
2019-03-15 02:37:38 +01:00
return _fildes[kPipeReadIndex];
}
2019-09-23 19:25:23 +02:00
} // namespace ix
#endif // !_WIN32