assert_false(in_main_thread);
}
+static void test_per_thread_cwd_job(void *ptr)
+{
+ const bool *per_thread_cwd_ptr = ptr;
+ bool per_thread_cwd;
+ char cwdbuf[PATH_MAX] = {0,};
+ char *cwdstr = NULL;
+ int ret;
+
+ /*
+ * This needs to be consistent.
+ */
+ per_thread_cwd = pthreadpool_tevent_current_job_per_thread_cwd();
+ assert_int_equal(per_thread_cwd, *per_thread_cwd_ptr);
+
+ if (!per_thread_cwd) {
+ return;
+ }
+
+ /*
+ * Check we're not already in "/".
+ */
+ cwdstr = getcwd(cwdbuf, sizeof(cwdbuf));
+ assert_non_null(cwdstr);
+ assert_string_not_equal(cwdstr, "/");
+
+ ret = chdir("/");
+ assert_int_equal(ret, 0);
+
+ /*
+ * Check we're in "/" now.
+ */
+ cwdstr = getcwd(cwdbuf, sizeof(cwdbuf));
+ assert_non_null(cwdstr);
+ assert_string_equal(cwdstr, "/");
+}
+
+static int test_per_thread_cwd_do(struct tevent_context *ev,
+ struct pthreadpool_tevent *pool)
+{
+ struct tevent_req *req;
+ bool per_thread_cwd;
+ bool ok;
+ int ret;
+ per_thread_cwd = pthreadpool_tevent_per_thread_cwd(pool);
+
+ req = pthreadpool_tevent_job_send(
+ ev, ev, pool, test_per_thread_cwd_job, &per_thread_cwd);
+ if (req == NULL) {
+ fprintf(stderr, "pthreadpool_tevent_job_send failed\n");
+ return ENOMEM;
+ }
+
+ ok = tevent_req_poll(req, ev);
+ if (!ok) {
+ ret = errno;
+ fprintf(stderr, "tevent_req_poll failed: %s\n",
+ strerror(ret));
+ return ret;
+ }
+
+ ret = pthreadpool_tevent_job_recv(req);
+ TALLOC_FREE(req);
+ if (ret != 0) {
+ fprintf(stderr, "tevent_req_recv failed: %s\n",
+ strerror(ret));
+ return ret;
+ }
+
+ return 0;
+}
+
+static void test_per_thread_cwd(void **state)
+{
+ struct pthreadpool_tevent_test *t = *state;
+ int ret;
+ bool per_thread_cwd_u;
+ bool per_thread_cwd_o;
+ bool per_thread_cwd_s;
+ char cwdbuf1[PATH_MAX] = {0,};
+ char *cwdstr1 = NULL;
+ char cwdbuf2[PATH_MAX] = {0,};
+ char *cwdstr2 = NULL;
+
+ /*
+ * The unlimited and one pools
+ * should be consistent.
+ *
+ * We can't enforce this as some constraint
+ * container environments disable unshare()
+ * completely, even just with CLONE_FS.
+ */
+ per_thread_cwd_u = pthreadpool_tevent_per_thread_cwd(t->upool);
+ per_thread_cwd_o = pthreadpool_tevent_per_thread_cwd(t->opool);
+ assert_int_equal(per_thread_cwd_u, per_thread_cwd_o);
+
+ /*
+ * The sync pool should never support this.
+ */
+ per_thread_cwd_s = pthreadpool_tevent_per_thread_cwd(t->spool);
+ assert_false(per_thread_cwd_s);
+
+ /*
+ * Check we're not already in "/".
+ */
+ cwdstr1 = getcwd(cwdbuf1, sizeof(cwdbuf1));
+ assert_non_null(cwdstr1);
+ assert_string_not_equal(cwdstr1, "/");
+
+ will_return(__wrap_pthread_create, 0);
+ ret = test_per_thread_cwd_do(t->ev, t->upool);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Check we're still in the same directory.
+ */
+ cwdstr2 = getcwd(cwdbuf2, sizeof(cwdbuf2));
+ assert_non_null(cwdstr2);
+ assert_string_equal(cwdstr2, cwdstr1);
+
+ will_return(__wrap_pthread_create, 0);
+ ret = test_per_thread_cwd_do(t->ev, t->opool);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Check we're still in the same directory.
+ */
+ cwdstr2 = getcwd(cwdbuf2, sizeof(cwdbuf2));
+ assert_non_null(cwdstr2);
+ assert_string_equal(cwdstr2, cwdstr1);
+
+ ret = test_per_thread_cwd_do(t->ev, t->spool);
+ assert_int_equal(ret, 0);
+
+ /*
+ * Check we're still in the same directory.
+ */
+ cwdstr2 = getcwd(cwdbuf2, sizeof(cwdbuf2));
+ assert_non_null(cwdstr2);
+ assert_string_equal(cwdstr2, cwdstr1);
+}
+
struct test_cancel_job {
int fdm; /* the main end of socketpair */
int fdj; /* the job end of socketpair */
cmocka_unit_test_setup_teardown(test_create,
setup_pthreadpool_tevent,
teardown_pthreadpool_tevent),
+ cmocka_unit_test_setup_teardown(test_per_thread_cwd,
+ setup_pthreadpool_tevent,
+ teardown_pthreadpool_tevent),
cmocka_unit_test_setup_teardown(test_cancel_job,
setup_pthreadpool_tevent,
teardown_pthreadpool_tevent),