From 5a02ed2f3505f5ed3282c6b43963e19e63e49905 Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Tue, 25 Aug 2015 15:47:29 +0200 Subject: Fix ethread events with timeout Lots of pthread platforms unnecessarily falled back on the pipe/select solution. This since we tried to use the same monotonic clock source for pthread_cond_timedwait() as used by OS monotonic time. This has been fixed on most platforms by using another clock source. Darwin can however not use pthread_cond_timedwait() with monotonic clock source and has to use the pipe/select solution. On darwin we now use select with _DARWIN_UNLIMITED_SELECT in order to be able to handle a large amount of file descriptors. --- erts/aclocal.m4 | 6 +- erts/emulator/beam/erl_process.c | 7 ++- erts/emulator/beam/erl_threads.h | 10 +++ erts/emulator/drivers/unix/unix_efile.c | 10 +-- erts/include/internal/pthread/ethr_event.h | 11 ++++ erts/include/internal/win/ethr_event.h | 1 + erts/lib_src/pthread/ethr_event.c | 97 +++++++++++++++++++++++++++--- erts/lib_src/win/ethr_event.c | 6 ++ 8 files changed, 130 insertions(+), 18 deletions(-) (limited to 'erts') diff --git a/erts/aclocal.m4 b/erts/aclocal.m4 index 0714ce6030..7550561737 100644 --- a/erts/aclocal.m4 +++ b/erts/aclocal.m4 @@ -750,8 +750,8 @@ AC_DEFUN(ERL_MONOTONIC_CLOCK, prefer_resolution_clock_gettime_monotonic="$2" ;; *) - check_msg="" - prefer_resolution_clock_gettime_monotonic= + check_msg="custom " + prefer_resolution_clock_gettime_monotonic="$2" ;; esac @@ -1472,7 +1472,7 @@ AC_ARG_WITH(with_sparc_memory_order, LM_CHECK_THR_LIB ERL_INTERNAL_LIBS -ERL_MONOTONIC_CLOCK(high_resolution, undefined, no) +ERL_MONOTONIC_CLOCK(try_find_pthread_compatible, CLOCK_HIGHRES CLOCK_MONOTONIC, no) case $erl_monotonic_clock_func in clock_gettime) diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index ee1dd36d48..58698173be 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -7938,11 +7938,16 @@ sched_thread_func(void *vesdp) ErtsThrPrgrCallbacks callbacks; ErtsSchedulerData *esdp = vesdp; Uint no = esdp->no; +#ifdef ERTS_SMP + erts_tse_t *tse; +#endif erts_sched_init_time_sup(esdp); #ifdef ERTS_SMP - ERTS_SCHED_SLEEP_INFO_IX(no - 1)->event = erts_tse_fetch(); + tse = erts_tse_fetch(); + erts_tse_prepare_timed(tse); + ERTS_SCHED_SLEEP_INFO_IX(no - 1)->event = tse; callbacks.arg = (void *) esdp->ssi; callbacks.wakeup = thr_prgr_wakeup; callbacks.prepare_wait = thr_prgr_prep_wait; diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h index 5347979372..34f91e2ec8 100644 --- a/erts/emulator/beam/erl_threads.h +++ b/erts/emulator/beam/erl_threads.h @@ -649,6 +649,7 @@ ERTS_GLB_INLINE void erts_tsd_set(erts_tsd_key_t key, void *value); ERTS_GLB_INLINE void * erts_tsd_get(erts_tsd_key_t key); ERTS_GLB_INLINE erts_tse_t *erts_tse_fetch(void); ERTS_GLB_INLINE void erts_tse_return(erts_tse_t *ep); +ERTS_GLB_INLINE void erts_tse_prepare_timed(erts_tse_t *ep); ERTS_GLB_INLINE void erts_tse_set(erts_tse_t *ep); ERTS_GLB_INLINE void erts_tse_reset(erts_tse_t *ep); ERTS_GLB_INLINE int erts_tse_wait(erts_tse_t *ep); @@ -3461,6 +3462,15 @@ ERTS_GLB_INLINE void erts_tse_return(erts_tse_t *ep) #endif } +ERTS_GLB_INLINE void erts_tse_prepare_timed(erts_tse_t *ep) +{ +#ifdef USE_THREADS + int res = ethr_event_prepare_timed(&((ethr_ts_event *) ep)->event); + if (res != 0) + erts_thr_fatal_error(res, "prepare timed"); +#endif +} + ERTS_GLB_INLINE void erts_tse_set(erts_tse_t *ep) { #ifdef USE_THREADS diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 06ba986044..46eccc6568 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -45,10 +45,10 @@ #endif #if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) -#define DARWIN 1 +#define __DARWIN__ 1 #endif -#if defined(DARWIN) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) +#if defined(__DARWIN__) || defined(HAVE_LINUX_FALLOC_H) || defined(HAVE_POSIX_FALLOCATE) #include #endif @@ -476,11 +476,11 @@ efile_fsync(Efile_error *errInfo, /* Where to return error codes. */ #ifdef NO_FSYNC undefined fsync /* XXX: Really? */ #else -#if defined(DARWIN) && defined(F_FULLFSYNC) +#if defined(__DARWIN__) && defined(F_FULLFSYNC) return check_error(fcntl(fd, F_FULLFSYNC), errInfo); #else return check_error(fsync(fd), errInfo); -#endif /* DARWIN */ +#endif /* __DARWIN__ */ #endif /* NO_FSYNC */ } @@ -962,7 +962,7 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, retval = len; } } while (len == SENDFILE_CHUNK_SIZE); -#elif defined(DARWIN) +#elif defined(__DARWIN__) int retval; off_t len; do { diff --git a/erts/include/internal/pthread/ethr_event.h b/erts/include/internal/pthread/ethr_event.h index 74cfa68e16..deb4b29686 100644 --- a/erts/include/internal/pthread/ethr_event.h +++ b/erts/include/internal/pthread/ethr_event.h @@ -83,12 +83,22 @@ ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e) #elif defined(ETHR_PTHREADS) /* --- Posix mutex/cond pipe/select implementation of events ---------------- */ +#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) +# define __DARWIN__ 1 +#endif + +#ifdef __DARWIN__ +typedef struct ethr_event_fdsets___ ethr_event_fdsets__; +#endif typedef struct { ethr_atomic32_t state; pthread_mutex_t mtx; pthread_cond_t cnd; int fd[2]; +#ifdef __DARWIN__ + ethr_event_fdsets__ *fdsets; +#endif } ethr_event; #define ETHR_EVENT_OFF_WAITER_SELECT__ ((ethr_sint32_t) -2) @@ -148,6 +158,7 @@ ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e) #endif int ethr_event_init(ethr_event *e); +int ethr_event_prepare_timed(ethr_event *e); int ethr_event_destroy(ethr_event *e); int ethr_event_wait(ethr_event *e); int ethr_event_swait(ethr_event *e, int spincount); diff --git a/erts/include/internal/win/ethr_event.h b/erts/include/internal/win/ethr_event.h index bf110e10f9..458565b9ea 100644 --- a/erts/include/internal/win/ethr_event.h +++ b/erts/include/internal/win/ethr_event.h @@ -56,6 +56,7 @@ ETHR_INLINE_FUNC_NAME_(ethr_event_reset)(ethr_event *e) #endif int ethr_event_init(ethr_event *e); +int ethr_event_prepare_timed(ethr_event *e); int ethr_event_destroy(ethr_event *e); int ethr_event_wait(ethr_event *e); int ethr_event_swait(ethr_event *e, int spincount); diff --git a/erts/lib_src/pthread/ethr_event.c b/erts/lib_src/pthread/ethr_event.c index ba664236f6..0629b4dfcd 100644 --- a/erts/lib_src/pthread/ethr_event.c +++ b/erts/lib_src/pthread/ethr_event.c @@ -29,6 +29,13 @@ #include "config.h" #endif +#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) +# define __DARWIN__ 1 +#endif +#ifdef __DARWIN__ +# define _DARWIN_UNLIMITED_SELECT +#endif + #include "ethread.h" #undef ETHR_INCLUDE_MONOTONIC_CLOCK__ #define ETHR_INCLUDE_MONOTONIC_CLOCK__ @@ -55,6 +62,12 @@ ethr_event_init(ethr_event *e) return 0; } +int +ethr_event_prepare_timed(ethr_event *e) +{ + return 0; +} + int ethr_event_destroy(ethr_event *e) { @@ -171,6 +184,17 @@ return_event_on: #include #include +#ifdef __DARWIN__ + +struct ethr_event_fdsets___ { + fd_set *rsetp; + fd_set *esetp; + size_t mem_size; + fd_mask mem[1]; +}; + +#endif + static void setup_nonblocking_pipe(ethr_event *e) { @@ -188,6 +212,35 @@ setup_nonblocking_pipe(ethr_event *e) flgs = fcntl(e->fd[1], F_GETFL, 0); fcntl(e->fd[1], F_SETFL, flgs | O_NONBLOCK); + +#ifndef __DARWIN__ + if (e->fd[0] >= FD_SETSIZE) + ETHR_FATAL_ERROR__(ENOTSUP); +#else + { + int nmasks; + ethr_event_fdsets__ *fdsets; + size_t mem_size; + + nmasks = (e->fd[0]+NFDBITS)/NFDBITS; + mem_size = 2*nmasks*sizeof(fd_mask); + if (mem_size < 2*sizeof(fd_set)) { + mem_size = 2*sizeof(fd_set); + nmasks = mem_size/(2*sizeof(fd_mask)); + } + + fdsets = malloc(sizeof(ethr_event_fdsets__) + + mem_size + - sizeof(fd_mask)); + if (!fdsets) + ETHR_FATAL_ERROR__(ENOMEM); + fdsets->rsetp = (fd_set *) (char *) &fdsets->mem[0]; + fdsets->esetp = (fd_set *) (char *) &fdsets->mem[nmasks]; + fdsets->mem_size = mem_size; + e->fdsets = fdsets; + } +#endif + ETHR_MEMBAR(ETHR_StoreStore); } @@ -252,6 +305,19 @@ ethr_event_init(ethr_event *e) e->fd[0] = e->fd[1] = ETHR_EVENT_INVALID_FD__; +#ifdef __DARWIN__ + e->fdsets = NULL; +#endif + + return 0; +} + +int +ethr_event_prepare_timed(ethr_event *e) +{ + if (e->fd[0] == ETHR_EVENT_INVALID_FD__) + setup_nonblocking_pipe(e); + return 0; } @@ -263,13 +329,14 @@ ethr_event_destroy(ethr_event *e) close(e->fd[0]); close(e->fd[1]); } +#ifdef __DARWIN__ + if (e->fdsets) + free(e->fdsets); +#endif res = pthread_mutex_destroy(&e->mtx); if (res != 0) return res; - res = pthread_cond_destroy(&e->cnd); - if (res != 0) - return res; - return 0; + return pthread_cond_destroy(&e->cnd); } static ETHR_INLINE int @@ -403,8 +470,10 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) int fd; int sres; ssize_t rres; - fd_set rset; - fd_set eset; +#ifndef __DARWIN__ + fd_set rset, eset; +#endif + fd_set *rsetp, *esetp; struct timeval select_timeout; #ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME @@ -457,12 +526,22 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) ETHR_ASSERT(act == val); } + +#ifdef __DARWIN__ + rsetp = e->fdsets->rsetp; + esetp = e->fdsets->esetp; + memset((void *) &e->fdsets->mem[0], 0, e->fdsets->mem_size); +#else FD_ZERO(&rset); - FD_SET(fd, &rset); FD_ZERO(&eset); - FD_SET(fd, &eset); + rsetp = &rset; + esetp = &eset; +#endif + + FD_SET(fd, rsetp); + FD_SET(fd, esetp); - sres = select(fd + 1, &rset, NULL, &eset, &select_timeout); + sres = select(fd + 1, rsetp, NULL, esetp, &select_timeout); if (sres == 0) res = ETIMEDOUT; else { diff --git a/erts/lib_src/win/ethr_event.c b/erts/lib_src/win/ethr_event.c index c88c8784a2..6951a216c5 100644 --- a/erts/lib_src/win/ethr_event.c +++ b/erts/lib_src/win/ethr_event.c @@ -46,6 +46,12 @@ ethr_event_init(ethr_event *e) return 0; } +int +ethr_event_prepare_timed(ethr_event *e) +{ + return 0; +} + int ethr_event_destroy(ethr_event *e) { -- cgit v1.2.3