[SCM] Samba Shared Repository - branch v4-2-test updated

Karolin Seeger kseeger at samba.org
Mon Apr 18 13:45:03 UTC 2016


The branch, v4-2-test has been updated
       via  75f26e3 vfs_catia: Fix bug 11827, memleak
       via  b7e46c1 tevent: version 0.9.28
       via  a8fb85f lib: tevent: Fix memory leak reported by Pavel Březina <pbrezina at redhat.com> when old signal action restored.
       via  331383c tevent: version 0.9.27
       via  c496c85 Fix ETIME handling for Solaris event ports.
       via  a10d492 tevent: Only set public headers field when installing as a public library.
       via  0345678 Simplify handling of dependencies on external libraries in test_headers.
       via  06a87da lib: tevent: Whitespace cleanup.
       via  1ca26ea lib: tevent: Fix bug in poll backend - poll_event_loop_poll()
       via  316ce07 tevent: version 0.9.26
       via  78f5f86 lib: tevent: docs: Add tutorial on thread usage.
       via  b88f6e9 lib: tevent: tests: Add a second thread test that does request/reply.
       via  a050245 lib: tevent: Initial test of tevent threaded context code.
       via  46d3bb7 lib: tevent: Initial checkin of threaded tevent context calling code.
      from  4882bde VERSION: Bump version up to 4.2.12

https://git.samba.org/?p=samba.git;a=shortlog;h=v4-2-test


- Log -----------------------------------------------------------------
commit 75f26e36f159035def45cc1aea178388279e6bfc
Author: Volker Lendecke <vl at samba.org>
Date:   Sun Apr 10 12:51:15 2016 +0200

    vfs_catia: Fix bug 11827, memleak
    
    add_srt should add the mappings to the linked list even if
    mappings==NULL (the default)
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11827
    Signed-off-by: Volker Lendecke <vl at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    
    Autobuild-User(master): Ralph Böhme <slow at samba.org>
    Autobuild-Date(master): Mon Apr 11 14:25:59 CEST 2016 on sn-devel-144
    
    (cherry picked from commit 3e2af1568d150de1cb12fef40580f4880ac787ff)
    
    Autobuild-User(v4-2-test): Karolin Seeger <kseeger at samba.org>
    Autobuild-Date(v4-2-test): Mon Apr 18 15:44:50 CEST 2016 on sn-devel-104

commit b7e46c14ea56e7827b00436b2c9180bfb5dc9713
Author: Stefan Metzmacher <metze at samba.org>
Date:   Fri Feb 19 11:46:03 2016 +0100

    tevent: version 0.9.28
    
    * Fix memory leak when old signal action restored (bug #11742)
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>
    
    Autobuild-User(master): Stefan Metzmacher <metze at samba.org>
    Autobuild-Date(master): Fri Feb 19 19:12:25 CET 2016 on sn-devel-144
    
    (cherry picked from commit da74d0c317be9ce67eb5d00d232167d466f68a1e)
    
    The last 12 patches addressed bug #11771:
    Backport tevent-0.9.28.

commit a8fb85f79ddbc0aafb39ffe31a74b5c233056890
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Feb 16 14:23:53 2016 -0800

    lib: tevent: Fix memory leak reported by Pavel Březina <pbrezina at redhat.com> when old signal action restored.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=11742
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Andreas Schneider <asn at samba.org>
    
    Autobuild-User(master): Andreas Schneider <asn at cryptomilk.org>
    Autobuild-Date(master): Thu Feb 18 01:42:50 CET 2016 on sn-devel-144
    
    (cherry picked from commit 833a2f474367624dd9980abb28227850e95fe976)

commit 331383cba3f32cff93e56dd4373a46e0cc0d4e61
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Feb 15 11:40:34 2016 +0100

    tevent: version 0.9.27
    
    * Fix bug in poll backend - poll_event_loop_poll()
      exits the for loop on POLLNVAL instead of
      continuing to find an event that is ready.
    * Fix ETIME handling for Solaris event ports (bug #11728).
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    Reviewed-by: Michael Adam <obnox at samba.org>
    
    Autobuild-User(master): Michael Adam <obnox at samba.org>
    Autobuild-Date(master): Tue Feb 16 00:00:51 CET 2016 on sn-devel-144
    
    (cherry picked from commit 2267faddfa9863b205dfad580fbd45182916cb32)

commit c496c8549383384b2277cfe7d5f150ba0c5f80d5
Author: Nathan Huff <nhuff at acm.org>
Date:   Fri Feb 5 13:35:07 2016 -0700

    Fix ETIME handling for Solaris event ports.
    
    It is possible for port_getn to return -1 with errno set to ETIME and
    still return events. If those events aren't processed the association is
    lost by samba since the kernel dissacociated them and samba never
    processed them so never reassociated them with the event port. The
    patch checks the nget return value in the case of ETIME and if it is non
    0 it doesn't return and goes through the event processing loop.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Nathan Huff <nhuff at acm.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Ralph Böhme <slow at samba.org>
    Autobuild-Date(master): Sun Feb  7 11:26:35 CET 2016 on sn-devel-144
    
    (cherry picked from commit 4953b1f73f8ec9387516be1058434d71937e1447)

commit a10d492314e8920f24b3bca7286807864350f05d
Author: Jelmer Vernooij <jelmer at jelmer.uk>
Date:   Mon Jan 4 23:01:26 2016 +0000

    tevent: Only set public headers field when installing as a public library.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Jelmer Vernooij <jelmer at jelmer.uk>
    (cherry picked from commit 2cba4918dbe82fb9d0455c73d35aa551dccc924f)

commit 034567814b9c2be4166b4671ff525bcd622276bf
Author: Jelmer Vernooij <jelmer at jelmer.uk>
Date:   Sat Jan 9 20:25:17 2016 +0000

    Simplify handling of dependencies on external libraries in test_headers.
    
    Signed-off-by: Jelmer Vernooij <jelmer at jelmer.uk>
    (cherry picked from commit 3123e2c66a29aaabad7408107bcf4a0e841a93ec)

commit 06a87da2da506bd17b965641e45eae126df12365
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Nov 17 09:13:41 2015 -0800

    lib: tevent: Whitespace cleanup.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Volker Lendecke <vl at samba.org>
    
    Autobuild-User(master): Volker Lendecke <vl at samba.org>
    Autobuild-Date(master): Wed Nov 18 15:54:03 CET 2015 on sn-devel-104
    
    (cherry picked from commit 39d0a81ed87c58836335ec10af22b36c9961f91e)

commit 1ca26eae75780a789559158ecec1afaa93f5dff4
Author: Jeremy Allison <jra at samba.org>
Date:   Tue Nov 17 10:28:50 2015 -0800

    lib: tevent: Fix bug in poll backend - poll_event_loop_poll()
    
    If the (pfd->revents & POLLNVAL) case is triggered,
    we do DLIST_REMOVE(ev->fd_events, fde); and then
    use fde->next in the loop above.
    
    Save off fde->next for loop interation before
    this so we can't use a deleted ->next value.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Volker Lendecke <vl at samba.org>
    (cherry picked from commit 2be3dd1407eabe3df360ede2eab178848e34733c)

commit 316ce07af065996c1c74344556e984e8018b9af3
Author: Stefan Metzmacher <metze at samba.org>
Date:   Mon Aug 24 15:47:51 2015 +0200

    tevent: version 0.9.26
    
    * New tevent_thread_proxy API
    * Minor build fixes
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 9884a8fa58ffc8ddff0977c069aedda3beb6415f)

commit 78f5f86ea5b4a90290571832f355b3039c236661
Author: Jeremy Allison <jra at samba.org>
Date:   Wed Jul 22 11:52:06 2015 -0700

    lib: tevent: docs: Add tutorial on thread usage.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Signed-off-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 68077c617b0a456baea56349fbf502307318c487)

commit b88f6e91cefa6bf885f8404d286840b9105aa678
Author: Jeremy Allison <jra at samba.org>
Date:   Fri Jul 24 09:27:21 2015 -0700

    lib: tevent: tests: Add a second thread test that does request/reply.
    
    Both tests run cleanly with valgrind --tool=drd and
    valgrind --tool=helgrind
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Signed-off-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit a132320b4c434ae9c2188377951d092f7309e63c)

commit a0502456a6479e8557566d361561dc8f9544229a
Author: Jeremy Allison <jra at samba.org>
Date:   Fri Jul 24 08:50:31 2015 -0700

    lib: tevent: Initial test of tevent threaded context code.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Signed-off-by: Ralph Boehme <slow at samba.org>
    (cherry picked from commit 187aebb25b970a3679a72109def8e8b85622722e)

commit 46d3bb7b8360ef36c80031752c7581a747d5a569
Author: Jeremy Allison <jra at samba.org>
Date:   Thu Jul 23 15:23:50 2015 -0700

    lib: tevent: Initial checkin of threaded tevent context calling code.
    
    Adds 2 new functions:
    
    struct tevent_thread_proxy *tevent_thread_proxy_create(
                    struct tevent_context *dest_ev_ctx);
    
    void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
    		struct tevent_immediate **pp_im,
    		tevent_immediate_handler_t handler,
    		void *pp_private_data);
    
    Brief doc included. Tests, docs and tutorial to follow.
    
    Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    (cherry picked from commit 49bddd8e4756ef52b05b850aec4864749fcf31cb)

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

Summary of changes:
 .../ABI/{tevent-0.9.24.sigs => tevent-0.9.26.sigs} |   2 +
 .../ABI/{tevent-0.9.24.sigs => tevent-0.9.27.sigs} |   2 +
 .../ABI/{tevent-0.9.24.sigs => tevent-0.9.28.sigs} |   2 +
 lib/tevent/doc/tevent_thread.dox                   | 322 ++++++++++++++++++
 lib/tevent/doc/tevent_tutorial.dox                 |   2 +
 lib/tevent/testsuite.c                             | 330 ++++++++++++++++++
 lib/tevent/tevent.h                                |  52 +++
 lib/tevent/tevent_epoll.c                          |   6 +-
 lib/tevent/tevent_poll.c                           |   5 +-
 lib/tevent/tevent_port.c                           |  22 +-
 lib/tevent/tevent_signal.c                         |   4 +
 lib/tevent/tevent_threads.c                        | 370 +++++++++++++++++++++
 lib/tevent/wscript                                 |   6 +-
 source3/modules/vfs_catia.c                        |   6 +-
 testsuite/headers/wscript_build                    |  13 +-
 15 files changed, 1119 insertions(+), 25 deletions(-)
 copy lib/tevent/ABI/{tevent-0.9.24.sigs => tevent-0.9.26.sigs} (97%)
 copy lib/tevent/ABI/{tevent-0.9.24.sigs => tevent-0.9.27.sigs} (97%)
 copy lib/tevent/ABI/{tevent-0.9.24.sigs => tevent-0.9.28.sigs} (97%)
 create mode 100644 lib/tevent/doc/tevent_thread.dox
 create mode 100644 lib/tevent/tevent_threads.c


Changeset truncated at 500 lines:

diff --git a/lib/tevent/ABI/tevent-0.9.24.sigs b/lib/tevent/ABI/tevent-0.9.26.sigs
similarity index 97%
copy from lib/tevent/ABI/tevent-0.9.24.sigs
copy to lib/tevent/ABI/tevent-0.9.26.sigs
index d8b9f4b..1357751 100644
--- a/lib/tevent/ABI/tevent-0.9.24.sigs
+++ b/lib/tevent/ABI/tevent-0.9.26.sigs
@@ -75,6 +75,8 @@ tevent_set_debug_stderr: int (struct tevent_context *)
 tevent_set_default_backend: void (const char *)
 tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
 tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
 tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
 tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
 tevent_timeval_current: struct timeval (void)
diff --git a/lib/tevent/ABI/tevent-0.9.24.sigs b/lib/tevent/ABI/tevent-0.9.27.sigs
similarity index 97%
copy from lib/tevent/ABI/tevent-0.9.24.sigs
copy to lib/tevent/ABI/tevent-0.9.27.sigs
index d8b9f4b..1357751 100644
--- a/lib/tevent/ABI/tevent-0.9.24.sigs
+++ b/lib/tevent/ABI/tevent-0.9.27.sigs
@@ -75,6 +75,8 @@ tevent_set_debug_stderr: int (struct tevent_context *)
 tevent_set_default_backend: void (const char *)
 tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
 tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
 tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
 tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
 tevent_timeval_current: struct timeval (void)
diff --git a/lib/tevent/ABI/tevent-0.9.24.sigs b/lib/tevent/ABI/tevent-0.9.28.sigs
similarity index 97%
copy from lib/tevent/ABI/tevent-0.9.24.sigs
copy to lib/tevent/ABI/tevent-0.9.28.sigs
index d8b9f4b..1357751 100644
--- a/lib/tevent/ABI/tevent-0.9.24.sigs
+++ b/lib/tevent/ABI/tevent-0.9.28.sigs
@@ -75,6 +75,8 @@ tevent_set_debug_stderr: int (struct tevent_context *)
 tevent_set_default_backend: void (const char *)
 tevent_set_trace_callback: void (struct tevent_context *, tevent_trace_callback_t, void *)
 tevent_signal_support: bool (struct tevent_context *)
+tevent_thread_proxy_create: struct tevent_thread_proxy *(struct tevent_context *)
+tevent_thread_proxy_schedule: void (struct tevent_thread_proxy *, struct tevent_immediate **, tevent_immediate_handler_t, void *)
 tevent_timeval_add: struct timeval (const struct timeval *, uint32_t, uint32_t)
 tevent_timeval_compare: int (const struct timeval *, const struct timeval *)
 tevent_timeval_current: struct timeval (void)
diff --git a/lib/tevent/doc/tevent_thread.dox b/lib/tevent/doc/tevent_thread.dox
new file mode 100644
index 0000000..7b45820
--- /dev/null
+++ b/lib/tevent/doc/tevent_thread.dox
@@ -0,0 +1,322 @@
+/**
+ at page tevent_context Chapter 6: Tevent with threads
+
+ at section context Tevent with threads
+
+In order to use tevent with threads, you must first understand
+how to use the talloc library in threaded programs. For more
+information about working with talloc, please visit <a
+href="https://talloc.samba.org/">talloc website</a> where tutorial and
+documentation are located.
+
+If a tevent context structure is talloced from a NULL, thread-safe talloc
+context, then it can be safe to use in a threaded program. The function
+<code>talloc_disable_null_tracking()</code> <b>must</b> be called from the initial
+program thread before any talloc calls are made to ensure talloc is thread-safe.
+
+Each thread must create it's own tevent context structure as follows
+<code>tevent_context_init(NULL)</code> and no talloc memory contexts
+can be shared between threads.
+
+Separate threads using tevent in this way can communicate
+by writing data into file descriptors that are being monitored
+by a tevent context on another thread. For example (simplified
+with no error handling):
+
+ at code
+Main thread:
+
+main()
+{
+	talloc_disable_null_tracking();
+
+	struct tevent_context *master_ev = tevent_context_init(NULL);
+	void *mem_ctx = talloc_new(master_ev);
+
+	// Create file descriptor to monitor.
+	int pipefds[2];
+
+	pipe(pipefds);
+
+	struct tevent_fd *fde = tevent_add_fd(master_ev,
+				mem_ctx,
+				pipefds[0], // read side of pipe
+				TEVENT_FD_READ,
+				pipe_read_handler, // callback function
+				private_data_pointer);
+
+	// Create sub thread, pass pipefds[1] write side of pipe to it.
+	// The above code not shown here..
+
+	// Process events.
+	tevent_loop_wait(master_ev);
+
+	// Cleanup if loop exits.
+	talloc_free(master_ev);
+}
+
+ at endcode
+
+When the subthread writes to pipefds[1], the function
+<code>pipe_read_handler()</code> will be called in the main thread.
+
+ at subsection More sophisticated use
+
+A popular way to use an event library within threaded programs
+is to allow a sub-thread to asynchronously schedule a tevent_immediate
+function call from the event loop of another thread. This can be built
+out of the basic functions and isolation mechanisms of tevent,
+but tevent also comes with some utility functions that make
+this easier, so long as you understand the limitations that
+using threads with talloc and tevent impose.
+
+To allow a tevent context to receive an asynchronous tevent_immediate
+function callback from another thread, create a struct tevent_thread_proxy *
+by calling @code
+
+struct tevent_thread_proxy *tevent_thread_proxy_create(
+                struct tevent_context *dest_ev_ctx);
+
+ at endcode
+
+This function allocates the internal data structures to
+allow asynchronous callbacks as a talloc child of the
+struct tevent_context *, and returns a struct tevent_thread_proxy *
+that can be passed to another thread.
+
+When you have finished receiving asynchronous callbacks, simply
+talloc_free the struct tevent_thread_proxy *, or talloc_free
+the struct tevent_context *, which will deallocate the resources
+used.
+
+To schedule an asynchronous tevent_immediate function call from one
+thread on the tevent loop of another thread, use
+ at code
+
+void tevent_thread_proxy_schedule(struct tevent_thread_proxy *tp,
+                                struct tevent_immediate **pp_im,
+                                tevent_immediate_handler_t handler,
+                                void **pp_private_data);
+
+ at endcode
+
+This function causes the function <code>handler()</code>
+to be invoked as a tevent_immediate callback from the event loop
+of the thread that created the struct tevent_thread_proxy *
+(so the owning <code>struct tevent_context *</code> should be
+long-lived and not in the process of being torn down).
+
+The <code>struct tevent_thread_proxy</code> object being
+used here is a child of the event context of the target
+thread. So external synchronization mechanisms must be
+used to ensure that the target object is still in use
+at the time of the <code>tevent_thread_proxy_schedule()</code>
+call. In the example below, the request/response nature
+of the communication ensures this.
+
+The <code>struct tevent_immediate **pp_im</code> passed into this function
+should be a struct tevent_immediate * allocated on a talloc context
+local to this thread, and will be reparented via talloc_move
+to be owned by <code>struct tevent_thread_proxy *tp</code>.
+<code>*pp_im</code> will be set to NULL on successful scheduling
+of the tevent_immediate call.
+
+<code>handler()</code> will be called as a normal tevent_immediate
+callback from the <code>struct tevent_context *</code> of the destination
+event loop that created the <code>struct tevent_thread_proxy *</code>
+
+Returning from this functions does not mean that the <code>handler</code>
+has been invoked, merely that it has been scheduled to be called in the
+destination event loop.
+
+Because the calling thread does not wait for the
+callback to be scheduled and run on the destination
+thread, this is a fire-and-forget call. If you wish
+confirmation of the <code>handler()</code> being
+successfully invoked, you must ensure it replies to the
+caller in some way.
+
+Because of asynchronous nature of this call, the nature
+of the parameter passed to the destination thread has some
+restructions. If you don't need parameters, merely pass
+<code>NULL</code> as the value of
+<code>void **pp_private_data</code>.
+
+If you wish to pass a pointer to data between the threads,
+it <b>MUST</b> be a pointer to a talloced pointer, which is
+not part of a talloc-pool, and it must not have a destructor
+attached. The ownership of the memory pointed to will
+be passed from the calling thread to the tevent library,
+and if the receiving thread does not talloc-reparent
+it to its own contexts, it will be freed once the
+<code>handler</code> is called.
+
+On success, <code>*pp_private</code> will be <code>NULL</code>
+to signify the talloc memory ownership has been moved.
+
+In practice for message passing between threads in
+event loops these restrictions are not very onerous.
+
+The easiest way to to a request-reply pair between
+tevent loops on different threads is to pass the
+parameter block of memory back and forth using
+a reply <code>tevent_thread_proxy_schedule()</code>
+call.
+
+Here is an example (without error checking for
+simplicity):
+
+ at code
+------------------------------------------------
+// Master thread.
+
+main()
+{
+	// Make talloc thread-safe.
+
+	talloc_disable_null_tracking();
+
+	// Create the master event context.
+
+	struct tevent_context *master_ev = tevent_context_init(NULL);
+
+	// Create the master thread proxy to allow it to receive
+	// async callbacks from other threads.
+
+	struct tevent_thread_proxy *master_tp =
+			tevent_thread_proxy_create(master_ev);
+
+	// Create sub-threads, passing master_tp in
+	// some way to them.
+	// This code not shown..
+
+	// Process events.
+	// Function master_callback() below
+	// will be invoked on this thread on
+	// master_ev event context.
+
+	tevent_loop_wait(master_ev);
+
+	// Cleanup if loop exits.
+
+	talloc_free(master_ev);
+}
+
+// Data passed between threads.
+struct reply_state {
+	struct tevent_thread_proxy *reply_tp;
+	pthread_t thread_id;
+	bool *p_finished;
+};
+
+// Callback Called in child thread context.
+
+static void thread_callback(struct tevent_context *ev,
+                                struct tevent_immediate *im,
+                                void *private_ptr)
+{
+	// Move the ownership of what private_ptr
+	// points to from the tevent library back to this thread.
+
+	struct reply_state *rsp =
+		talloc_get_type_abort(private_ptr, struct reply_state);
+
+	talloc_steal(ev, rsp);
+
+	*rsp->p_finished = true;
+
+	// im will be talloc_freed on return from this call.
+	// but rsp will not.
+}
+
+// Callback Called in master thread context.
+
+static void master_callback(struct tevent_context *ev,
+                                struct tevent_immediate *im,
+                                void *private_ptr)
+{
+	// Move the ownership of what private_ptr
+	// points to from the tevent library to this thread.
+
+	struct reply_state *rsp =
+		talloc_get_type_abort(private_ptr, struct reply_state);
+
+	talloc_steal(ev, rsp);
+
+	printf("Callback from thread %s\n", thread_id_to_string(rsp->thread_id));
+
+	/* Now reply to the thread ! */
+	tevent_thread_proxy_schedule(rsp->reply_tp,
+				&im,
+				thread_callback,
+				&rsp);
+
+	// Note - rsp and im are now NULL as the tevent library
+	// owns the memory.
+}
+
+// Child thread.
+
+static void *thread_fn(void *private_ptr)
+{
+	struct tevent_thread_proxy *master_tp =
+		talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+	bool finished = false;
+	int ret;
+
+	// Create our own event context.
+
+	struct tevent_context *ev = tevent_context_init(NULL);
+
+	// Create the local thread proxy to allow us to receive
+	// async callbacks from other threads.
+
+	struct tevent_thread_proxy *local_tp =
+			tevent_thread_proxy_create(master_ev);
+
+	// Setup the data to send.
+
+	struct reply_state *rsp = talloc(ev, struct reply_state);
+
+	rsp->reply_tp = local_tp;
+	rsp->thread_id = pthread_self();
+	rsp->p_finished = &finished;
+
+	// Create the immediate event to use.
+
+	struct tevent_immediate *im = tevent_create_immediate(ev);
+
+	// Call the master thread.
+
+	tevent_thread_proxy_schedule(master_tp,
+				&im,
+				master_callback,
+				&rsp);
+
+	// Note - rsp and im are now NULL as the tevent library
+	// owns the memory.
+
+	// Wait for the reply.
+
+	while (!finished) {
+		tevent_loop_once(ev);
+	}
+
+	// Cleanup.
+
+	talloc_free(ev);
+	return NULL;
+}
+
+ at endcode
+
+Note this doesn't have to be a master-subthread communication.
+Any thread that has access to the <code>struct tevent_thread_proxy *</code>
+pointer of another thread that has called <code>tevent_thread_proxy_create()
+</code> can send an async tevent_immediate request.
+
+But remember the caveat that external synchronization must be used
+to ensure the target <code>struct tevent_thread_proxy *</code> object
+exists at the time of the <code>tevent_thread_proxy_schedule()</code>
+call or unreproducible crashes will result.
+*/
diff --git a/lib/tevent/doc/tevent_tutorial.dox b/lib/tevent/doc/tevent_tutorial.dox
index 9f01fa1..207a244 100644
--- a/lib/tevent/doc/tevent_tutorial.dox
+++ b/lib/tevent/doc/tevent_tutorial.dox
@@ -17,4 +17,6 @@ Tutorial describing working with tevent library.
 
 @subpage tevent_queue
 
+ at subpage tevent_thread
+
 */
diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c
index c63c878..bcd27fd 100644
--- a/lib/tevent/testsuite.c
+++ b/lib/tevent/testsuite.c
@@ -808,6 +808,327 @@ static bool test_event_context_threaded(struct torture_context *test,
 	return true;
 }
 
+#define NUM_TEVENT_THREADS 100
+
+/* Ugly, but needed for torture_comment... */
+static struct torture_context *thread_test_ctx;
+static pthread_t thread_map[NUM_TEVENT_THREADS];
+static unsigned thread_counter;
+
+/* Called in master thread context */
+static void callback_nowait(struct tevent_context *ev,
+				struct tevent_immediate *im,
+				void *private_ptr)
+{
+	pthread_t *thread_id_ptr =
+		talloc_get_type_abort(private_ptr, pthread_t);
+	unsigned i;
+
+	for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+		if (pthread_equal(*thread_id_ptr,
+				thread_map[i])) {
+			break;
+		}
+	}
+	torture_comment(thread_test_ctx,
+			"Callback %u from thread %u\n",
+			thread_counter,
+			i);
+	thread_counter++;
+}
+
+/* Blast the master tevent_context with a callback, no waiting. */
+static void *thread_fn_nowait(void *private_ptr)
+{
+	struct tevent_thread_proxy *master_tp =
+		talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
+	struct tevent_immediate *im;
+	pthread_t *thread_id_ptr;
+
+	im = tevent_create_immediate(NULL);
+	if (im == NULL) {
+		return NULL;
+	}
+	thread_id_ptr = talloc(NULL, pthread_t);
+	if (thread_id_ptr == NULL) {
+		return NULL;
+	}
+	*thread_id_ptr = pthread_self();
+
+	tevent_thread_proxy_schedule(master_tp,
+				&im,
+				callback_nowait,
+				&thread_id_ptr);
+	return NULL;
+}
+
+static void timeout_fn(struct tevent_context *ev,
+			struct tevent_timer *te,
+			struct timeval tv, void *p)
+{
+	thread_counter = NUM_TEVENT_THREADS * 10;
+}
+
+static bool test_multi_tevent_threaded(struct torture_context *test,
+					const void *test_data)
+{
+	unsigned i;
+	struct tevent_context *master_ev;
+	struct tevent_thread_proxy *tp;
+
+	talloc_disable_null_tracking();
+
+	/* Ugly global stuff. */
+	thread_test_ctx = test;
+	thread_counter = 0;
+
+	master_ev = tevent_context_init(NULL);
+	if (master_ev == NULL) {
+		return false;
+	}
+	tevent_set_debug_stderr(master_ev);
+
+	tp = tevent_thread_proxy_create(master_ev);
+	if (tp == NULL) {
+		torture_fail(test,
+			talloc_asprintf(test,
+				"tevent_thread_proxy_create failed\n"));
+		talloc_free(master_ev);
+		return false;
+	}
+
+	for (i = 0; i < NUM_TEVENT_THREADS; i++) {
+		int ret = pthread_create(&thread_map[i],
+				NULL,
+				thread_fn_nowait,
+				tp);
+		if (ret != 0) {
+			torture_fail(test,
+				talloc_asprintf(test,
+					"Failed to create thread %i, %d\n",
+					i, ret));
+			return false;
+		}
+	}
+
+	/* Ensure we don't wait more than 10 seconds. */
+	tevent_add_timer(master_ev,


-- 
Samba Shared Repository



More information about the samba-cvs mailing list