From e12e70b6bd242cb3fea74d1df8b7b44e0a9f7f26 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 21 Jun 2013 03:34:36 +0000 Subject: introduce mog_yield wrapper around sched_yield/pthread_yield While pthread_yield is non-standard, it is relatively common and preferable for systems where pthreads are _not_ 1:1 mapped to kernel threads. This also provides a stronger yield to weaken the priority of the calling thread wherever we previously used sched_yield. --- Makefile.am | 1 + cmogstored.h | 3 +++ configure.ac | 3 +++ fdmap.c | 2 +- mnt.c | 2 +- thrpool.c | 22 ++-------------------- yield.c | 29 +++++++++++++++++++++++++++++ 7 files changed, 40 insertions(+), 22 deletions(-) create mode 100644 yield.c diff --git a/Makefile.am b/Makefile.am index 918200c..dd1e9e3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -92,6 +92,7 @@ mog_src += trace.h mog_src += trywrite.c mog_src += util.h mog_src += upgrade.c +mog_src += yield.c LDADD = $(LIBINTL) $(top_builddir)/lib/libgnu.a libnostd.a noinst_LIBRARIES = libnostd.a diff --git a/cmogstored.h b/cmogstored.h index 580de8d..e6975c3 100644 --- a/cmogstored.h +++ b/cmogstored.h @@ -596,3 +596,6 @@ struct mog_ni { /* nameinfo.c */ void mog_nameinfo(struct mog_packaddr *, struct mog_ni *); + +/* yield.c */ +void mog_yield(void); diff --git a/configure.ac b/configure.ac index 8a9e6d1..5cfdc9b 100644 --- a/configure.ac +++ b/configure.ac @@ -45,6 +45,9 @@ AC_CHECK_FUNCS([sendfile]) AC_CHECK_FUNCS([open_memstream]) AC_CHECK_FUNCS([posix_fadvise]) +dnl non-standard, but common +AC_CHECK_FUNCS([pthread_yield]) + dnl gnulib doesn't actually define SOCK_NONBLOCK/SOCK_CLOEXEC, and dnl even if it did, emulation wouldn't be thread-safe AC_CHECK_FUNCS([accept4]) diff --git a/fdmap.c b/fdmap.c index 823cf9f..7ef8aff 100644 --- a/fdmap.c +++ b/fdmap.c @@ -300,7 +300,7 @@ out: * 4) close sockets. */ for (fd = (int)expired * 8; --fd >= 0; ) - sched_yield(); + mog_yield(); return expired; } diff --git a/mnt.c b/mnt.c index 9fb2e68..092111c 100644 --- a/mnt.c +++ b/mnt.c @@ -163,7 +163,7 @@ static void timed_init_once(void) if ((++tries % 1024) == 0) warn("pthread_create: %s (tries: %lu)", strerror(rc), tries); - sched_yield(); + mog_yield(); } else { assert(0 && "pthread_create usage error"); } diff --git a/thrpool.c b/thrpool.c index 7d62b59..9cf8196 100644 --- a/thrpool.c +++ b/thrpool.c @@ -66,24 +66,6 @@ void mog_thr_test_quit(void) } } -/* - * sched_yield may migrate us to the same CPU as the task we're waiting - * on, so just keep yielding for every CPU we have as this throttles - * our ability to spam SIGURG. This means the threads we're trying to - * gracefully kill off can finish their work and check their mog_do_quit - * flag sooner - */ -static void yield_all(void) -{ - static unsigned long nproc_all; - unsigned long i; - - if (!nproc_all) - nproc_all = num_processors(NPROC_ALL) * 2; - for (i = 0; i < nproc_all; i++) - pthread_yield(); -} - /* * we no longer rely on pthreads cancellation, so our explicit checks for * thread quitting requires us to continuously signal a thread for death @@ -99,7 +81,7 @@ static void poke(pthread_t thr, int sig) * we lower thread counts or shut down */ while ((err = pthread_kill(thr, sig)) == 0) - yield_all(); + mog_yield(); assert(err == ESRCH && "pthread_kill() usage bug"); } @@ -115,7 +97,7 @@ thr_create_fail_retry(struct mog_thrpool *tp, size_t size, syslog(LOG_ERR, "pthread_create: %m (tries: %lu)", *nr_eagain); } - yield_all(); + mog_yield(); return true; } else { errno = err; diff --git a/yield.c b/yield.c new file mode 100644 index 0000000..3a0b66d --- /dev/null +++ b/yield.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2013, Eric Wong + * License: GPLv3 or later (see COPYING for details) + */ +#include "cmogstored.h" +#ifndef HAVE_PTHREAD_YIELD +# define pthread_yield() (void)sched_yield() +#endif + +/* + * pthread_yield may migrate us to the same CPU as the task we're waiting + * on, so just keep yielding for every CPU we have as this throttles + * our ability to spam SIGURG. This means the threads we're trying to + * gracefully kill off can finish their work and check their mog_do_quit + * flag sooner + * + * We only use this as a last resort when normal wakeups/notifications + * are not usable (e.g. recovering from out-of-resource problems) + */ +void mog_yield(void) +{ + static unsigned long nproc_all; + unsigned long i; + + if (!nproc_all) + nproc_all = num_processors(NPROC_ALL) * 2; + for (i = 0; i < nproc_all; i++) + pthread_yield(); +} -- cgit v1.2.3-24-ge0c7