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 <[email protected]>
Date:   Sun Apr 26 00:01:43 2009 +0200

    Add getaddrinfo_send/recv

commit 8cf75770cf2b3905ca98c84b21fadca8e05f08b7
Author: Volker Lendecke <[email protected]>
Date:   Sat Apr 25 20:02:24 2009 +0200

    Add fncall_send/recv

commit db2cc8c9f2ec6f98884b1eb7738148cecdf6fd45
Author: Volker Lendecke <[email protected]>
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

Reply via email to