configure.ac: add option --enable-eventfd

Remove the runtime check for eventfd(), hard-code the feature once
it's been selected at compile time.  The class WakeFD is splitted into
EventFD and EventPipe, using WakeFD as a macro diversion.
This commit is contained in:
Max Kellermann 2013-08-06 23:25:57 +02:00
parent 66f678023f
commit 47e16dbee3
10 changed files with 247 additions and 107 deletions

View File

@ -288,7 +288,9 @@ libutil_a_SOURCES = \
# Event loop library
libevent_a_SOURCES = \
src/event/WakeFD.cxx src/event/WakeFD.hxx \
src/event/EventPipe.cxx src/event/EventPipe.hxx \
src/event/EventFD.cxx src/event/EventFD.hxx \
src/event/WakeFD.hxx \
src/event/TimeoutMonitor.hxx src/event/TimeoutMonitor.cxx \
src/event/SocketMonitor.cxx src/event/SocketMonitor.hxx \
src/event/BufferedSocket.cxx src/event/BufferedSocket.hxx \

View File

@ -139,7 +139,8 @@ AC_SEARCH_LIBS([syslog], [bsd socket inet],
AC_SEARCH_LIBS([socket], [socket])
AC_SEARCH_LIBS([gethostbyname], [nsl])
AC_CHECK_FUNCS(pipe2 accept4 eventfd)
AC_CHECK_FUNCS(pipe2 accept4)
MPD_OPTIONAL_FUNC(eventfd, USE_EVENTFD)
AC_SEARCH_LIBS([exp], [m],,
[AC_MSG_ERROR([exp() not found])])

12
m4/mpd_func.m4 Normal file
View File

@ -0,0 +1,12 @@
dnl MPD_OPTIONAL_FUNC(func, macro)
dnl
dnl Allow the user to enable or disable the use of a function. If the
dnl option is not specified, the function is auto-detected.
AC_DEFUN([MPD_OPTIONAL_FUNC], [
AC_ARG_ENABLE([$1],
AS_HELP_STRING([--enable-$1],
[use the function "$1()" (default: auto)]),
[test xenable_$1 = xyes && AC_DEFINE([$2], 1, [Define to use $1()])],
[AC_CHECK_FUNC([$1],
[AC_DEFINE([$2], 1, [Define to use $1()])],)])
])

72
src/event/EventFD.cxx Normal file
View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#ifdef USE_EVENTFD
#include "EventFD.hxx"
#include "fd_util.h"
#include "gcc.h"
#include <unistd.h>
#include <sys/eventfd.h>
#ifdef WIN32
static bool PoorSocketPair(int fd[2]);
#endif
bool
EventFD::Create()
{
assert(fd == -1);
fd = eventfd_cloexec_nonblock(0, 0);
return fd >= 0;
}
void
EventFD::Destroy()
{
close(fd);
#ifndef NDEBUG
fd = -1;
#endif
}
bool
EventFD::Read()
{
assert(fd >= 0);
eventfd_t value;
return read(fd, &value, sizeof(value)) == (ssize_t)sizeof(value);
}
void
EventFD::Write()
{
assert(fd >= 0);
static constexpr eventfd_t value = 1;
gcc_unused ssize_t nbytes =
write(fd, &value, sizeof(value));
}
#endif /* USE_EVENTFD */

68
src/event/EventFD.hxx Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_EVENT_FD_HXX
#define MPD_EVENT_FD_HXX
#include "check.h"
#include <assert.h>
/**
* A class that wraps eventfd().
*
* For optimization purposes, this class does not have a constructor
* or a destructor.
*/
class EventFD {
int fd;
public:
#ifdef NDEBUG
EventFD() = default;
#else
EventFD():fd(-1) {}
#endif
EventFD(const EventFD &other) = delete;
EventFD &operator=(const EventFD &other) = delete;
bool Create();
void Destroy();
int Get() const {
assert(fd >= 0);
return fd;
}
/**
* Checks if Write() was called at least once since the last
* Read() call.
*/
bool Read();
/**
* Wakes up the reader. Multiple calls to this function will
* be combined to one wakeup.
*/
void Write();
};
#endif

View File

@ -18,7 +18,7 @@
*/
#include "config.h"
#include "WakeFD.hxx"
#include "EventPipe.hxx"
#include "fd_util.h"
#include "gcc.h"
@ -30,16 +30,12 @@
#include <cstring> /* for memset() */
#endif
#ifdef HAVE_EVENTFD
#include <sys/eventfd.h>
#endif
#ifdef WIN32
static bool PoorSocketPair(int fd[2]);
#endif
bool
WakeFD::Create()
EventPipe::Create()
{
assert(fds[0] == -1);
assert(fds[1] == -1);
@ -47,85 +43,50 @@ WakeFD::Create()
#ifdef WIN32
return PoorSocketPair(fds);
#else
#ifdef HAVE_EVENTFD
fds[0] = eventfd_cloexec_nonblock(0, 0);
if (fds[0] >= 0) {
fds[1] = -2;
return true;
}
#endif
return pipe_cloexec_nonblock(fds) >= 0;
#endif
}
void
WakeFD::Destroy()
EventPipe::Destroy()
{
#ifdef WIN32
closesocket(fds[0]);
closesocket(fds[1]);
#else
close(fds[0]);
#ifdef HAVE_EVENTFD
if (!IsEventFD())
#endif
close(fds[1]);
#endif
close(fds[1]);
#ifndef NDEBUG
fds[0] = -1;
fds[1] = -1;
#endif
#endif
}
bool
WakeFD::Read()
EventPipe::Read()
{
assert(fds[0] >= 0);
#ifdef WIN32
assert(fds[1] >= 0);
char buffer[256];
#ifdef WIN32
return recv(fds[0], buffer, sizeof(buffer), 0) > 0;
#else
#ifdef HAVE_EVENTFD
if (IsEventFD()) {
eventfd_t value;
return read(fds[0], &value,
sizeof(value)) == (ssize_t)sizeof(value);
}
#endif
assert(fds[1] >= 0);
char buffer[256];
return read(fds[0], buffer, sizeof(buffer)) > 0;
#endif
}
void
WakeFD::Write()
EventPipe::Write()
{
assert(fds[0] >= 0);
assert(fds[1] >= 0);
#ifdef WIN32
assert(fds[1] >= 0);
send(fds[1], "", 1, 0);
#else
#ifdef HAVE_EVENTFD
if (IsEventFD()) {
static constexpr eventfd_t value = 1;
gcc_unused ssize_t nbytes =
write(fds[0], &value, sizeof(value));
return;
}
#endif
assert(fds[1] >= 0);
gcc_unused ssize_t nbytes = write(fds[1], "", 1);
#endif
}
@ -141,7 +102,7 @@ static void SafeCloseSocket(SOCKET s)
/* Our poor man's socketpair() implementation
* Due to limited protocol/address family support and primitive error handling
* it's better to keep this as a private implementation detail of WakeFD
* it's better to keep this as a private implementation detail of EventPipe
* rather than wide-available API.
*/
static bool PoorSocketPair(int fd[2])
@ -160,14 +121,14 @@ static bool PoorSocketPair(int fd[2])
int ret = bind(listen_socket,
reinterpret_cast<sockaddr*>(&address),
sizeof(address));
if (ret < 0) {
SafeCloseSocket(listen_socket);
return false;
}
ret = listen(listen_socket, 1);
if (ret < 0) {
SafeCloseSocket(listen_socket);
return false;

69
src/event/EventPipe.hxx Normal file
View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_EVENT_PIPE_HXX
#define MPD_EVENT_PIPE_HXX
#include "check.h"
#include <assert.h>
/**
* A pipe that can be used to trigger an event to the read side.
*
* For optimization purposes, this class does not have a constructor
* or a destructor.
*/
class EventPipe {
int fds[2];
public:
#ifdef NDEBUG
EventPipe() = default;
#else
EventPipe():fds{-1, -1} {};
#endif
EventPipe(const EventPipe &other) = delete;
EventPipe &operator=(const EventPipe &other) = delete;
bool Create();
void Destroy();
int Get() const {
assert(fds[0] >= 0);
assert(fds[1] >= 0);
return fds[0];
}
/**
* Checks if Write() was called at least once since the last
* Read() call.
*/
bool Read();
/**
* Wakes up the reader. Multiple calls to this function will
* be combined to one wakeup.
*/
void Write();
};
#endif /* MAIN_NOTIFY_H */

View File

@ -24,57 +24,12 @@
#include <assert.h>
/**
* This class can be used to wake up an I/O event loop.
*
* For optimization purposes, this class does not have a constructor
* or a destructor.
*/
class WakeFD {
int fds[2];
public:
#ifdef NDEBUG
WakeFD() = default;
#ifdef USE_EVENTFD
#include "EventFD.hxx"
#define WakeFD EventFD
#else
WakeFD():fds{-1, -1} {};
#include "EventPipe.hxx"
#define WakeFD EventPipe
#endif
WakeFD(const WakeFD &other) = delete;
WakeFD &operator=(const WakeFD &other) = delete;
bool Create();
void Destroy();
int Get() const {
assert(fds[0] >= 0);
#ifndef HAVE_EVENTFD
assert(fds[1] >= 0);
#endif
return fds[0];
}
/**
* Checks if Write() was called at least once since the last
* Read() call.
*/
bool Read();
/**
* Wakes up the reader. Multiple calls to this function will
* be combined to one wakeup.
*/
void Write();
private:
#ifdef HAVE_EVENTFD
bool IsEventFD() {
assert(fds[0] >= 0);
return fds[1] == -2;
}
#endif
};
#endif /* MAIN_NOTIFY_H */

View File

@ -49,7 +49,7 @@
#include <sys/inotify.h>
#endif
#ifdef HAVE_EVENTFD
#ifdef USE_EVENTFD
#include <sys/eventfd.h>
#endif
@ -332,7 +332,7 @@ inotify_init_cloexec(void)
#endif
#ifdef HAVE_EVENTFD
#ifdef USE_EVENTFD
int
eventfd_cloexec_nonblock(unsigned initval, int flags)

View File

@ -144,7 +144,7 @@ inotify_init_cloexec(void);
#endif
#ifdef HAVE_EVENTFD
#ifdef USE_EVENTFD
/**
* Wrapper for eventfd() which sets the flags CLOEXEC and NONBLOCK