diff options
author | Eric Wong <normalperson@yhbt.net> | 2013-02-15 02:40:50 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2013-02-15 02:40:50 +0000 |
commit | 5629899a12649b9b21f41efc29b92adbd82afe6c (patch) | |
tree | 8f97f684d65356623af0610e5587bebaa9af6129 | |
parent | 44f4f76d06899b1a0e4719671a4fde3c0851764a (diff) | |
download | cmogstored-5629899a12649b9b21f41efc29b92adbd82afe6c.tar.gz |
This will inform the user of why cmogstored may be slow to start, since we need the mountlist to be populated at startup. We also throw a pthread_cancel() in there to load libgcc_s under glibc, so we can avoid loading libgcc_s once we're under FD pressure. This makes test/http_idle_expire.rb more reliable.
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | cmogstored.h | 3 | ||||
-rw-r--r-- | m4/.gitignore | 3 | ||||
-rw-r--r-- | m4/gnulib-cache.m4 | 3 | ||||
-rw-r--r-- | mnt.c | 81 | ||||
-rw-r--r-- | sig.c | 21 |
6 files changed, 103 insertions, 10 deletions
diff --git a/Makefile.am b/Makefile.am index 1e2b598..6fa520c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,7 +1,7 @@ ACLOCAL_AMFLAGS = -I m4 AM_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib AM_CFLAGS = $(WARN_CFLAGS) $(PTHREAD_CFLAGS) -AM_LDFLAGS = $(LIBGNU_LIBDEPS) +AM_LDFLAGS = $(LIBGNU_LIBDEPS) $(LIB_CLOCK_GETTIME) SUBDIRS = lib # slow.mk is auto-generated by the maintainer (see GNUmakefile) diff --git a/cmogstored.h b/cmogstored.h index 2a31857..393cecb 100644 --- a/cmogstored.h +++ b/cmogstored.h @@ -20,6 +20,7 @@ #include <sys/uio.h> #include <sys/mman.h> #include <sys/types.h> +#include <sys/select.h> #include <sys/stat.h> #include <sys/socket.h> #include <sys/ioctl.h> @@ -62,6 +63,7 @@ #include "gc.h" #include "nproc.h" #include "findprog.h" +#include "timespec.h" #include "gcc.h" #include "util.h" @@ -412,6 +414,7 @@ enum mog_next mog_queue_step(struct mog_fd *mfd) MOG_CHECK; /* sig.c */ void mog_intr_disable(void); void mog_intr_enable(void); +void mog_sleep(long seconds); /* file.c */ struct mog_fd * mog_file_open_read(struct mog_svc *, char *path); diff --git a/m4/.gitignore b/m4/.gitignore index 391f27d..a0934c7 100644 --- a/m4/.gitignore +++ b/m4/.gitignore @@ -175,3 +175,6 @@ /eaccess.m4 /findprog.m4 /stpcpy.m4 +/clock_time.m4 +/gettime.m4 +/timespec.m4 diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4 index 1eeafec..03015fb 100644 --- a/m4/gnulib-cache.m4 +++ b/m4/gnulib-cache.m4 @@ -27,7 +27,7 @@ # Specification in the form of a command-line invocation: -# gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --with-tests --avoid=accept --avoid=accept4 --avoid=alloca --avoid=fstatat --avoid=getcwd --avoid=ioctl --avoid=openat --avoid=read --avoid=sleep --avoid=write --no-conditional-dependencies --no-libtool --macro-prefix=gl argp base64 canonicalize crypto/gc-md5 crypto/gc-sha1 dprintf error findprog git-version-gen hash mempcpy minmax mountlist nonblocking nproc pipe2 progname random_r verify warnings xvasprintf +# gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --with-tests --avoid=accept --avoid=accept4 --avoid=alloca --avoid=fstatat --avoid=getcwd --avoid=ioctl --avoid=openat --avoid=read --avoid=sleep --avoid=write --no-conditional-dependencies --no-libtool --macro-prefix=gl argp base64 canonicalize crypto/gc-md5 crypto/gc-sha1 dprintf error findprog gettime git-version-gen hash mempcpy minmax mountlist nonblocking nproc pipe2 progname random_r verify warnings xvasprintf # Specification in the form of a few gnulib-tool.m4 macro invocations: gl_LOCAL_DIR([]) @@ -40,6 +40,7 @@ gl_MODULES([ dprintf error findprog + gettime git-version-gen hash mempcpy @@ -8,6 +8,11 @@ */ #include "cmogstored.h" +struct init_args { + pthread_mutex_t cond_lock; + pthread_cond_t cond; +}; + static pthread_mutex_t by_dev_lock = PTHREAD_MUTEX_INITIALIZER; /* @@ -113,6 +118,73 @@ skip: } } +/* runs inside a thread, this is called at startup before daemonization */ +static void * init_once(void *ptr) +{ + struct init_args *ia = ptr; + + CHECK(int, 0, pthread_mutex_lock(&by_dev_lock) ); + assert(by_dev == NULL && + "by_dev exists during initialization"); + by_dev = mnt_new(7); + mnt_populate(by_dev); + CHECK(int, 0, pthread_mutex_unlock(&by_dev_lock) ); + + /* wake up parent thread, this tells parent to cancel us */ + CHECK(int, 0, pthread_mutex_lock(&ia->cond_lock)); + CHECK(int, 0, pthread_cond_signal(&ia->cond)); + CHECK(int, 0, pthread_mutex_unlock(&ia->cond_lock)); + + mog_sleep(-1); /* wait for cancellation */ + assert(0 && "init_once did not get cancelled"); + return NULL; +} + +/* once-only initialization */ +static void timed_init_once(void) +{ + pthread_t thr; + unsigned long tries; + struct init_args ia = { + .cond_lock = PTHREAD_MUTEX_INITIALIZER, + .cond = PTHREAD_COND_INITIALIZER + }; + + CHECK(int, 0, pthread_mutex_lock(&ia.cond_lock)); + CHECK(int, 0, pthread_create(&thr, NULL, init_once, &ia)); + + for (tries = 1; ; tries++) { + struct timespec ts; + int rc; + + gettime(&ts); + ts.tv_sec += 5; + rc = pthread_cond_timedwait(&ia.cond, &ia.cond_lock, &ts); + + if (rc == 0) + break; + if (rc == ETIMEDOUT) + warn("still populating mountlist (tries: %lu)", tries); + else if (rc == EINTR) + continue; + else + assert(0 && "unhandled pthread_cond_timedwait failure"); + } + CHECK(int, 0, pthread_mutex_unlock(&ia.cond_lock)); + + /* + * this will load libgcc_s under glibc, we want to do this early + * in process lifetime to prevent load failures if we are under + * FD pressure later on. + */ + CHECK(int, 0, pthread_cancel(thr)); + + CHECK(int, 0, pthread_join(thr, NULL)); + CHECK(int, 0, pthread_cond_destroy(&ia.cond)); + CHECK(int, 0, pthread_mutex_destroy(&ia.cond_lock)); + atexit(mnt_atexit); +} + void mog_mnt_refresh(void) { Hash_table *new, *old; @@ -146,14 +218,7 @@ void mog_mnt_refresh(void) mog_iou_cleanup_finish(); hash_free(old); } else { - /* once-only initialization */ - CHECK(int, 0, pthread_mutex_lock(&by_dev_lock) ); - assert(by_dev == NULL && - "by_dev exists during initialization"); - by_dev = mnt_new(7); - mnt_populate(by_dev); - CHECK(int, 0, pthread_mutex_unlock(&by_dev_lock) ); - atexit(mnt_atexit); + timed_init_once(); } CHECK(int, 0, pthread_mutex_unlock(&refresh_lock) ); @@ -23,3 +23,24 @@ void mog_intr_enable(void) CHECK(int, 0, sigemptyset(&set)); CHECK(int, 0, pthread_sigmask(SIG_SETMASK, &set, NULL)); } + +/* thread-safe, interruptible sleep, negative seconds -> sleep forever */ +void mog_sleep(long seconds) +{ + sigset_t set; + struct timespec ts; + struct timespec *tsp; + + if (seconds < 0) { + tsp = NULL; + } else { + ts.tv_sec = seconds; + ts.tv_nsec = 0; + tsp = &ts; + } + + CHECK(int, 0, sigemptyset(&set)); + if (pselect(0, NULL, NULL, NULL, tsp, &set) < 0) + assert((errno == EINTR || errno == ENOMEM) && + "BUG in pselect usage"); +} |