aboutsummaryrefslogtreecommitdiffstats
path: root/src/system
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2015-03-03 17:03:21 +0100
committerMax Kellermann <max@duempel.org>2015-03-03 17:14:30 +0100
commit40a587bbaff38bb0b60313c24b94e2ecd53b181c (patch)
treed72c9db82e0db482ebe054119460b506433e9d05 /src/system
parent818d729d8b60a682e267ac408c710f5851389d79 (diff)
downloadmpd-40a587bbaff38bb0b60313c24b94e2ecd53b181c.tar.gz
mpd-40a587bbaff38bb0b60313c24b94e2ecd53b181c.tar.xz
mpd-40a587bbaff38bb0b60313c24b94e2ecd53b181c.zip
system/FileDescriptor: new wrapper class for a file descriptor
Diffstat (limited to '')
-rw-r--r--src/system/EventFD.cxx21
-rw-r--r--src/system/EventFD.hxx9
-rw-r--r--src/system/FileDescriptor.cxx219
-rw-r--r--src/system/FileDescriptor.hxx171
-rw-r--r--src/system/SignalFD.cxx14
-rw-r--r--src/system/SignalFD.hxx5
-rw-r--r--src/system/fd_util.c36
-rw-r--r--src/system/fd_util.h22
8 files changed, 409 insertions, 88 deletions
diff --git a/src/system/EventFD.cxx b/src/system/EventFD.cxx
index 2c1cef040..016dd372c 100644
--- a/src/system/EventFD.cxx
+++ b/src/system/EventFD.cxx
@@ -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 */
diff --git a/src/system/EventFD.hxx b/src/system/EventFD.hxx
index 654547078..616877f4a 100644
--- a/src/system/EventFD.hxx
+++ b/src/system/EventFD.hxx
@@ -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();
}
/**
diff --git a/src/system/FileDescriptor.cxx b/src/system/FileDescriptor.cxx
new file mode 100644
index 000000000..946493329
--- /dev/null
+++ b/src/system/FileDescriptor.cxx
@@ -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
diff --git a/src/system/FileDescriptor.hxx b/src/system/FileDescriptor.hxx
new file mode 100644
index 000000000..8db0dffdd
--- /dev/null
+++ b/src/system/FileDescriptor.hxx
@@ -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
diff --git a/src/system/SignalFD.cxx b/src/system/SignalFD.cxx
index 92d2eec01..14193c893 100644
--- a/src/system/SignalFD.cxx
+++ b/src/system/SignalFD.cxx
@@ -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;
}
diff --git a/src/system/SignalFD.hxx b/src/system/SignalFD.hxx
index d376c6b59..dae150fea 100644
--- a/src/system/SignalFD.hxx
+++ b/src/system/SignalFD.hxx
@@ -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();
}
/**
diff --git a/src/system/fd_util.c b/src/system/fd_util.c
index 440d5b142..5763ede90 100644
--- a/src/system/fd_util.c
+++ b/src/system/fd_util.c
@@ -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)
{
diff --git a/src/system/fd_util.h b/src/system/fd_util.h
index 02e959a8e..172b1ade3 100644
--- a/src/system/fd_util.h
+++ b/src/system/fd_util.h
@@ -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.
*/