[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha7-1343-g5b7b47f

Volker Lendecke vlendec at samba.org
Fri May 1 10:31:22 GMT 2009


The branch, master has been updated
       via  5b7b47f01568200f5064ca4b48457edb5ccc3109 (commit)
       via  8cf75770cf2b3905ca98c84b21fadca8e05f08b7 (commit)
       via  db2cc8c9f2ec6f98884b1eb7738148cecdf6fd45 (commit)
      from  f3af298e5b1457ba8661fd0e3f5304ad3175f3ba (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 5b7b47f01568200f5064ca4b48457edb5ccc3109
Author: Volker Lendecke <vl at samba.org>
Date:   Sun Apr 26 00:01:43 2009 +0200

    Add getaddrinfo_send/recv

commit 8cf75770cf2b3905ca98c84b21fadca8e05f08b7
Author: Volker Lendecke <vl at samba.org>
Date:   Sat Apr 25 20:02:24 2009 +0200

    Add fncall_send/recv

commit db2cc8c9f2ec6f98884b1eb7738148cecdf6fd45
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Apr 23 17:23:13 2009 +0200

    Add thread pool
    
    Included if pthreads are found, can be disabled with --enable-pthreadpool=no
    
    Tim, Steven, I haven't yet seen comments from you. You have been asking for
    such a thing at SambaXP. Do you like this? :-)

-----------------------------------------------------------------------

Summary of changes:
 source3/Makefile.in                        |    3 +-
 source3/configure.in                       |   15 +-
 source3/include/proto.h                    |   15 +
 source3/include/pthreadpool.h              |   42 +++
 source3/include/smb.h                      |    1 +
 source3/lib/fncall.c                       |  365 ++++++++++++++++++++
 source3/lib/pthreadpool.c                  |  505 ++++++++++++++++++++++++++++
 source3/lib/util_sock.c                    |   82 +++++
 source3/script/tests/test_smbtorture_s3.sh |    1 +
 source3/torture/torture.c                  |   55 +++
 10 files changed, 1082 insertions(+), 2 deletions(-)
 create mode 100644 source3/include/pthreadpool.h
 create mode 100644 source3/lib/fncall.c
 create mode 100644 source3/lib/pthreadpool.c


Changeset truncated at 500 lines:

diff --git a/source3/Makefile.in b/source3/Makefile.in
index 8bf29dd..171ff44 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -385,7 +385,8 @@ LIB_OBJ = $(LIBSAMBAUTIL_OBJ) $(UTIL_OBJ) $(CRYPTO_OBJ) \
 	  lib/module.o lib/events.o @LIBTEVENT_OBJ0@ \
 	  lib/ldap_escape.o @CHARSET_STATIC@ \
 	  lib/secdesc.o lib/util_seaccess.o ../libcli/security/secace.o \
-	  ../libcli/security/secacl.o \
+	  ../libcli/security/secacl.o @PTHREADPOOL_OBJ@ \
+	  lib/fncall.o \
 	  libads/krb5_errs.o lib/system_smbd.o lib/audit.o $(LIBNDR_OBJ) \
 	  lib/file_id.o lib/idmap_cache.o \
 	  ../libcli/security/dom_sid.o ../libcli/security/security_descriptor.o
diff --git a/source3/configure.in b/source3/configure.in
index 4ed9e68..fc925ee 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -5895,7 +5895,9 @@ else
 fi
 
 AC_CHECK_LIB(pthread, pthread_mutex_lock, [WINBIND_NSS_PTHREAD="-lpthread"
-			AC_DEFINE(HAVE_PTHREAD, 1, [whether pthread exists])])
+			AC_DEFINE(HAVE_PTHREAD, 1, [whether pthread exists])
+			samba_cv_HAVE_PTHREAD=yes],
+			samba_cv_HAVE_PTHREAD=no)
 
 AC_SUBST(WINBIND_NSS_PTHREAD)
 AC_SUBST(WINBIND_NSS)
@@ -6051,6 +6053,17 @@ if test x"$enable_avahi" != x"no"; then
 fi
 
 #################################################
+# Check if user wants pthreadpool support
+
+AC_ARG_ENABLE(pthreadpool,
+[AS_HELP_STRING([--enable-pthreadpool], [Enable pthreads pool helper support (default=auto)])])
+
+if test x"$enable_pthreadpool" != x"no" -a x"$samba_cv_HAVE_PTHREAD" = x"yes"; then
+    AC_DEFINE(WITH_PTHREADPOOL, 1, [Whether to include pthreadpool helpers])
+    AC_SUBST(PTHREADPOOL_OBJ, "lib/pthreadpool.o")
+fi
+
+#################################################
 # Check to see if we should use the included iniparser
 
 AC_ARG_WITH(included-iniparser,
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 0d52e00..936a724 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -1418,6 +1418,13 @@ struct tevent_req *read_smb_send(TALLOC_CTX *mem_ctx,
 				 int fd);
 ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
 		      uint8_t **pbuf, int *perrno);
+struct tevent_req *getaddrinfo_send(TALLOC_CTX *mem_ctx,
+				    struct tevent_context *ev,
+				    struct fncall_context *ctx,
+				    const char *node,
+				    const char *service,
+				    const struct addrinfo *hints);
+int getaddrinfo_recv(struct tevent_req *req, struct addrinfo **res);
 
 /* The following definitions come from lib/util_str.c  */
 
@@ -7098,4 +7105,12 @@ void *avahi_start_register(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 
 /* Misc protos */
 
+struct fncall_context *fncall_context_init(TALLOC_CTX *mem_ctx,
+					   int max_threads);
+struct tevent_req *fncall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct fncall_context *ctx,
+			       void (*fn)(void *private_data),
+			       void *private_data);
+int fncall_recv(struct tevent_req *req, int *perr);
+
 #endif /*  _PROTO_H_  */
diff --git a/source3/include/pthreadpool.h b/source3/include/pthreadpool.h
new file mode 100644
index 0000000..7ef7ddf
--- /dev/null
+++ b/source3/include/pthreadpool.h
@@ -0,0 +1,42 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * threadpool implementation based on pthreads
+ * Copyright (C) Volker Lendecke 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PTHREADPOOL_H__
+#define __PTHREADPOOL_H__
+
+struct pthreadpool;
+
+int pthreadpool_init(unsigned max_threads, struct pthreadpool **presult);
+int pthreadpool_destroy(struct pthreadpool *pool);
+
+/*
+ * Add a job to a pthreadpool.
+ */
+int pthreadpool_add_job(struct pthreadpool *pool, int job_id,
+			void (*fn)(void *private_data), void *private_data);
+
+/*
+ * Get the signalling fd out of a thread pool. This fd will become readable
+ * when a job is finished. The job that finished can be retrieved via
+ * pthreadpool_finished_job().
+ */
+int pthreadpool_sig_fd(struct pthreadpool *pool);
+int pthreadpool_finished_job(struct pthreadpool *pool);
+
+#endif
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 01e6ddf..5a381b3 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -365,6 +365,7 @@ struct named_mutex;
 struct pcap_cache;
 struct wb_context;
 struct rpc_cli_smbd_conn;
+struct fncall_context;
 
 struct vfs_fsp_data {
     struct vfs_fsp_data *next;
diff --git a/source3/lib/fncall.c b/source3/lib/fncall.c
new file mode 100644
index 0000000..e810b68
--- /dev/null
+++ b/source3/lib/fncall.c
@@ -0,0 +1,365 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Async fn calls
+ * Copyright (C) Volker Lendecke 2009
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#if WITH_PTHREADPOOL
+
+#include "pthreadpool.h"
+
+struct fncall_state {
+	struct fncall_context *ctx;
+	int job_id;
+	bool done;
+
+	void *private_parent;
+	void *job_private;
+};
+
+struct fncall_context {
+	struct pthreadpool *pool;
+	int next_job_id;
+	int sig_fd;
+	struct tevent_req **pending;
+
+	struct fncall_state **orphaned;
+	int num_orphaned;
+
+	struct fd_event *fde;
+};
+
+static void fncall_handler(struct tevent_context *ev, struct tevent_fd *fde,
+			   uint16_t flags, void *private_data);
+
+static int fncall_context_destructor(struct fncall_context *ctx)
+{
+	while (talloc_array_length(ctx->pending) != 0) {
+		/* No TALLOC_FREE here */
+		talloc_free(ctx->pending[0]);
+	}
+
+	while (ctx->num_orphaned != 0) {
+		/*
+		 * We've got jobs in the queue for which the tevent_req has
+		 * been finished already. Wait for all of them to finish.
+		 */
+		fncall_handler(NULL, NULL, TEVENT_FD_READ, ctx);
+	}
+
+	pthreadpool_destroy(ctx->pool);
+	ctx->pool = NULL;
+
+	return 0;
+}
+
+struct fncall_context *fncall_context_init(TALLOC_CTX *mem_ctx,
+					   int max_threads)
+{
+	struct fncall_context *ctx;
+	int ret;
+
+	ctx = talloc_zero(mem_ctx, struct fncall_context);
+	if (ctx == NULL) {
+		return NULL;
+	}
+
+	ret = pthreadpool_init(max_threads, &ctx->pool);
+	if (ret != 0) {
+		TALLOC_FREE(ctx);
+		return NULL;
+	}
+	talloc_set_destructor(ctx, fncall_context_destructor);
+
+	ctx->sig_fd = pthreadpool_sig_fd(ctx->pool);
+	if (ctx->sig_fd == -1) {
+		TALLOC_FREE(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+static int fncall_next_job_id(struct fncall_context *ctx)
+{
+	int num_pending = talloc_array_length(ctx->pending);
+	int result;
+
+	while (true) {
+		int i;
+
+		result = ctx->next_job_id++;
+		if (result == 0) {
+			continue;
+		}
+
+		for (i=0; i<num_pending; i++) {
+			struct fncall_state *state = tevent_req_data(
+				ctx->pending[i], struct fncall_state);
+
+			if (result == state->job_id) {
+				break;
+			}
+		}
+		if (i == num_pending) {
+			return result;
+		}
+	}
+}
+
+static void fncall_unset_pending(struct tevent_req *req);
+static int fncall_destructor(struct tevent_req *req);
+
+static bool fncall_set_pending(struct tevent_req *req,
+			       struct fncall_context *ctx,
+			       struct tevent_context *ev)
+{
+	struct tevent_req **pending;
+	int num_pending, orphaned_array_length;
+
+	num_pending = talloc_array_length(ctx->pending);
+
+	pending = talloc_realloc(ctx, ctx->pending, struct tevent_req *,
+				 num_pending+1);
+	if (pending == NULL) {
+		return false;
+	}
+	pending[num_pending] = req;
+	num_pending += 1;
+	ctx->pending = pending;
+	talloc_set_destructor(req, fncall_destructor);
+
+	/*
+	 * Make sure that the orphaned array of fncall_state structs has
+	 * enough space. A job can change from pending to orphaned in
+	 * fncall_destructor, and to fail in a talloc destructor should be
+	 * avoided if possible.
+	 */
+
+	orphaned_array_length = talloc_array_length(ctx->orphaned);
+	if (num_pending > orphaned_array_length) {
+		struct fncall_state **orphaned;
+
+		orphaned = talloc_realloc(ctx, ctx->orphaned,
+					  struct fncall_state *,
+					  orphaned_array_length + 1);
+		if (orphaned == NULL) {
+			fncall_unset_pending(req);
+			return false;
+		}
+		ctx->orphaned = orphaned;
+	}
+
+	if (ctx->fde != NULL) {
+		return true;
+	}
+
+	ctx->fde = tevent_add_fd(ev, ctx->pending, ctx->sig_fd, TEVENT_FD_READ,
+				 fncall_handler, ctx);
+	if (ctx->fde == NULL) {
+		fncall_unset_pending(req);
+		return false;
+	}
+	return true;
+}
+
+static void fncall_unset_pending(struct tevent_req *req)
+{
+	struct fncall_state *state = tevent_req_data(req, struct fncall_state);
+	struct fncall_context *ctx = state->ctx;
+	int num_pending = talloc_array_length(ctx->pending);
+	int i;
+
+	if (num_pending == 1) {
+		TALLOC_FREE(ctx->fde);
+		TALLOC_FREE(ctx->pending);
+		return;
+	}
+
+	for (i=0; i<num_pending; i++) {
+		if (req == ctx->pending[i]) {
+			break;
+		}
+	}
+	if (i == num_pending) {
+		return;
+	}
+	if (num_pending > 1) {
+		ctx->pending[i] = ctx->pending[num_pending-1];
+	}
+	ctx->pending = talloc_realloc(NULL, ctx->pending, struct tevent_req *,
+				      num_pending - 1);
+}
+
+static int fncall_destructor(struct tevent_req *req)
+{
+	struct fncall_state *state = tevent_req_data(
+		req, struct fncall_state);
+	struct fncall_context *ctx = state->ctx;
+
+	fncall_unset_pending(req);
+
+	if (state->done) {
+		return 0;
+	}
+
+	/*
+	 * Keep around the state of the deleted request until the request has
+	 * finished in the helper thread. fncall_handler will destroy it.
+	 */
+	ctx->orphaned[ctx->num_orphaned] = talloc_move(ctx->orphaned, &state);
+	ctx->num_orphaned += 1;
+
+	return 0;
+}
+
+struct tevent_req *fncall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct fncall_context *ctx,
+			       void (*fn)(void *private_data),
+			       void *private_data)
+{
+	struct tevent_req *req;
+	struct fncall_state *state;
+	int ret;
+
+	req = tevent_req_create(mem_ctx, &state, struct fncall_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ctx = ctx;
+	state->job_id = fncall_next_job_id(state->ctx);
+	state->done = false;
+
+	/*
+	 * We need to keep the private data we handed out to the thread around
+	 * as long as the job is not finished. This is a bit of an abstraction
+	 * violation, because the "req->state1->subreq->state2" (we're
+	 * "subreq", "req" is the request our caller creates) is broken to
+	 * "ctx->state2->state1", but we are right now in the destructor for
+	 * "subreq2", so what can we do. We need to keep state1 around,
+	 * otherwise the helper thread will have no place to put its results.
+	 */
+
+	state->private_parent = talloc_parent(private_data);
+	state->job_private = talloc_move(state, &private_data);
+
+	ret = pthreadpool_add_job(state->ctx->pool, state->job_id, fn,
+				  state->job_private);
+	if (ret == -1) {
+		tevent_req_error(req, errno);
+		return tevent_req_post(req, ev);
+	}
+	if (!fncall_set_pending(req, state->ctx, ev)) {
+		tevent_req_nomem(NULL, req);
+		return tevent_req_post(req, ev);
+	}
+	return req;
+}
+
+static void fncall_handler(struct tevent_context *ev, struct tevent_fd *fde,
+			   uint16_t flags, void *private_data)
+{
+	struct fncall_context *ctx = talloc_get_type_abort(
+		private_data, struct fncall_context);
+	int i, num_pending;
+	int job_id;
+
+	job_id = pthreadpool_finished_job(ctx->pool);
+	if (job_id <= 0) {
+		return;
+	}
+
+	num_pending = talloc_array_length(ctx->pending);
+
+	for (i=0; i<num_pending; i++) {
+		struct fncall_state *state = tevent_req_data(
+			ctx->pending[i], struct fncall_state);
+
+		if (job_id == state->job_id) {
+			state->done = true;
+			talloc_move(state->private_parent,
+				    &state->job_private);
+			tevent_req_done(ctx->pending[i]);
+			return;
+		}
+	}
+
+	for (i=0; i<ctx->num_orphaned; i++) {
+		if (job_id == ctx->orphaned[i]->job_id) {
+			break;
+		}
+	}
+	if (i == ctx->num_orphaned) {
+		return;
+	}
+
+	TALLOC_FREE(ctx->orphaned[i]);
+
+	if (i < ctx->num_orphaned-1) {
+		ctx->orphaned[i] = ctx->orphaned[ctx->num_orphaned-1];
+	}
+	ctx->num_orphaned -= 1;
+}
+
+int fncall_recv(struct tevent_req *req, int *perr)
+{
+	if (tevent_req_is_unix_error(req, perr)) {
+		return -1;
+	}
+	return 0;
+}
+
+#else  /* WITH_PTHREADPOOL */
+
+struct fncall_context {
+	uint8_t dummy;
+};
+
+struct fncall_context *fncall_context_init(TALLOC_CTX *mem_ctx,
+					   int max_threads)
+{
+	return talloc(mem_ctx, struct fncall_context);
+}
+
+struct fncall_state {
+	uint8_t dummy;
+};
+
+struct tevent_req *fncall_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+			       struct fncall_context *ctx,
+			       void (*fn)(void *private_data),
+			       void *private_data)
+{
+	struct tevent_req *req;
+	struct fncall_state *state;
+
+	req = tevent_req_create(mem_ctx, &state, struct fncall_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	fn(private_data);
+	tevent_req_post(req, ev);


-- 
Samba Shared Repository


More information about the samba-cvs mailing list