system/FileDescriptor: new wrapper class for a file descriptor
This commit is contained in:
parent
818d729d8b
commit
40a587bbaf
@ -57,9 +57,9 @@ src_mpd_LDADD = \
|
||||
libevent.a \
|
||||
libthread.a \
|
||||
libnet.a \
|
||||
$(FS_LIBS) \
|
||||
libsystem.a \
|
||||
libutil.a \
|
||||
$(FS_LIBS) \
|
||||
$(ICU_LDADD) \
|
||||
$(SYSTEMD_DAEMON_LIBS) \
|
||||
$(GLIB_LIBS)
|
||||
@ -431,6 +431,7 @@ libnet_a_SOURCES = \
|
||||
libsystem_a_SOURCES = \
|
||||
src/system/ByteOrder.hxx \
|
||||
src/system/FatalError.cxx src/system/FatalError.hxx \
|
||||
src/system/FileDescriptor.cxx src/system/FileDescriptor.hxx \
|
||||
src/system/fd_util.c src/system/fd_util.h \
|
||||
src/system/EventPipe.cxx src/system/EventPipe.hxx \
|
||||
src/system/EventFD.cxx src/system/EventFD.hxx \
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "InotifySource.hxx"
|
||||
#include "InotifyDomain.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "system/fd_util.h"
|
||||
#include "system/FileDescriptor.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
@ -72,8 +72,8 @@ InotifySource::OnSocketReady(gcc_unused unsigned flags)
|
||||
inline
|
||||
InotifySource::InotifySource(EventLoop &_loop,
|
||||
mpd_inotify_callback_t _callback, void *_ctx,
|
||||
int _fd)
|
||||
:SocketMonitor(_fd, _loop),
|
||||
FileDescriptor _fd)
|
||||
:SocketMonitor(_fd.Get(), _loop),
|
||||
callback(_callback), callback_ctx(_ctx)
|
||||
{
|
||||
ScheduleRead();
|
||||
@ -85,8 +85,8 @@ InotifySource::Create(EventLoop &loop,
|
||||
mpd_inotify_callback_t callback, void *callback_ctx,
|
||||
Error &error)
|
||||
{
|
||||
int fd = inotify_init_cloexec();
|
||||
if (fd < 0) {
|
||||
FileDescriptor fd;
|
||||
if (!fd.CreateInotify()) {
|
||||
error.SetErrno("inotify_init() has failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "Compiler.h"
|
||||
|
||||
class Error;
|
||||
class FileDescriptor;
|
||||
|
||||
typedef void (*mpd_inotify_callback_t)(int wd, unsigned mask,
|
||||
const char *name, void *ctx);
|
||||
@ -33,7 +34,8 @@ class InotifySource final : private SocketMonitor {
|
||||
void *callback_ctx;
|
||||
|
||||
InotifySource(EventLoop &_loop,
|
||||
mpd_inotify_callback_t callback, void *ctx, int fd);
|
||||
mpd_inotify_callback_t callback, void *ctx,
|
||||
FileDescriptor fd);
|
||||
|
||||
public:
|
||||
~InotifySource() {
|
||||
|
@ -75,17 +75,11 @@ FileReader::Close()
|
||||
|
||||
#else
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
FileReader::FileReader(Path _path, Error &error)
|
||||
:path(_path),
|
||||
fd(OpenFile(path,
|
||||
O_RDONLY,
|
||||
0))
|
||||
:path(_path)
|
||||
{
|
||||
if (fd < 0)
|
||||
fd.OpenReadOnly(path.c_str());
|
||||
if (!fd.IsDefined())
|
||||
error.FormatErrno("Failed to open %s", path.c_str());
|
||||
}
|
||||
|
||||
@ -94,7 +88,7 @@ FileReader::Read(void *data, size_t size, Error &error)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
ssize_t nbytes = read(fd, data, size);
|
||||
ssize_t nbytes = fd.Read(data, size);
|
||||
if (nbytes < 0) {
|
||||
error.FormatErrno("Failed to read from %s", path.c_str());
|
||||
nbytes = 0;
|
||||
@ -108,7 +102,7 @@ FileReader::Seek(off_t offset, Error &error)
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
auto result = lseek(fd, offset, SEEK_SET);
|
||||
auto result = fd.Seek(offset);
|
||||
const bool success = result >= 0;
|
||||
if (!success)
|
||||
error.SetErrno("Failed to seek");
|
||||
@ -121,8 +115,7 @@ FileReader::Close()
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
close(fd);
|
||||
fd = -1;
|
||||
fd.Close();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -25,6 +25,10 @@
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#ifndef WIN32
|
||||
#include "system/FileDescriptor.hxx"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef WIN32
|
||||
@ -39,7 +43,7 @@ class FileReader final : public Reader {
|
||||
#ifdef WIN32
|
||||
HANDLE handle;
|
||||
#else
|
||||
int fd;
|
||||
FileDescriptor fd;
|
||||
#endif
|
||||
|
||||
public:
|
||||
@ -55,7 +59,7 @@ public:
|
||||
#ifdef WIN32
|
||||
return handle != INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
return fd >= 0;
|
||||
return fd.IsDefined();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -23,10 +23,8 @@
|
||||
#include "../InputPlugin.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "fs/Path.hxx"
|
||||
#include "system/fd_util.h"
|
||||
#include "open.h"
|
||||
#include "system/FileDescriptor.hxx"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
@ -35,10 +33,10 @@
|
||||
static constexpr Domain file_domain("file");
|
||||
|
||||
class FileInputStream final : public InputStream {
|
||||
const int fd;
|
||||
FileDescriptor fd;
|
||||
|
||||
public:
|
||||
FileInputStream(const char *path, int _fd, off_t _size,
|
||||
FileInputStream(const char *path, FileDescriptor _fd, off_t _size,
|
||||
Mutex &_mutex, Cond &_cond)
|
||||
:InputStream(path, _mutex, _cond),
|
||||
fd(_fd) {
|
||||
@ -48,7 +46,7 @@ public:
|
||||
}
|
||||
|
||||
~FileInputStream() {
|
||||
close(fd);
|
||||
fd.Close();
|
||||
}
|
||||
|
||||
/* virtual methods from InputStream */
|
||||
@ -66,29 +64,29 @@ OpenFileInputStream(Path path,
|
||||
Mutex &mutex, Cond &cond,
|
||||
Error &error)
|
||||
{
|
||||
const int fd = OpenFile(path, O_RDONLY|O_BINARY, 0);
|
||||
if (fd < 0) {
|
||||
FileDescriptor fd;
|
||||
if (!fd.OpenReadOnly(path.c_str())) {
|
||||
error.FormatErrno("Failed to open \"%s\"",
|
||||
path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) < 0) {
|
||||
if (fstat(fd.Get(), &st) < 0) {
|
||||
error.FormatErrno("Failed to stat \"%s\"", path.c_str());
|
||||
close(fd);
|
||||
fd.Close();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!S_ISREG(st.st_mode)) {
|
||||
error.Format(file_domain, "Not a regular file: %s",
|
||||
path.c_str());
|
||||
close(fd);
|
||||
fd.Close();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef POSIX_FADV_SEQUENTIAL
|
||||
posix_fadvise(fd, (off_t)0, st.st_size, POSIX_FADV_SEQUENTIAL);
|
||||
posix_fadvise(fd.Get(), (off_t)0, st.st_size, POSIX_FADV_SEQUENTIAL);
|
||||
#endif
|
||||
|
||||
return new FileInputStream(path.c_str(), fd, st.st_size, mutex, cond);
|
||||
@ -107,7 +105,7 @@ input_file_open(gcc_unused const char *filename,
|
||||
bool
|
||||
FileInputStream::Seek(offset_type new_offset, Error &error)
|
||||
{
|
||||
auto result = lseek(fd, (off_t)new_offset, SEEK_SET);
|
||||
auto result = fd.Seek((off_t)new_offset);
|
||||
if (result < 0) {
|
||||
error.SetErrno("Failed to seek");
|
||||
return false;
|
||||
@ -120,7 +118,7 @@ FileInputStream::Seek(offset_type new_offset, Error &error)
|
||||
size_t
|
||||
FileInputStream::Read(void *ptr, size_t read_size, Error &error)
|
||||
{
|
||||
ssize_t nbytes = read(fd, ptr, read_size);
|
||||
ssize_t nbytes = fd.Read(ptr, read_size);
|
||||
if (nbytes < 0) {
|
||||
error.SetErrno("Failed to read");
|
||||
return 0;
|
||||
|
@ -20,46 +20,35 @@
|
||||
#include "config.h"
|
||||
#ifdef USE_EVENTFD
|
||||
#include "EventFD.hxx"
|
||||
#include "system/fd_util.h"
|
||||
#include "system/FatalError.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/eventfd.h>
|
||||
|
||||
EventFD::EventFD()
|
||||
:fd(eventfd_cloexec_nonblock(0, 0))
|
||||
{
|
||||
if (fd < 0)
|
||||
if (!fd.CreateEventFD(0))
|
||||
FatalSystemError("eventfd() failed");
|
||||
}
|
||||
|
||||
EventFD::~EventFD()
|
||||
{
|
||||
assert(fd >= 0);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
bool
|
||||
EventFD::Read()
|
||||
{
|
||||
assert(fd >= 0);
|
||||
assert(fd.IsDefined());
|
||||
|
||||
eventfd_t value;
|
||||
return read(fd, &value, sizeof(value)) == (ssize_t)sizeof(value);
|
||||
return fd.Read(&value, sizeof(value)) == (ssize_t)sizeof(value);
|
||||
}
|
||||
|
||||
void
|
||||
EventFD::Write()
|
||||
{
|
||||
assert(fd >= 0);
|
||||
assert(fd.IsDefined());
|
||||
|
||||
static constexpr eventfd_t value = 1;
|
||||
gcc_unused ssize_t nbytes =
|
||||
write(fd, &value, sizeof(value));
|
||||
fd.Write(&value, sizeof(value));
|
||||
}
|
||||
|
||||
#endif /* USE_EVENTFD */
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define MPD_EVENT_FD_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "FileDescriptor.hxx"
|
||||
|
||||
/**
|
||||
* A class that wraps eventfd().
|
||||
@ -28,17 +29,19 @@
|
||||
* Errors in the constructor are fatal.
|
||||
*/
|
||||
class EventFD {
|
||||
int fd;
|
||||
FileDescriptor fd;
|
||||
|
||||
public:
|
||||
EventFD();
|
||||
~EventFD();
|
||||
~EventFD() {
|
||||
fd.Close();
|
||||
}
|
||||
|
||||
EventFD(const EventFD &other) = delete;
|
||||
EventFD &operator=(const EventFD &other) = delete;
|
||||
|
||||
int Get() const {
|
||||
return fd;
|
||||
return fd.Get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
219
src/system/FileDescriptor.cxx
Normal file
219
src/system/FileDescriptor.cxx
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2015 Max Kellermann <max@duempel.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "FileDescriptor.hxx"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_POSIX
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENTFD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_SIGNALFD
|
||||
#include <sys/signalfd.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INOTIFY_INIT
|
||||
#include <sys/inotify.h>
|
||||
#endif
|
||||
|
||||
#ifndef O_NOCTTY
|
||||
#define O_NOCTTY 0
|
||||
#endif
|
||||
|
||||
#ifndef O_CLOEXEC
|
||||
#define O_CLOEXEC 0
|
||||
#endif
|
||||
|
||||
bool
|
||||
FileDescriptor::Open(const char *pathname, int flags)
|
||||
{
|
||||
assert(!IsDefined());
|
||||
|
||||
fd = ::open(pathname, flags);
|
||||
return IsDefined();
|
||||
}
|
||||
|
||||
bool
|
||||
FileDescriptor::OpenReadOnly(const char *pathname)
|
||||
{
|
||||
return Open(pathname, O_RDONLY | O_NOCTTY | O_CLOEXEC);
|
||||
}
|
||||
|
||||
#ifdef HAVE_POSIX
|
||||
|
||||
bool
|
||||
FileDescriptor::OpenNonBlocking(const char *pathname)
|
||||
{
|
||||
return Open(pathname, O_RDWR | O_NOCTTY | O_CLOEXEC | O_NONBLOCK);
|
||||
}
|
||||
|
||||
bool
|
||||
FileDescriptor::CreatePipe(FileDescriptor &r, FileDescriptor &w)
|
||||
{
|
||||
int fds[2];
|
||||
|
||||
#ifdef HAVE_PIPE2
|
||||
const int flags = O_CLOEXEC;
|
||||
const int result = pipe2(fds, flags);
|
||||
#else
|
||||
const int result = pipe(fds);
|
||||
#endif
|
||||
|
||||
if (result < 0)
|
||||
return false;
|
||||
|
||||
r = FileDescriptor(fds[0]);
|
||||
w = FileDescriptor(fds[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FileDescriptor::SetNonBlocking()
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
||||
}
|
||||
|
||||
void
|
||||
FileDescriptor::SetBlocking()
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENTFD
|
||||
|
||||
bool
|
||||
FileDescriptor::CreateEventFD(unsigned initval)
|
||||
{
|
||||
assert(!IsDefined());
|
||||
|
||||
fd = ::eventfd(initval, EFD_NONBLOCK|EFD_CLOEXEC);
|
||||
return fd >= 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_SIGNALFD
|
||||
|
||||
bool
|
||||
FileDescriptor::CreateSignalFD(const sigset_t *mask)
|
||||
{
|
||||
int new_fd = ::signalfd(fd, mask, SFD_NONBLOCK|SFD_CLOEXEC);
|
||||
if (new_fd < 0)
|
||||
return false;
|
||||
|
||||
fd = new_fd;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INOTIFY_INIT
|
||||
|
||||
bool
|
||||
FileDescriptor::CreateInotify()
|
||||
{
|
||||
#ifdef HAVE_INOTIFY_INIT1
|
||||
int new_fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
|
||||
#else
|
||||
int new_fd = inotify_init();
|
||||
#endif
|
||||
if (new_fd < 0)
|
||||
return false;
|
||||
|
||||
#ifndef HAVE_INOTIFY_INIT1
|
||||
SetNonBlocking();
|
||||
#endif
|
||||
|
||||
fd = new_fd;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool
|
||||
FileDescriptor::Rewind()
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
return lseek(fd, 0, SEEK_SET) == 0;
|
||||
}
|
||||
|
||||
off_t
|
||||
FileDescriptor::GetSize() const
|
||||
{
|
||||
struct stat st;
|
||||
return ::fstat(fd, &st) >= 0
|
||||
? (long)st.st_size
|
||||
: -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_POSIX
|
||||
|
||||
int
|
||||
FileDescriptor::Poll(short events, int timeout) const
|
||||
{
|
||||
assert(IsDefined());
|
||||
|
||||
struct pollfd pfd;
|
||||
pfd.fd = fd;
|
||||
pfd.events = events;
|
||||
int result = poll(&pfd, 1, timeout);
|
||||
return result > 0
|
||||
? pfd.revents
|
||||
: result;
|
||||
}
|
||||
|
||||
int
|
||||
FileDescriptor::WaitReadable(int timeout) const
|
||||
{
|
||||
return Poll(POLLIN, timeout);
|
||||
}
|
||||
|
||||
int
|
||||
FileDescriptor::WaitWritable(int timeout) const
|
||||
{
|
||||
return Poll(POLLOUT, timeout);
|
||||
}
|
||||
|
||||
#endif
|
171
src/system/FileDescriptor.hxx
Normal file
171
src/system/FileDescriptor.hxx
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2015 Max Kellermann <max@duempel.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef FILE_DESCRIPTOR_HXX
|
||||
#define FILE_DESCRIPTOR_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef USE_SIGNALFD
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* An OO wrapper for a UNIX file descriptor.
|
||||
*
|
||||
* This class is unmanaged and trivial.
|
||||
*/
|
||||
class FileDescriptor {
|
||||
protected:
|
||||
int fd;
|
||||
|
||||
public:
|
||||
FileDescriptor() = default;
|
||||
explicit constexpr FileDescriptor(int _fd):fd(_fd) {}
|
||||
|
||||
constexpr bool operator==(FileDescriptor other) const {
|
||||
return fd == other.fd;
|
||||
}
|
||||
|
||||
constexpr bool IsDefined() const {
|
||||
return fd >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file descriptor. This may only be called if
|
||||
* IsDefined() returns true.
|
||||
*/
|
||||
constexpr int Get() const {
|
||||
return fd;
|
||||
}
|
||||
|
||||
void Set(int _fd) {
|
||||
fd = _fd;
|
||||
}
|
||||
|
||||
int Steal() {
|
||||
assert(IsDefined());
|
||||
|
||||
int _fd = fd;
|
||||
fd = -1;
|
||||
return _fd;
|
||||
}
|
||||
|
||||
void SetUndefined() {
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
static constexpr FileDescriptor Undefined() {
|
||||
return FileDescriptor(-1);
|
||||
}
|
||||
|
||||
bool Open(const char *pathname, int flags);
|
||||
bool OpenReadOnly(const char *pathname);
|
||||
|
||||
#ifdef HAVE_POSIX
|
||||
bool OpenNonBlocking(const char *pathname);
|
||||
|
||||
static bool CreatePipe(FileDescriptor &r, FileDescriptor &w);
|
||||
|
||||
/**
|
||||
* Enable non-blocking mode on this file descriptor.
|
||||
*/
|
||||
void SetNonBlocking();
|
||||
|
||||
/**
|
||||
* Enable blocking mode on this file descriptor.
|
||||
*/
|
||||
void SetBlocking();
|
||||
|
||||
/**
|
||||
* Duplicate the file descriptor onto the given file descriptor.
|
||||
*/
|
||||
bool Duplicate(int new_fd) const {
|
||||
return ::dup2(Get(), new_fd) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENTFD
|
||||
bool CreateEventFD(unsigned initval=0);
|
||||
#endif
|
||||
|
||||
#ifdef USE_SIGNALFD
|
||||
bool CreateSignalFD(const sigset_t *mask);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INOTIFY_INIT
|
||||
bool CreateInotify();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Close the file descriptor. It is legal to call it on an
|
||||
* "undefined" object. After this call, IsDefined() is guaranteed
|
||||
* to return false, and this object may be reused.
|
||||
*/
|
||||
void Close() {
|
||||
::close(Steal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Rewind the pointer to the beginning of the file.
|
||||
*/
|
||||
bool Rewind();
|
||||
|
||||
off_t Seek(off_t offset) {
|
||||
return lseek(Get(), offset, SEEK_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the file in bytes, or -1 on error.
|
||||
*/
|
||||
gcc_pure
|
||||
off_t GetSize() const;
|
||||
|
||||
ssize_t Read(void *buffer, size_t length) {
|
||||
return ::read(fd, buffer, length);
|
||||
}
|
||||
|
||||
ssize_t Write(const void *buffer, size_t length) {
|
||||
return ::write(fd, buffer, length);
|
||||
}
|
||||
|
||||
#ifdef HAVE_POSIX
|
||||
int Poll(short events, int timeout) const;
|
||||
|
||||
int WaitReadable(int timeout) const;
|
||||
int WaitWritable(int timeout) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
@ -23,33 +23,29 @@
|
||||
#include "FatalError.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/signalfd.h>
|
||||
|
||||
void
|
||||
SignalFD::Create(const sigset_t &mask)
|
||||
{
|
||||
fd = ::signalfd(fd, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
|
||||
if (fd < 0)
|
||||
if (!fd.CreateSignalFD(&mask))
|
||||
FatalSystemError("signalfd() failed");
|
||||
}
|
||||
|
||||
void
|
||||
SignalFD::Close()
|
||||
{
|
||||
if (fd >= 0) {
|
||||
::close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
if (fd.IsDefined())
|
||||
fd.Close();
|
||||
}
|
||||
|
||||
int
|
||||
SignalFD::Read()
|
||||
{
|
||||
assert(fd >= 0);
|
||||
assert(fd.IsDefined());
|
||||
|
||||
signalfd_siginfo info;
|
||||
return read(fd, &info, sizeof(info)) > 0
|
||||
return fd.Read(&info, sizeof(info)) > 0
|
||||
? info.ssi_signo
|
||||
: -1;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define MPD_SIGNAL_FD_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "FileDescriptor.hxx"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
@ -28,7 +29,7 @@
|
||||
* A class that wraps signalfd().
|
||||
*/
|
||||
class SignalFD {
|
||||
int fd;
|
||||
FileDescriptor fd;
|
||||
|
||||
public:
|
||||
SignalFD():fd(-1) {}
|
||||
@ -48,7 +49,7 @@ public:
|
||||
void Close();
|
||||
|
||||
int Get() const {
|
||||
return fd;
|
||||
return fd.Get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,10 +41,6 @@
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_INOTIFY_INIT
|
||||
#include <sys/inotify.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENTFD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
@ -200,38 +196,6 @@ accept_cloexec_nonblock(int fd, struct sockaddr *address,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_INOTIFY_INIT
|
||||
|
||||
int
|
||||
inotify_init_cloexec(void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
#ifdef HAVE_INOTIFY_INIT1
|
||||
fd = inotify_init1(IN_CLOEXEC);
|
||||
if (fd >= 0 || errno != ENOSYS)
|
||||
return fd;
|
||||
#endif
|
||||
|
||||
fd = inotify_init();
|
||||
if (fd >= 0)
|
||||
fd_set_cloexec(fd, true);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENTFD
|
||||
|
||||
int
|
||||
eventfd_cloexec_nonblock(unsigned initval, int flags)
|
||||
{
|
||||
return eventfd(initval, flags | EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
close_socket(int fd)
|
||||
{
|
||||
|
@ -91,28 +91,6 @@ int
|
||||
accept_cloexec_nonblock(int fd, struct sockaddr *address,
|
||||
size_t *address_length_r);
|
||||
|
||||
#ifdef HAVE_INOTIFY_INIT
|
||||
|
||||
/**
|
||||
* Wrapper for inotify_init(), which sets the CLOEXEC flag (atomically
|
||||
* if supported by the OS).
|
||||
*/
|
||||
int
|
||||
inotify_init_cloexec(void);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENTFD
|
||||
|
||||
/**
|
||||
* Wrapper for eventfd() which sets the flags CLOEXEC and NONBLOCK
|
||||
* flag (atomically if supported by the OS).
|
||||
*/
|
||||
int
|
||||
eventfd_cloexec_nonblock(unsigned initval, int flags);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Portable wrapper for close(); use closesocket() on WIN32/WinSock.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user