thread_pthread.c: use eventfd instead of pipe on Linux
Based on r64478, any regular user creating more than 1024 pipes on Linux will end up with tiny pipes with only a single page capacity. So avoid wasting user resources and use lighter eventfd on Linux. [ruby-core:88563] [Misc #15011] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64527 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
5bd4283f77
commit
0a77fd04b7
@ -983,6 +983,7 @@ AC_CHECK_HEADERS(pwd.h)
|
|||||||
AC_CHECK_HEADERS(setjmpex.h)
|
AC_CHECK_HEADERS(setjmpex.h)
|
||||||
AC_CHECK_HEADERS(stdalign.h)
|
AC_CHECK_HEADERS(stdalign.h)
|
||||||
AC_CHECK_HEADERS(sys/attr.h)
|
AC_CHECK_HEADERS(sys/attr.h)
|
||||||
|
AC_CHECK_HEADERS(sys/eventfd.h)
|
||||||
AC_CHECK_HEADERS(sys/fcntl.h)
|
AC_CHECK_HEADERS(sys/fcntl.h)
|
||||||
AC_CHECK_HEADERS(sys/file.h)
|
AC_CHECK_HEADERS(sys/file.h)
|
||||||
AC_CHECK_HEADERS(sys/id.h)
|
AC_CHECK_HEADERS(sys/id.h)
|
||||||
@ -1755,6 +1756,7 @@ AC_CHECK_FUNCS(dup)
|
|||||||
AC_CHECK_FUNCS(dup3)
|
AC_CHECK_FUNCS(dup3)
|
||||||
AC_CHECK_FUNCS(eaccess)
|
AC_CHECK_FUNCS(eaccess)
|
||||||
AC_CHECK_FUNCS(endgrent)
|
AC_CHECK_FUNCS(endgrent)
|
||||||
|
AC_CHECK_FUNCS(eventfd)
|
||||||
AC_CHECK_FUNCS(fchmod)
|
AC_CHECK_FUNCS(fchmod)
|
||||||
AC_CHECK_FUNCS(fchown)
|
AC_CHECK_FUNCS(fchown)
|
||||||
AC_CHECK_FUNCS(fcntl)
|
AC_CHECK_FUNCS(fcntl)
|
||||||
|
13
thread.c
13
thread.c
@ -398,6 +398,10 @@ ubf_sigwait(void *ignore)
|
|||||||
# define BUSY_WAIT_SIGNALS (0)
|
# define BUSY_WAIT_SIGNALS (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef USE_EVENTFD
|
||||||
|
# define USE_EVENTFD (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if THREAD_DEBUG
|
#if THREAD_DEBUG
|
||||||
static int debug_mutex_initialized = 1;
|
static int debug_mutex_initialized = 1;
|
||||||
static rb_nativethread_lock_t debug_mutex;
|
static rb_nativethread_lock_t debug_mutex;
|
||||||
@ -4271,9 +4275,12 @@ async_bug_fd(const char *mesg, int errno_arg, int fd)
|
|||||||
static int
|
static int
|
||||||
consume_communication_pipe(int fd)
|
consume_communication_pipe(int fd)
|
||||||
{
|
{
|
||||||
#define CCP_READ_BUFF_SIZE 1024
|
#if USE_EVENTFD
|
||||||
|
uint64_t buff[1];
|
||||||
|
#else
|
||||||
/* buffer can be shared because no one refers to them. */
|
/* buffer can be shared because no one refers to them. */
|
||||||
static char buff[CCP_READ_BUFF_SIZE];
|
static char buff[1024];
|
||||||
|
#endif
|
||||||
ssize_t result;
|
ssize_t result;
|
||||||
int ret = FALSE; /* for rb_sigwait_sleep */
|
int ret = FALSE; /* for rb_sigwait_sleep */
|
||||||
|
|
||||||
@ -4289,7 +4296,7 @@ consume_communication_pipe(int fd)
|
|||||||
result = read(fd, buff, sizeof(buff));
|
result = read(fd, buff, sizeof(buff));
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
ret = TRUE;
|
ret = TRUE;
|
||||||
if (result < (ssize_t)sizeof(buff)) {
|
if (USE_EVENTFD || result < (ssize_t)sizeof(buff)) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,13 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#if defined(HAVE_SYS_EVENTFD_H) && defined(HAVE_EVENTFD)
|
||||||
|
# define USE_EVENTFD (1)
|
||||||
|
# include <sys/eventfd.h>
|
||||||
|
#else
|
||||||
|
# define USE_EVENTFD (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(SIGVTALRM) && !defined(__CYGWIN__)
|
#if defined(SIGVTALRM) && !defined(__CYGWIN__)
|
||||||
# define USE_UBF_LIST 1
|
# define USE_UBF_LIST 1
|
||||||
#endif
|
#endif
|
||||||
@ -1386,13 +1393,17 @@ static struct {
|
|||||||
static void
|
static void
|
||||||
rb_thread_wakeup_timer_thread_fd(int fd)
|
rb_thread_wakeup_timer_thread_fd(int fd)
|
||||||
{
|
{
|
||||||
|
#if USE_EVENTFD
|
||||||
|
const uint64_t buff = 1;
|
||||||
|
#else
|
||||||
|
const char buff = '!';
|
||||||
|
#endif
|
||||||
ssize_t result;
|
ssize_t result;
|
||||||
|
|
||||||
/* already opened */
|
/* already opened */
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
static const char buff[1] = {'!'};
|
|
||||||
retry:
|
retry:
|
||||||
if ((result = write(fd, buff, 1)) <= 0) {
|
if ((result = write(fd, &buff, sizeof(buff))) <= 0) {
|
||||||
int e = errno;
|
int e = errno;
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case EINTR: goto retry;
|
case EINTR: goto retry;
|
||||||
@ -1505,8 +1516,8 @@ rb_thread_wakeup_timer_thread(int sig)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CLOSE_INVALIDATE(expr) \
|
#define CLOSE_INVALIDATE_PAIR(expr) \
|
||||||
close_invalidate(&expr,"close_invalidate: "#expr)
|
close_invalidate_pair(expr,"close_invalidate: "#expr)
|
||||||
static void
|
static void
|
||||||
close_invalidate(int *fdp, const char *msg)
|
close_invalidate(int *fdp, const char *msg)
|
||||||
{
|
{
|
||||||
@ -1518,6 +1529,19 @@ close_invalidate(int *fdp, const char *msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
close_invalidate_pair(int fds[2], const char *msg)
|
||||||
|
{
|
||||||
|
if (USE_EVENTFD && fds[0] == fds[1]) {
|
||||||
|
close_invalidate(&fds[0], msg);
|
||||||
|
fds[1] = -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
close_invalidate(&fds[0], msg);
|
||||||
|
close_invalidate(&fds[1], msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_nonblock(int fd)
|
set_nonblock(int fd)
|
||||||
{
|
{
|
||||||
@ -1545,6 +1569,18 @@ setup_communication_pipe_internal(int pipes[2])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't bother with eventfd on ancient Linux 2.6.22..2.6.26 which were
|
||||||
|
* missing EFD_* flags, they can fall back to pipe
|
||||||
|
*/
|
||||||
|
#if USE_EVENTFD && defined(EFD_NONBLOCK) && defined(EFD_CLOEXEC)
|
||||||
|
pipes[0] = pipes[1] = eventfd(0, EFD_NONBLOCK|EFD_CLOEXEC);
|
||||||
|
if (pipes[0] >= 0) {
|
||||||
|
rb_update_max_fd(pipes[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
err = rb_cloexec_pipe(pipes);
|
err = rb_cloexec_pipe(pipes);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
rb_warn("pipe creation failed for timer: %s, scheduling broken",
|
rb_warn("pipe creation failed for timer: %s, scheduling broken",
|
||||||
@ -1612,8 +1648,7 @@ static void
|
|||||||
ubf_timer_invalidate(void)
|
ubf_timer_invalidate(void)
|
||||||
{
|
{
|
||||||
#if UBF_TIMER == UBF_TIMER_PTHREAD
|
#if UBF_TIMER == UBF_TIMER_PTHREAD
|
||||||
CLOSE_INVALIDATE(timer_pthread.low[0]);
|
CLOSE_INVALIDATE_PAIR(timer_pthread.low);
|
||||||
CLOSE_INVALIDATE(timer_pthread.low[1]);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1669,8 +1704,7 @@ rb_thread_create_timer_thread(void)
|
|||||||
rb_pid_t owner = signal_self_pipe.owner_process;
|
rb_pid_t owner = signal_self_pipe.owner_process;
|
||||||
|
|
||||||
if (owner && owner != current) {
|
if (owner && owner != current) {
|
||||||
CLOSE_INVALIDATE(signal_self_pipe.normal[0]);
|
CLOSE_INVALIDATE_PAIR(signal_self_pipe.normal);
|
||||||
CLOSE_INVALIDATE(signal_self_pipe.normal[1]);
|
|
||||||
ubf_timer_invalidate();
|
ubf_timer_invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user