pthreadpool: call unshare(CLONE_FS) if available
authorRalph Boehme <slow@samba.org>
Tue, 13 Mar 2018 15:59:32 +0000 (16:59 +0100)
committerRalph Boehme <slow@samba.org>
Tue, 24 Jul 2018 15:38:27 +0000 (17:38 +0200)
This paves the way for pthreadpool jobs that are path based.

Callers can use pthreadpool_per_thread_cwd() to check if
the current pool supports it.

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Signed-off-by: Ralph Boehme <slow@samba.org>
lib/pthreadpool/pthreadpool.c
lib/pthreadpool/pthreadpool.h
lib/pthreadpool/pthreadpool_sync.c

index 528f4cdfd6786f8d1feaa7a9bb9f1bf914ec7417..127e684c63e34c27e25aa7624700f5c40bd57134 100644 (file)
@@ -112,10 +112,13 @@ struct pthreadpool {
         * where the forking thread will unlock it again.
         */
        pthread_mutex_t fork_mutex;
+
+       bool per_thread_cwd;
 };
 
 static pthread_mutex_t pthreadpools_mutex = PTHREAD_MUTEX_INITIALIZER;
 static struct pthreadpool *pthreadpools = NULL;
+static bool pthreadpool_support_thread_cwd = false;
 static pthread_once_t pthreadpool_atfork_initialized = PTHREAD_ONCE_INIT;
 
 static void pthreadpool_prep_atfork(void);
@@ -182,6 +185,11 @@ int pthreadpool_init(unsigned max_threads, struct pthreadpool **presult,
        pool->max_threads = max_threads;
        pool->num_idle = 0;
        pool->prefork_cond = NULL;
+       if (max_threads != 0) {
+               pool->per_thread_cwd = pthreadpool_support_thread_cwd;
+       } else {
+               pool->per_thread_cwd = false;
+       }
 
        ret = pthread_mutex_lock(&pthreadpools_mutex);
        if (ret != 0) {
@@ -241,6 +249,15 @@ size_t pthreadpool_queued_jobs(struct pthreadpool *pool)
        return ret;
 }
 
+bool pthreadpool_per_thread_cwd(struct pthreadpool *pool)
+{
+       if (pool->stopped) {
+               return false;
+       }
+
+       return pool->per_thread_cwd;
+}
+
 static void pthreadpool_prepare_pool(struct pthreadpool *pool)
 {
        int ret;
@@ -359,6 +376,16 @@ static void pthreadpool_child(void)
 
 static void pthreadpool_prep_atfork(void)
 {
+#ifdef HAVE_UNSHARE_CLONE_FS
+       int res;
+
+       /* remember if unshare(CLONE_FS) works. */
+       res = unshare(CLONE_FS);
+       if (res == 0) {
+               pthreadpool_support_thread_cwd = true;
+       }
+#endif
+
        pthread_atfork(pthreadpool_prepare, pthreadpool_parent,
                       pthreadpool_child);
 }
@@ -571,6 +598,13 @@ static void *pthreadpool_server(void *arg)
        struct pthreadpool *pool = (struct pthreadpool *)arg;
        int res;
 
+#ifdef HAVE_UNSHARE_CLONE_FS
+       if (pool->per_thread_cwd) {
+               res = unshare(CLONE_FS);
+               assert(res == 0);
+       }
+#endif
+
        res = pthread_mutex_lock(&pool->mutex);
        if (res != 0) {
                return NULL;
index b4733580e07bbc7ed5150de88242302e5c52877c..d8daf9e4519b95e68b17fb1d085c5e1611e9ba9e 100644 (file)
@@ -71,6 +71,23 @@ size_t pthreadpool_max_threads(struct pthreadpool *pool);
  */
 size_t pthreadpool_queued_jobs(struct pthreadpool *pool);
 
+/**
+ * @brief Check for per thread current working directory support of pthreadpool
+ *
+ * Since Linux kernel 2.6.16, unshare(CLONE_FS) is supported,
+ * which provides a per thread current working directory
+ * and allows [f]chdir() within the worker threads.
+ *
+ * Note that this doesn't work on some contraint container setups,
+ * the complete unshare() syscall might be rejected.
+ * pthreadpool_per_thread_cwd() returns what is available
+ * at runtime, so the callers should really check this!
+ *
+ * @param[in]  pool            The pool to run the job on
+ * @return                     supported: true, otherwise: false
+ */
+bool pthreadpool_per_thread_cwd(struct pthreadpool *pool);
+
 /**
  * @brief Stop a pthreadpool
  *
index 48e6a0ddb6049db90617c598f48271ce95486680..2ed6f36dbbc70745cf46ba5ca01296b6ab156db9 100644 (file)
@@ -65,6 +65,11 @@ size_t pthreadpool_queued_jobs(struct pthreadpool *pool)
        return 0;
 }
 
+bool pthreadpool_per_thread_cwd(struct pthreadpool *pool)
+{
+       return false;
+}
+
 int pthreadpool_add_job(struct pthreadpool *pool, int job_id,
                        void (*fn)(void *private_data), void *private_data)
 {