about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2013-06-21 03:34:36 +0000
committerEric Wong <normalperson@yhbt.net>2013-06-25 22:07:42 +0000
commite12e70b6bd242cb3fea74d1df8b7b44e0a9f7f26 (patch)
tree49f915d77028ae98852243efed2ab3c7c8323660
parenta18a08a0e9a7c472656afc86cbbbfcefda5e456d (diff)
downloadcmogstored-e12e70b6bd242cb3fea74d1df8b7b44e0a9f7f26.tar.gz
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.
-rw-r--r--Makefile.am1
-rw-r--r--cmogstored.h3
-rw-r--r--configure.ac3
-rw-r--r--fdmap.c2
-rw-r--r--mnt.c2
-rw-r--r--thrpool.c22
-rw-r--r--yield.c29
7 files changed, 40 insertions, 22 deletions
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
@@ -67,24 +67,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
  * in case it enters a sleeping syscall (epoll_wait/kevent) immediately
@@ -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 <normalperson@yhbt.net>
+ * 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();
+}