[PATCH] tevent glib event loop glue
Ralph Boehme
rb at sernet.de
Mon Feb 15 15:56:21 UTC 2016
Hi metze,
On Sat, Feb 13, 2016 at 09:38:19AM +0100, Stefan Metzmacher wrote:
> > Attached is a patchset that adds support for polling a glib
> > g_main_context from tevent. Later commits make use of it in the mdsvc
> > RPC server.
> >
> > The second patch adds a test binary that can be used to run query
> > Gnome Tracker either using the native glib event loop or tevent.
> >
> > I'm still unsure whether we want this added directly to tevent at this
> > early stage, or instead better put it to source3/lib/. It makes no
> > difference for Samba internal consumers.
>
> I'd prefer to keep in Samba only for now (as
> lib/util/tevent_glib_glue.[ch]) and adding a 'samba_' prefix to the
> public function,so that we won't conflict, if we later also add this
> to tevent.
Updated patchset attached.
Please review&push if ok. Thanks!
-Ralph
--
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de,mailto:kontakt@sernet.de
-------------- next part --------------
From 5675c0f0fce2c683f5a98dc98405b500b713fcf8 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Mon, 15 Feb 2016 10:42:52 +0100
Subject: [PATCH 1/6] s3: build: seperate out check for Gnome Tracker from
Spotlight
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/wscript | 31 +++++++++++++++++--------------
1 file changed, 17 insertions(+), 14 deletions(-)
diff --git a/source3/wscript b/source3/wscript
index d9e10c0..8e23621 100644
--- a/source3/wscript
+++ b/source3/wscript
@@ -1544,23 +1544,26 @@ main() {
conf.fatal('AFS headers not available, but --with-fake-kaserver was specified')
conf.env['libtracker']=''
+ tracker_versions = ['1.0', '0.16', '0.14']
+
+ for version in tracker_versions:
+ testlib = 'tracker-sparql-' + version
+ if conf.CHECK_CFG(package=testlib,
+ args='--cflags --libs',
+ mandatory=False):
+ conf.SET_TARGET_TYPE(testlib, 'SYSLIB')
+ conf.env['libtracker'] = testlib
+ conf.DEFINE('HAVE_TRACKER', '1')
+ break
+
conf.env.with_spotlight = False
if Options.options.with_spotlight:
- versions = ['1.0', '0.16', '0.14']
- for version in versions:
- testlib = 'tracker-sparql-' + version
- if conf.CHECK_CFG(package=testlib,
- args='--cflags --libs',
- mandatory=False):
- conf.SET_TARGET_TYPE(testlib, 'SYSLIB')
- conf.env['libtracker'] = testlib
- conf.env.with_spotlight = True
- conf.DEFINE('WITH_SPOTLIGHT', '1')
- break
-
- if not conf.env.with_spotlight:
- conf.fatal("Spotlight support requested but tracker-sparql library missing")
+ if not conf.CONFIG_SET('HAVE_TRACKER'):
+ conf.fatal('Missing Gnome Tracker development files')
+
Logs.info("building with Spotlight support")
+ conf.DEFINE('WITH_SPOTLIGHT', '1')
+ conf.env.with_spotlight = True
forced_static_modules.extend(TO_LIST('auth_domain auth_builtin auth_sam auth_winbind'))
default_static_modules.extend(TO_LIST('''pdb_smbpasswd pdb_tdbsam pdb_wbc_sam
--
2.5.0
From f35b81cd7149dc88eb23b98a0fce704d770d7d98 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 20 Jan 2016 15:08:31 +0100
Subject: [PATCH 2/6] s3/lib: new tevent_glib_glue subsystem
tevent_glib_glue_create() takes glib GMainContext and adds its event
sources to a tevent context. tevent will poll the sources and run
handlers for pending events as detailed in the glib documentation:
https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html
If Samba was built without glib support, the function will always return
NULL with an error number ENOSYS.
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/lib/tevent_glib_glue.c | 694 +++++++++++++++++++++++++++++++++++++++++
source3/lib/tevent_glib_glue.h | 70 +++++
source3/wscript | 13 +
source3/wscript_build | 5 +
4 files changed, 782 insertions(+)
create mode 100644 source3/lib/tevent_glib_glue.c
create mode 100644 source3/lib/tevent_glib_glue.h
diff --git a/source3/lib/tevent_glib_glue.c b/source3/lib/tevent_glib_glue.c
new file mode 100644
index 0000000..3e2ed67
--- /dev/null
+++ b/source3/lib/tevent_glib_glue.c
@@ -0,0 +1,694 @@
+/*
+ Unix SMB/CIFS implementation.
+ Integration of a glib g_main_context into a tevent_context
+ Copyright (C) Stefan Metzmacher 2016
+ Copyright (C) Ralph Boehme 2016
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "tevent_glib_glue.h"
+#include "system/filesys.h"
+#include "system/select.h"
+#include "lib/util/debug.h"
+#include <tevent.h>
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_TEVENT
+
+#ifdef HAVE_GLIB
+
+#include <glib.h>
+
+struct tevent_fd_map {
+ int fd;
+ struct tevent_fd *fd_event;
+};
+
+struct tevent_glib_glue {
+ struct tevent_context *ev;
+ GMainContext *gmain_ctx;
+ bool quit;
+
+ struct tevent_timer *retry_timer;
+ gint gtimeout;
+ gint gpriority;
+ GPollFD *gpollfds;
+ gint num_gpollfds;
+ GPollFD *prev_gpollfds;
+ gint num_prev_gpollfds;
+
+ struct tevent_fd_map *fd_map;
+ size_t num_maps;
+ struct tevent_timer *timer;
+ struct tevent_immediate *im;
+ bool scheduled_im;
+ struct pollfd *pollfds;
+};
+
+static bool tevent_glib_prepare(struct tevent_glib_glue *glue);
+static bool tevent_glib_process(struct tevent_glib_glue *glue);
+static void tevent_glib_glue_cleanup(struct tevent_glib_glue *glue);
+static void tevent_glib_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+
+typedef int (*gfds_cmp_cb)(const void *fd1, const void *fd2);
+typedef bool (*gfds_found_cb)(struct tevent_glib_glue *glue,
+ const GPollFD *new, const GPollFD *old);
+typedef bool (*gfds_new_cb)(struct tevent_glib_glue *glue, const GPollFD *fd);
+typedef bool (*gfds_removed_cb)(struct tevent_glib_glue *glue, const GPollFD *fd);
+
+/**
+ * Compare two GPollFD arrays
+ *
+ * For every element that exists in gfds and prev_gfds found_fn() is called.
+ * For every element in gfds but not in prev_gfds, new_fn() is called.
+ * For every element in prev_gfds but not in gfds removed_fn() is called.
+ **/
+static bool cmp_gfds(struct tevent_glib_glue *glue,
+ GPollFD *gfds, GPollFD *prev_gfds,
+ size_t num_gfds, size_t num_prev_gfds,
+ gfds_cmp_cb cmp_cb,
+ gfds_found_cb found_cb,
+ gfds_new_cb new_cb,
+ gfds_removed_cb removed_cb)
+{
+ bool ok;
+ size_t i = 0, j = 0;
+ int cmp;
+
+ while (i < num_gfds && j < num_prev_gfds) {
+ cmp = cmp_cb(&gfds[i], &prev_gfds[j]);
+ if (cmp == 0) {
+ ok = found_cb(glue, &gfds[i], &prev_gfds[j]);
+ if (!ok) {
+ return false;
+ }
+ i++;
+ j++;
+ } else if (cmp < 0) {
+ ok = new_cb(glue, &gfds[i]);
+ if (!ok) {
+ return false;
+ }
+ i++;
+ } else {
+ ok = removed_cb(glue, &prev_gfds[j]);
+ if (!ok) {
+ return false;
+ }
+ j++;
+ }
+ }
+
+ while (i < num_gfds) {
+ ok = new_cb(glue, &gfds[i++]);
+ if (!ok) {
+ return false;
+ }
+ }
+
+ while (j < num_prev_gfds) {
+ ok = removed_cb(glue, &prev_gfds[j++]);
+ if (!ok) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int glib_fd_cmp_func(const void *p1, const void *p2)
+{
+ const GPollFD *lhs = p1;
+ const GPollFD *rhs = p2;
+
+ if (lhs->fd < rhs->fd) {
+ return -1;
+ } else if (lhs->fd > rhs->fd) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static bool match_gfd_cb(struct tevent_glib_glue *glue,
+ const GPollFD *new_gfd,
+ const GPollFD *old_gfd)
+{
+ size_t i;
+ struct tevent_fd *fd_event = NULL;
+
+ if (new_gfd->events == old_gfd->events) {
+ return true;
+ }
+
+ for (i = 0; i < glue->num_maps; i++) {
+ if (glue->fd_map[i].fd == new_gfd->fd) {
+ break;
+ }
+ }
+
+ if (i == glue->num_maps) {
+ DBG_ERR("match_gfd_cb: glib fd %d not in map\n", new_gfd->fd);
+ return false;
+ }
+
+ fd_event = glue->fd_map[i].fd_event;
+ if (fd_event == NULL) {
+ DBG_ERR("fd_event for fd %d is NULL\n", new_gfd->fd);
+ return false;
+ }
+
+ tevent_fd_set_flags(fd_event, 0);
+
+ if (new_gfd->events & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
+ TEVENT_FD_READABLE(fd_event);
+ }
+ if (new_gfd->events & G_IO_OUT) {
+ TEVENT_FD_WRITEABLE(fd_event);
+ }
+
+ return true;
+}
+
+static bool add_gfd_cb(struct tevent_glib_glue *glue, const GPollFD *gfd)
+{
+ struct tevent_fd *fd_event = NULL;
+ uint16_t events;
+
+ events = (gfd->events & (G_IO_IN | G_IO_HUP | G_IO_ERR)) ?
+ TEVENT_FD_READ : 0;
+ events |= (gfd->events & G_IO_OUT) ? TEVENT_FD_WRITE : 0;
+
+ fd_event = tevent_add_fd(glue->ev, glue->fd_map,
+ gfd->fd,
+ events,
+ tevent_glib_fd_handler,
+ glue);
+ if (fd_event == NULL) {
+ DBG_ERR("tevent_add_fd failed\n");
+ return false;
+ }
+
+ glue->fd_map = talloc_realloc(glue, glue->fd_map,
+ struct tevent_fd_map,
+ glue->num_maps + 1);
+ if (glue->fd_map == NULL) {
+ DBG_ERR("talloc_realloc failed\n");
+ return false;
+ }
+
+ glue->fd_map[glue->num_maps].fd = gfd->fd;
+ glue->fd_map[glue->num_maps].fd_event = fd_event;
+ glue->num_maps++;
+
+ DBG_DEBUG("added tevent_fd for glib fd %d\n", gfd->fd);
+
+ return true;
+}
+
+static bool remove_gfd_cb(struct tevent_glib_glue *glue, const GPollFD *gfd)
+{
+ size_t i;
+
+ for (i = 0; i < glue->num_maps; i++) {
+ if (glue->fd_map[i].fd == gfd->fd) {
+ break;
+ }
+ }
+
+ if (i == glue->num_maps) {
+ DBG_ERR("remove_gfd_cb: glib fd %d not in map\n", gfd->fd);
+ return false;
+ }
+
+ TALLOC_FREE(glue->fd_map[i].fd_event);
+
+ if (i + 1 < glue->num_maps) {
+ memmove(&glue->fd_map[i], &glue->fd_map[i+1],
+ (glue->num_maps - (i + 1)) * sizeof(struct tevent_fd_map));
+ }
+
+ glue->num_maps--;
+
+ glue->fd_map = talloc_realloc(glue, glue->fd_map,
+ struct tevent_fd_map,
+ glue->num_maps);
+ if (glue->num_maps > 0 && glue->fd_map == NULL) {
+ DBG_ERR("talloc_realloc failed\n");
+ return false;
+ }
+
+ return true;
+}
+
+static void tevent_glib_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct tevent_glib_glue *glue = talloc_get_type_abort(
+ private_data, struct tevent_glib_glue);
+
+ tevent_glib_process(glue);
+
+ return;
+}
+
+static void tevent_glib_timer_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct tevent_glib_glue *glue = talloc_get_type_abort(
+ private_data, struct tevent_glib_glue);
+
+ glue->timer = NULL;
+ tevent_glib_process(glue);
+
+ return;
+}
+
+static void tevent_glib_im_handler(struct tevent_context *ev,
+ struct tevent_immediate *im,
+ void *private_data)
+{
+ struct tevent_glib_glue *glue = talloc_get_type_abort(
+ private_data, struct tevent_glib_glue);
+
+ glue->scheduled_im = false;
+ tevent_glib_process(glue);
+
+ return;
+}
+
+static bool save_current_fdset(struct tevent_glib_glue *glue)
+{
+ /* Save old glib fds, we only grow the prev array */
+ if (glue->num_prev_gpollfds < glue->num_gpollfds) {
+ glue->prev_gpollfds = talloc_realloc(glue,
+ glue->prev_gpollfds,
+ GPollFD,
+ glue->num_gpollfds);
+ if (glue->prev_gpollfds == NULL) {
+ DBG_ERR("talloc_realloc failed\n");
+ return false;
+ }
+ }
+ glue->num_prev_gpollfds = glue->num_gpollfds;
+ if (glue->num_gpollfds > 0) {
+ memcpy(glue->prev_gpollfds, glue->gpollfds,
+ sizeof(GPollFD) * glue->num_gpollfds);
+ memset(glue->gpollfds, 0, sizeof(GPollFD) * glue->num_gpollfds);
+ }
+
+ return true;
+}
+
+static bool get_glib_fds_and_timeout(struct tevent_glib_glue *glue)
+{
+ bool ok;
+ gint num_fds;
+
+ ok = save_current_fdset(glue);
+ if (!ok) {
+ return false;
+ }
+
+ while (true) {
+ num_fds = g_main_context_query(glue->gmain_ctx,
+ glue->gpriority,
+ &glue->gtimeout,
+ glue->gpollfds,
+ glue->num_gpollfds);
+ if (num_fds == glue->num_gpollfds) {
+ break;
+ }
+ glue->gpollfds = talloc_realloc(glue,
+ glue->gpollfds,
+ GPollFD,
+ num_fds);
+ if (num_fds > 0 && glue->gpollfds == NULL) {
+ DBG_ERR("talloc_realloc failed\n");
+ return false;
+ }
+ glue->num_gpollfds = num_fds;
+ };
+
+ if (glue->num_gpollfds > 0) {
+ qsort(glue->gpollfds, num_fds, sizeof(GPollFD), glib_fd_cmp_func);
+ }
+
+ DBG_DEBUG("get_glib_fds_and_timeout: num fds: %d, timeout: %d ms\n",
+ num_fds, glue->gtimeout);
+
+ return true;
+}
+
+static bool tevent_glib_update_events(struct tevent_glib_glue *glue)
+{
+ bool ok;
+
+ ok = cmp_gfds(glue,
+ glue->gpollfds,
+ glue->prev_gpollfds,
+ glue->num_gpollfds,
+ glue->num_prev_gpollfds,
+ glib_fd_cmp_func,
+ match_gfd_cb,
+ add_gfd_cb,
+ remove_gfd_cb);
+ if (!ok) {
+ return false;
+ }
+
+ TALLOC_FREE(glue->timer);
+ if ((glue->gtimeout == 0) && (!glue->scheduled_im)) {
+ /*
+ * Schedule an immediate event. We use a immediate event and not
+ * an immediate timer event, because the former can be reused.
+ *
+ * We may be called in a loop in tevent_glib_process() and only
+ * want to schedule this once, so we remember the fact.
+ *
+ * Doing this here means we occasionally schedule an unneeded
+ * immediate event, but it avoids leaking abstraction into upper
+ * layers.
+ */
+ tevent_schedule_immediate(glue->im, glue->ev,
+ tevent_glib_im_handler,
+ glue);
+ glue->scheduled_im = true;
+ } else if (glue->gtimeout > 0) {
+ uint64_t microsec = glue->gtimeout * 1000;
+ struct timeval tv = tevent_timeval_current_ofs(microsec / 1000000,
+ microsec % 1000000);
+
+ glue->timer = tevent_add_timer(glue->ev, glue,
+ tv,
+ tevent_glib_timer_handler,
+ glue);
+ if (glue->timer == NULL) {
+ DBG_ERR("tevent_add_timer failed\n");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void tevent_glib_retry_timer(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *private_data)
+{
+ struct tevent_glib_glue *glue = talloc_get_type_abort(
+ private_data, struct tevent_glib_glue);
+
+ glue->retry_timer = NULL;
+ (void)tevent_glib_prepare(glue);
+}
+
+static bool tevent_glib_prepare(struct tevent_glib_glue *glue)
+{
+ bool ok;
+ gboolean gok, source_ready;
+
+ gok = g_main_context_acquire(glue->gmain_ctx);
+ if (!gok) {
+ DBG_ERR("couldn't acquire g_main_context\n");
+
+ tevent_glib_glue_cleanup(glue);
+
+ glue->retry_timer = tevent_add_timer(
+ glue->ev, glue,
+ tevent_timeval_current_ofs(0, 1000),
+ tevent_glib_retry_timer,
+ glue);
+ if (glue->retry_timer == NULL) {
+ DBG_ERR("tevent_add_timer failed\n");
+ return false;
+ }
+ return true;
+ }
+
+ source_ready = g_main_context_prepare(glue->gmain_ctx, &glue->gpriority);
+ if (source_ready) {
+ g_main_context_dispatch(glue->gmain_ctx);
+ }
+
+ ok = get_glib_fds_and_timeout(glue);
+ if (!ok) {
+ DBG_ERR("get_glib_fds_and_timeout failed\n");
+ samba_tevent_glib_glue_quit(glue);
+ return false;
+ }
+
+ tevent_glib_update_events(glue);
+
+ return true;
+}
+
+static short gpoll_to_poll_event(gushort gevent)
+{
+ short pevent = 0;
+
+ if (gevent & G_IO_IN) {
+ pevent |= POLLIN;
+ }
+ if (gevent & G_IO_OUT) {
+ pevent |= POLLOUT;
+ }
+ if (gevent & G_IO_HUP) {
+ pevent |= POLLHUP;
+ }
+ if (gevent & G_IO_ERR) {
+ pevent |= POLLERR;
+ }
+
+ return pevent;
+}
+
+static gushort poll_to_gpoll_event(short pevent)
+{
+ gushort gevent = 0;
+
+ if (pevent & POLLIN) {
+ gevent |= G_IO_IN;
+ }
+ if (pevent & POLLOUT) {
+ gevent |= G_IO_OUT;
+ }
+ if (pevent & POLLHUP) {
+ gevent |= G_IO_HUP;
+ }
+ if (pevent & POLLERR) {
+ gevent |= G_IO_ERR;
+ }
+
+ return gevent;
+}
+
+static bool gpoll_to_poll_fds(struct tevent_glib_glue *glue)
+{
+ size_t i;
+
+ TALLOC_FREE(glue->pollfds);
+
+ glue->pollfds = talloc_zero_array(glue, struct pollfd,
+ glue->num_gpollfds);
+ if (glue->pollfds == NULL) {
+ DBG_ERR("talloc_zero_array failed\n");
+ return false;
+ }
+
+ for (i = 0; i < glue->num_gpollfds; i++) {
+ glue->pollfds[i].fd = glue->gpollfds[i].fd;
+ glue->pollfds[i].events = gpoll_to_poll_event(
+ glue->gpollfds[i].events);
+ }
+
+ return true;
+}
+
+static void poll_to_gpoll_revents(struct tevent_glib_glue *glue)
+{
+ size_t i;
+
+ for (i = 0; i < glue->num_gpollfds; i++) {
+ glue->gpollfds[i].revents = poll_to_gpoll_event(
+ glue->pollfds[i].revents);
+ }
+}
+
+static bool tevent_glib_process(struct tevent_glib_glue *glue)
+{
+ bool ok;
+ int num_ready;
+
+ ok = gpoll_to_poll_fds(glue);
+ if (!ok) {
+ DBG_ERR("gpoll_to_poll_fds failed\n");
+ samba_tevent_glib_glue_quit(glue);
+ return false;
+ }
+
+ num_ready = poll(glue->pollfds, glue->num_gpollfds, 0);
+ if (num_ready == -1) {
+ DBG_ERR("poll: %s\n", strerror(errno));
+ }
+
+ if (num_ready > 0) {
+ poll_to_gpoll_revents(glue);
+ }
+
+ DBG_DEBUG("tevent_glib_process: num_ready: %d\n", num_ready);
+
+ do {
+ bool sources_ready;
+
+ sources_ready = g_main_context_check(glue->gmain_ctx,
+ glue->gpriority,
+ glue->gpollfds,
+ glue->num_gpollfds);
+ if (!sources_ready) {
+ break;
+ }
+
+ g_main_context_dispatch(glue->gmain_ctx);
+
+ if (glue->quit) {
+ /* Set via tevent_glib_glue_quit() */
+ g_main_context_release(glue->gmain_ctx);
+ return true;
+ }
+
+ /*
+ * This is an optimisation for the following case:
+ *
+ * If g_main_context_query() returns a timeout value of 0 this
+ * implicates that there may be more glib event sources ready.
+ * This avoids sheduling an immediate event and going through
+ * tevent_loop_once().
+ */
+ if (glue->gtimeout != 0) {
+ break;
+ }
+
+ /*
+ * Give other glib threads a chance to grab the context,
+ * tevent_glib_prepare() will then re-acquire it
+ */
+ g_main_context_release(glue->gmain_ctx);
+
+ ok = tevent_glib_prepare(glue);
+ if (!ok) {
+ samba_tevent_glib_glue_quit(glue);
+ return false;
+ }
+ } while (true);
+
+ /*
+ * Give other glib threads a chance to grab the context,
+ * tevent_glib_prepare() will then re-acquire it
+ */
+ g_main_context_release(glue->gmain_ctx);
+
+ ok = tevent_glib_prepare(glue);
+ if (!ok) {
+ samba_tevent_glib_glue_quit(glue);
+ return false;
+ }
+
+ return true;
+}
+
+static void tevent_glib_glue_cleanup(struct tevent_glib_glue *glue)
+{
+ size_t n = talloc_array_length(glue->fd_map);
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ TALLOC_FREE(glue->fd_map[i].fd_event);
+ }
+
+ TALLOC_FREE(glue->fd_map);
+ TALLOC_FREE(glue->gpollfds);
+ TALLOC_FREE(glue->prev_gpollfds);
+ TALLOC_FREE(glue->timer);
+ TALLOC_FREE(glue->retry_timer);
+ TALLOC_FREE(glue->im);
+ glue->num_gpollfds = 0;
+ glue->num_prev_gpollfds = 0;
+}
+
+void samba_tevent_glib_glue_quit(struct tevent_glib_glue *glue)
+{
+ tevent_glib_glue_cleanup(glue);
+ glue->quit = true;
+ return;
+}
+
+struct tevent_glib_glue *samba_tevent_glib_glue_create(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ GMainContext *gmain_ctx)
+{
+ bool ok;
+ struct tevent_glib_glue *glue = NULL;
+
+ glue = talloc_zero(mem_ctx, struct tevent_glib_glue);
+ if (glue == NULL) {
+ DBG_ERR("talloc_zero failed\n");
+ return NULL;
+ }
+
+ *glue = (struct tevent_glib_glue) {
+ .ev = ev,
+ .gmain_ctx = gmain_ctx,
+ };
+
+ glue->im = tevent_create_immediate(glue);
+
+ ok = tevent_glib_prepare(glue);
+ if (!ok) {
+ TALLOC_FREE(glue);
+ return NULL;
+ }
+
+ return glue;
+}
+
+#else /* HAVE_GLIB */
+
+struct tevent_glib_glue *samba_tevent_glib_glue_create(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ GMainContext *gmain_ctx)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+void samba_tevent_glib_glue_quit(struct tevent_glib_glue *glue)
+{
+ return;
+}
+#endif /* HAVE_GLIB */
diff --git a/source3/lib/tevent_glib_glue.h b/source3/lib/tevent_glib_glue.h
new file mode 100644
index 0000000..94f53cb
--- /dev/null
+++ b/source3/lib/tevent_glib_glue.h
@@ -0,0 +1,70 @@
+/*
+ Unix SMB/CIFS implementation.
+ Poll glib event loop from tevent
+
+ Copyright (C) Ralph Boehme 2016
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _TEVENT_GLIB_GLUE_H
+#define _TEVENT_GLIB_GLUE_H
+
+#include <talloc.h>
+#include <tevent.h>
+
+typedef struct _GMainContext GMainContext;
+
+/**
+ * @brief Add a glib GmainContext to a tevent context
+ *
+ * tevent will poll the glib event sources and run handlers for
+ * pending events as detailed in the glib documentation:
+ *
+ * https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html
+ *
+ * If tevent was built without glib support, this function will always return
+ * NULL with an error number ENOSYS.
+ *
+ * @param[in] mem_ctx Memory context to use
+ *
+ * @param[in] ev Event context to use
+ *
+ * @param[in] gmain_ctx GMainContext that will be added to tevent
+ *
+ * @return A handle on the glue context that binds the
+ * the GMainContext to tevent. Pass the glue handle to
+ * tevent_glib_glue_quit() in a callback when you want
+ * stop processing glib events.
+ * You must not call talloc_free() on the handle while
+ * the loop is still in use and attached to tevent.
+ */
+struct tevent_glib_glue *samba_tevent_glib_glue_create(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ GMainContext *gmain_ctx);
+
+/**
+ * @brief Stop polling a GMainContext
+ *
+ * Used in a callback when you want to stop processing glib events.
+ *
+ * @param[in] glue And tevent_glib_glue handle
+ */
+void samba_tevent_glib_glue_quit(struct tevent_glib_glue *glue);
+
+#endif
diff --git a/source3/wscript b/source3/wscript
index 8e23621..d310019 100644
--- a/source3/wscript
+++ b/source3/wscript
@@ -1543,6 +1543,17 @@ main() {
else:
conf.fatal('AFS headers not available, but --with-fake-kaserver was specified')
+ if conf.CHECK_CFG(package='glib-2.0', args='--cflags --libs',
+ msg='Checking for glib-2.0', uselib_store="GLIB-2.0"):
+ if (conf.CHECK_HEADERS('glib.h', lib='glib-2.0') and conf.CHECK_LIB('glib-2.0', shlib=True)):
+ conf.DEFINE('HAVE_GLIB', 1)
+ else:
+ # define an empty subsystem to allow it to be used as an empty dependency
+ conf.SET_TARGET_TYPE('glib-2.0', 'EMPTY')
+ else:
+ # define an empty subsystem to allow it to be used as an empty dependency
+ conf.SET_TARGET_TYPE('glib-2.0', 'EMPTY')
+
conf.env['libtracker']=''
tracker_versions = ['1.0', '0.16', '0.14']
@@ -1558,6 +1569,8 @@ main() {
conf.env.with_spotlight = False
if Options.options.with_spotlight:
+ if not conf.CONFIG_SET('HAVE_GLIB'):
+ conf.fatal('Missing glib-2.0 development files')
if not conf.CONFIG_SET('HAVE_TRACKER'):
conf.fatal('Missing Gnome Tracker development files')
diff --git a/source3/wscript_build b/source3/wscript_build
index 0c7dfc2..e79e7ee 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -858,6 +858,11 @@ bld.SAMBA3_SUBSYSTEM('INIT_SAMR',
bld.SAMBA3_SUBSYSTEM('LIBLSA',
source='lib/lsa.c')
+bld.SAMBA3_SUBSYSTEM('tevent-glib-glue',
+ source='lib/tevent_glib_glue.c',
+ deps='glib-2.0'
+)
+
########################## BINARIES #################################
bld.SAMBA3_BINARY('smbd/smbd',
--
2.5.0
From 43c0e0f05ad813dd5219aebbb9a1f1659e493bee Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 28 Jan 2016 08:29:28 +0100
Subject: [PATCH 3/6] s3/lib: add a tevent_glib_glue subsystem test
Tests adapted from glib2 glib/tests/mainloop.c.
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/lib/tevent_glib_glue_tests.c | 359 ++++++++++++++++++++++++++
source3/script/tests/test_tevent_glib_glue.sh | 20 ++
source3/selftest/tests.py | 3 +
source3/wscript_build | 11 +
4 files changed, 393 insertions(+)
create mode 100644 source3/lib/tevent_glib_glue_tests.c
create mode 100755 source3/script/tests/test_tevent_glib_glue.sh
diff --git a/source3/lib/tevent_glib_glue_tests.c b/source3/lib/tevent_glib_glue_tests.c
new file mode 100644
index 0000000..bbba465
--- /dev/null
+++ b/source3/lib/tevent_glib_glue_tests.c
@@ -0,0 +1,359 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ testing of the tevent glib glue subsystem
+
+ Copyright (C) Ralph Boehme 2016
+
+ glib tests adapted from glib2 glib/tests/mainloop.c
+ Copyright (C) 2011 Red Hat Inc., Matthias Clasen
+
+ ** NOTE! The following LGPL license applies to the tevent
+ ** library. This does NOT imply that all of Samba is released
+ ** under the LGPL
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "replace.h"
+#include "lib/tevent_glib_glue.h"
+#include <glib.h>
+#include <glib-unix.h>
+
+/*
+ * Unfortunately the glib test suite runner doesn't pass args to tests
+ * so we must keep a few globals here.
+ */
+static struct tevent_context *ev;
+
+static gboolean cb (gpointer data)
+{
+ return FALSE;
+}
+
+static gboolean prepare (GSource *source, gint *time)
+{
+ return FALSE;
+}
+static gboolean check (GSource *source)
+{
+ return FALSE;
+}
+static gboolean dispatch (GSource *source, GSourceFunc cb_in, gpointer date)
+{
+ return FALSE;
+}
+
+static GSourceFuncs funcs = {
+ prepare,
+ check,
+ dispatch,
+ NULL
+};
+
+static void test_maincontext_basic(void)
+{
+ GMainContext *ctx;
+ struct tevent_glib_glue *glue;
+ GSource *source;
+ guint id;
+ gpointer data = &funcs;
+
+ ctx = g_main_context_new ();
+ glue = samba_tevent_glib_glue_create(ev, ev, ctx);
+ g_assert (glue != NULL);
+
+ g_assert (!g_main_context_pending (ctx));
+ g_assert (!g_main_context_iteration (ctx, FALSE));
+
+ source = g_source_new (&funcs, sizeof (GSource));
+ g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_DEFAULT);
+ g_assert (!g_source_is_destroyed (source));
+
+ g_assert (!g_source_get_can_recurse (source));
+ g_assert (g_source_get_name (source) == NULL);
+
+ g_source_set_can_recurse (source, TRUE);
+ g_source_set_name (source, "d");
+
+ g_assert (g_source_get_can_recurse (source));
+ g_assert_cmpstr (g_source_get_name (source), ==, "d");
+
+ g_assert (g_main_context_find_source_by_user_data (ctx, NULL) == NULL);
+ g_assert (g_main_context_find_source_by_funcs_user_data (ctx, &funcs, NULL) == NULL);
+
+ id = g_source_attach (source, ctx);
+ g_assert_cmpint (g_source_get_id (source), ==, id);
+ g_assert (g_main_context_find_source_by_id (ctx, id) == source);
+
+ g_source_set_priority (source, G_PRIORITY_HIGH);
+ g_assert_cmpint (g_source_get_priority (source), ==, G_PRIORITY_HIGH);
+
+ g_source_destroy (source);
+ g_assert (g_source_get_context (source) == ctx);
+ g_assert (g_main_context_find_source_by_id (ctx, id) == NULL);
+
+ samba_tevent_glib_glue_quit(glue);
+ TALLOC_FREE(glue);
+ g_main_context_unref (ctx);
+
+ if (g_test_undefined ())
+ {
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "*assertion*source->context != NULL*failed*");
+ g_assert (g_source_get_context (source) == NULL);
+ g_test_assert_expected_messages ();
+ }
+
+ g_source_unref (source);
+
+ ctx = g_main_context_default ();
+
+ glue = samba_tevent_glib_glue_create(ev, ev, ctx);
+ g_assert (glue != NULL);
+
+ source = g_source_new (&funcs, sizeof (GSource));
+ g_source_set_funcs (source, &funcs);
+ g_source_set_callback (source, cb, data, NULL);
+ id = g_source_attach (source, ctx);
+ g_source_unref (source);
+ g_source_set_name_by_id (id, "e");
+ g_assert_cmpstr (g_source_get_name (source), ==, "e");
+ g_assert (g_source_get_context (source) == ctx);
+ g_assert (g_source_remove_by_funcs_user_data (&funcs, data));
+
+ source = g_source_new (&funcs, sizeof (GSource));
+ g_source_set_funcs (source, &funcs);
+ g_source_set_callback (source, cb, data, NULL);
+ id = g_source_attach (source, ctx);
+ g_source_unref (source);
+ g_assert (g_source_remove_by_user_data (data));
+ g_assert (!g_source_remove_by_user_data ((gpointer)0x1234));
+
+ g_idle_add (cb, data);
+ g_assert (g_idle_remove_by_data (data));
+
+ samba_tevent_glib_glue_quit(glue);
+ TALLOC_FREE(glue);
+}
+
+static gboolean count_calls (gpointer data)
+{
+ gint *i = data;
+
+ (*i)++;
+
+ return TRUE;
+}
+
+static gboolean quit_loop (gpointer data)
+{
+ struct tevent_glib_glue *glue = talloc_get_type_abort(data, struct tevent_glib_glue);
+
+ samba_tevent_glib_glue_quit(glue);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void test_timeouts (void)
+{
+ GMainContext *ctx;
+ struct tevent_glib_glue *glue;
+ GSource *source;
+ static gint a;
+ static gint b;
+ static gint c;
+
+ a = b = c = 0;
+
+ ctx = g_main_context_new ();
+ glue = samba_tevent_glib_glue_create(ev, ev, ctx);
+ g_assert (glue != NULL);
+
+ source = g_timeout_source_new (100);
+ g_source_set_callback (source, count_calls, &a, NULL);
+ g_source_attach (source, ctx);
+ g_source_unref (source);
+
+ source = g_timeout_source_new (250);
+ g_source_set_callback (source, count_calls, &b, NULL);
+ g_source_attach (source, ctx);
+ g_source_unref (source);
+
+ source = g_timeout_source_new (330);
+ g_source_set_callback (source, count_calls, &c, NULL);
+ g_source_attach (source, ctx);
+ g_source_unref (source);
+
+ source = g_timeout_source_new (1050);
+ g_source_set_callback (source, quit_loop, glue, NULL);
+ g_source_attach (source, ctx);
+ g_source_unref (source);
+
+ g_assert (tevent_loop_wait(ev) == 0);
+
+ /* We may be delayed for an arbitrary amount of time - for example,
+ * it's possible for all timeouts to fire exactly once.
+ */
+ g_assert_cmpint (a, >, 0);
+ g_assert_cmpint (a, >=, b);
+ g_assert_cmpint (b, >=, c);
+
+ g_assert_cmpint (a, <=, 10);
+ g_assert_cmpint (b, <=, 4);
+ g_assert_cmpint (c, <=, 3);
+
+ samba_tevent_glib_glue_quit(glue);
+ TALLOC_FREE(glue);
+ g_main_context_unref (ctx);
+}
+
+
+static gchar zeros[1024];
+
+static gsize fill_a_pipe (gint fd)
+{
+ gsize written = 0;
+ GPollFD pfd;
+
+ pfd.fd = fd;
+ pfd.events = G_IO_OUT;
+ while (g_poll (&pfd, 1, 0) == 1)
+ /* we should never see -1 here */
+ written += write (fd, zeros, sizeof zeros);
+
+ return written;
+}
+
+static gboolean write_bytes (gint fd,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ gssize *to_write = user_data;
+ gint limit;
+
+ if (*to_write == 0)
+ return FALSE;
+
+ /* Detect if we run before we should */
+ g_assert (*to_write >= 0);
+
+ limit = MIN (*to_write, sizeof zeros);
+ *to_write -= write (fd, zeros, limit);
+
+ return TRUE;
+}
+
+static gboolean read_bytes (gint fd,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ static gchar buffer[1024];
+ gssize *to_read = user_data;
+
+ *to_read -= read (fd, buffer, sizeof buffer);
+
+ /* The loop will exit when there is nothing else to read, then we will
+ * use g_source_remove() to destroy this source.
+ */
+ return TRUE;
+}
+
+static void test_unix_fd(void)
+{
+ gssize to_write = -1;
+ gssize to_read;
+ gint fds[2];
+ gint a, b;
+ gint s;
+ GSource *source_a;
+ GSource *source_b;
+ struct tevent_glib_glue *glue;
+
+ glue = samba_tevent_glib_glue_create(ev, ev, g_main_context_default());
+ g_assert (glue != NULL);
+
+ s = pipe (fds);
+ g_assert (s == 0);
+
+ to_read = fill_a_pipe (fds[1]);
+ /* write at higher priority to keep the pipe full... */
+ a = g_unix_fd_add_full (G_PRIORITY_HIGH, fds[1], G_IO_OUT, write_bytes, &to_write, NULL);
+ source_a = g_source_ref (g_main_context_find_source_by_id (NULL, a));
+ /* make sure no 'writes' get dispatched yet */
+ while (tevent_loop_once(ev));
+
+ to_read += 128 * 1024 * 1024;
+ to_write = 128 * 1024 * 1024;
+ b = g_unix_fd_add (fds[0], G_IO_IN, read_bytes, &to_read);
+ source_b = g_source_ref (g_main_context_find_source_by_id (NULL, b));
+
+ /* Assuming the kernel isn't internally 'laggy' then there will always
+ * be either data to read or room in which to write. That will keep
+ * the loop running until all data has been read and written.
+ */
+ while (to_write > 0 || to_read > 0)
+ {
+ gssize to_write_was = to_write;
+ gssize to_read_was = to_read;
+
+ if (tevent_loop_once(ev) != 0)
+ break;
+
+ /* Since the sources are at different priority, only one of them
+ * should possibly have run.
+ */
+ g_assert (to_write == to_write_was || to_read == to_read_was);
+ }
+
+ g_assert (to_write == 0);
+ g_assert (to_read == 0);
+
+ /* 'a' is already removed by itself */
+ g_assert (g_source_is_destroyed (source_a));
+ g_source_unref (source_a);
+ g_source_remove (b);
+ g_assert (g_source_is_destroyed (source_b));
+ g_source_unref (source_b);
+
+ samba_tevent_glib_glue_quit(glue);
+ TALLOC_FREE(glue);
+
+ close (fds[1]);
+ close (fds[0]);
+}
+
+int main(int argc, const char *argv[])
+{
+ int test_argc = 3;
+ char *test_argv[] = {
+ discard_const("test_glib_glue"),
+ discard_const("-m"),
+ discard_const("no-undefined")
+ };
+ char **argvp = test_argv;
+
+ g_test_init(&test_argc, &argvp, NULL);
+
+ ev = tevent_context_init(NULL);
+ if (ev == NULL) {
+ exit(1);
+ }
+
+ g_test_add_func ("/maincontext/basic", test_maincontext_basic);
+ g_test_add_func ("/mainloop/timeouts", test_timeouts);
+ g_test_add_func ("/mainloop/unix-fd", test_unix_fd);
+
+ return g_test_run();
+}
diff --git a/source3/script/tests/test_tevent_glib_glue.sh b/source3/script/tests/test_tevent_glib_glue.sh
new file mode 100755
index 0000000..6754494
--- /dev/null
+++ b/source3/script/tests/test_tevent_glib_glue.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+incdir=`dirname $0`/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+if [ ! -x $BINDIR/tevent_glib_glue_test ] ; then
+ # Some machines don't have /bin/true, simulate it
+ cat >$BINDIR/tevent_glib_glue_test <<EOF
+#!/bin/sh
+exit 0
+EOF
+ chmod +x $BINDIR/tevent_glib_glue_test
+fi
+
+failed=0
+
+testit "tevent_glib_glue_test" $VALGRIND $BINDIR/tevent_glib_glue_test ||
+ failed=`expr $failed + 1`
+
+testok $0 $failed
diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py
index b2bae75..bf9aad6 100755
--- a/source3/selftest/tests.py
+++ b/source3/selftest/tests.py
@@ -253,6 +253,9 @@ plantestsuite(
"samba3.pthreadpool", "nt4_dc",
[os.path.join(samba3srcdir, "script/tests/test_pthreadpool.sh")])
+plantestsuite("samba3.tevent_glib_glue", "nt4_dc",
+ [os.path.join(samba3srcdir, "script/tests/test_tevent_glib_glue.sh")])
+
plantestsuite("samba3.async_req", "nt4_dc",
[os.path.join(samba3srcdir, "script/tests/test_async_req.sh")])
diff --git a/source3/wscript_build b/source3/wscript_build
index e79e7ee..f2ca534 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1381,6 +1381,17 @@ bld.SAMBA3_BINARY('eventlogadm',
param
LIBEVENTLOG''')
+bld.SAMBA3_BINARY('tevent_glib_glue_test',
+ source='lib/tevent_glib_glue_tests.c',
+ deps='''
+ talloc
+ libsmb
+ popt_samba3
+ param
+ tevent-glib-glue''',
+ enabled=bld.CONFIG_SET('HAVE_GLIB'),
+ install=False)
+
bld.SAMBA3_BINARY('sharesec',
source='utils/sharesec.c lib/util_sd.c',
deps='''
--
2.5.0
From 558b99cbcfcc015a1f4677de5abdd8b3a5dd6e03 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Fri, 22 Jan 2016 15:38:39 +0100
Subject: [PATCH 4/6] s3/lib: tevent-glib-glue test utiltity with Tracker
A small utilitly useful for tesing the tevent_glib_glue code. It runs a
tracker-sparql search query against your local tracker store that must
be setup and running.
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/utils/async-tracker.c | 286 ++++++++++++++++++++++++++++++++++++++++++
source3/wscript_build | 11 ++
2 files changed, 297 insertions(+)
create mode 100644 source3/utils/async-tracker.c
diff --git a/source3/utils/async-tracker.c b/source3/utils/async-tracker.c
new file mode 100644
index 0000000..4b674af
--- /dev/null
+++ b/source3/utils/async-tracker.c
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2011, Nokia <ivan.frade at nokia.com>
+ * Copyright (C) 2015, Noel Power <nopower at suse.com>
+ * Copyright (C) 2016, Ralph Boehme <slow at samba.org.>
+ *
+ * This library 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 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "includes.h"
+#include "lib/util/debug.h"
+#include "popt_common.h"
+#include "param.h"
+#include "lib/tevent_glib_glue.h"
+
+/*
+ * glib uses TRUE and FALSE which was redefined by "includes.h" to be
+ * unusable, undefine so glib can establish its own working
+ * replacement.
+ */
+#undef TRUE
+#undef FALSE
+#include <libtracker-sparql/tracker-sparql.h>
+
+enum loop_type {TEVENT_LOOP, GLIB_LOOP};
+
+struct test_state {
+ enum loop_type loop_type;
+ TrackerSparqlConnection *connection;
+ GCancellable *cancellable;
+ GTimer *timer;
+ GMainLoop *loop;
+ struct tevent_context *ev;
+ struct tevent_glib_glue *glue;
+};
+
+static void cleanup(struct test_state *state)
+{
+ g_cancellable_cancel(state->cancellable);
+ g_object_unref(state->cancellable);
+ g_timer_destroy(state->timer);
+ if (state->connection) {
+ g_object_unref(state->connection);
+ state->connection = NULL;
+ }
+ if (state->loop_type == GLIB_LOOP) {
+ g_main_loop_quit(state->loop);
+ } else {
+ samba_tevent_glib_glue_quit(state->glue);
+ }
+}
+
+static void cursor_cb(GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ TrackerSparqlCursor *cursor;
+ GError *error = NULL;
+ gboolean more_results;
+ struct test_state *state = talloc_get_type_abort(user_data, struct test_state);
+
+ cursor = TRACKER_SPARQL_CURSOR(object);
+ more_results = tracker_sparql_cursor_next_finish(cursor,
+ res,
+ &error);
+
+ if (!error) {
+ static gint i = 0;
+
+ if (more_results) {
+ if (i++ < 5) {
+ int num_cols = tracker_sparql_cursor_get_n_columns(cursor);
+ int col;
+ if (i == 1) {
+ g_print("Printing first 5 results:\n");
+ }
+ for (col = 0; col < num_cols; col++) {
+ g_print(" %s ", tracker_sparql_cursor_get_string(
+ cursor, col, NULL));
+ if (col == num_cols -1 ) {
+ g_print("\n");
+ }
+ }
+
+ if (i == 5) {
+ g_print(" ...\n");
+ g_print(" Printing nothing for remaining results\n");
+ }
+ }
+
+ tracker_sparql_cursor_next_async(cursor,
+ state->cancellable,
+ cursor_cb,
+ state);
+ } else {
+ g_print("\n");
+ g_print("Async cursor next took: %.6f (for all %d results)\n",
+ g_timer_elapsed (state->timer, NULL), i);
+
+ g_object_unref(cursor);
+ cleanup(state);
+ }
+ } else {
+ g_critical("Could not run cursor next: %s", error->message);
+
+ if (cursor) {
+ g_object_unref(cursor);
+ }
+
+ g_error_free(error);
+ cleanup(state);
+ }
+}
+
+static void query_cb(GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ TrackerSparqlCursor *cursor;
+ GError *error = NULL;
+ struct test_state *state = talloc_get_type_abort(
+ user_data, struct test_state);
+
+ cursor = tracker_sparql_connection_query_finish(
+ TRACKER_SPARQL_CONNECTION (object),
+ res,
+ &error);
+
+ g_print("Async query took: %.6f\n", g_timer_elapsed(state->timer, NULL));
+
+ g_timer_start(state->timer);
+
+ if (!error) {
+ tracker_sparql_cursor_next_async(cursor,
+ state->cancellable,
+ cursor_cb,
+ state);
+ } else {
+ g_critical("Could not run query: %s", error->message);
+
+ if (cursor) {
+ g_object_unref(cursor);
+ }
+
+ g_error_free(error);
+ cleanup(state);
+ }
+}
+
+static void connection_cb(GObject *object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ struct test_state *state = talloc_get_type_abort(
+ user_data, struct test_state);
+ GError *error = NULL;
+
+ state->connection = tracker_sparql_connection_get_finish(res, &error);
+ g_print("Async connection took: %.6f\n",
+ g_timer_elapsed(state->timer, NULL));
+
+ g_timer_start(state->timer);
+
+ if (!error) {
+ tracker_sparql_connection_query_async(
+ state->connection,
+ "SELECT ?name nie:mimeType(?s) nfo:fileName(?s) "
+ "WHERE { {?s nie:url ?name}}",
+ state->cancellable,
+ query_cb,
+ state);
+ } else {
+ g_critical("Could not connect: %s", error->message);
+ g_error_free(error);
+ cleanup(state);
+ }
+}
+
+static void debug_fn(void *private_data,
+ enum tevent_debug_level level,
+ const char *fmt,
+ va_list ap)
+{
+ dbgtext_va(fmt, ap);
+}
+
+int main(int argc, const char **argv)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct test_state *state = NULL;
+ int c;
+ poptContext pc;
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {"tevent", 't', POPT_ARG_NONE, NULL, 't', "Use tevent loop" },
+ {"glib", 'g', POPT_ARG_NONE, NULL, 'g', "Use glib loop" },
+ POPT_COMMON_SAMBA
+ POPT_TABLEEND
+ };
+
+ mem_ctx = talloc_new(NULL);
+ if (mem_ctx == NULL) {
+ exit(1);
+ }
+
+ state = talloc_zero(mem_ctx, struct test_state);
+ if (state == NULL) {
+ exit(1);
+ }
+
+ state->loop_type = GLIB_LOOP;
+
+ setup_logging(argv[0], DEBUG_STDERR);
+ smb_init_locale();
+
+ if (!lp_load_client(get_dyn_CONFIGFILE())) {
+ fprintf(stderr, "ERROR: Can't load %s - run testparm to debug it\n",
+ get_dyn_CONFIGFILE());
+ exit(1);
+ }
+
+ pc = poptGetContext(NULL, argc, argv, long_options,
+ POPT_CONTEXT_KEEP_FIRST);
+
+ while ((c = poptGetNextOpt(pc)) != -1) {
+ switch (c) {
+ case 'g':
+ state->loop_type = GLIB_LOOP;
+ break;
+ case 't':
+ state->loop_type = TEVENT_LOOP;
+ break;
+ }
+ }
+
+ if (state->loop_type == GLIB_LOOP) {
+ state->loop = g_main_loop_new(NULL, false);
+ } else {
+ state->ev = tevent_context_init(mem_ctx);
+ if (CHECK_DEBUGLVL(10)) {
+ tevent_set_debug(state->ev, debug_fn, NULL);
+ }
+ state->glue = samba_tevent_glib_glue_create(
+ mem_ctx, state->ev, g_main_context_default());
+ if (state->glue == NULL) {
+ printf("tevent_glib_glue_create failed\n");
+ exit(1);
+ }
+ }
+
+ state->timer = g_timer_new();
+ state->cancellable = g_cancellable_new();
+ tracker_sparql_connection_get_async(state->cancellable,
+ connection_cb,
+ state);
+
+ if (state->loop_type == GLIB_LOOP) {
+ printf("entering g_main_loop_run\n");
+ g_main_loop_run(state->loop);
+ } else {
+ printf("entering tevent_loop_wait\n");
+ tevent_loop_wait(state->ev);
+
+ DBG_DEBUG("freeing glue\n");
+ TALLOC_FREE(state->glue);
+ DBG_DEBUG("freeing event context\n");
+ TALLOC_FREE(state->ev);
+ }
+
+ TALLOC_FREE(mem_ctx);
+ poptFreeContext(pc);
+
+ return 0;
+}
diff --git a/source3/wscript_build b/source3/wscript_build
index f2ca534..75fdd02 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -1392,6 +1392,17 @@ bld.SAMBA3_BINARY('tevent_glib_glue_test',
enabled=bld.CONFIG_SET('HAVE_GLIB'),
install=False)
+bld.SAMBA3_BINARY('tevent_glib_tracker',
+ source='utils/async-tracker.c',
+ deps='''
+ talloc
+ libsmb
+ popt_samba3
+ param
+ tevent-glib-glue ''' + bld.env['libtracker'],
+ enabled=bld.CONFIG_SET('HAVE_TRACKER'),
+ install=False)
+
bld.SAMBA3_BINARY('sharesec',
source='utils/sharesec.c lib/util_sd.c',
deps='''
--
2.5.0
From 1da7bca4a1ee806b0d5cf7a71a928201150cd628 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 27 Jan 2016 13:17:04 +0100
Subject: [PATCH 5/6] s3-mdssvc: add tevent context arg to mds_init_ctx
This is needed later when adding tevent_glib_glue support.
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/rpc_server/mdssvc/mdssvc.c | 1 +
source3/rpc_server/mdssvc/mdssvc.h | 1 +
source3/rpc_server/mdssvc/srv_mdssvc_nt.c | 6 +++++-
3 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/source3/rpc_server/mdssvc/mdssvc.c b/source3/rpc_server/mdssvc/mdssvc.c
index abfea43..9d1f206 100644
--- a/source3/rpc_server/mdssvc/mdssvc.c
+++ b/source3/rpc_server/mdssvc/mdssvc.c
@@ -1809,6 +1809,7 @@ static gboolean gmainloop_timer(gpointer user_data)
* Initialise a context per share handle
**/
struct mds_ctx *mds_init_ctx(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
const struct auth_session_info *session_info,
const char *path)
{
diff --git a/source3/rpc_server/mdssvc/mdssvc.h b/source3/rpc_server/mdssvc/mdssvc.h
index 2c9dc83..3bbcdd6 100644
--- a/source3/rpc_server/mdssvc/mdssvc.h
+++ b/source3/rpc_server/mdssvc/mdssvc.h
@@ -114,6 +114,7 @@ struct mds_ctx {
extern bool mds_init(struct messaging_context *msg_ctx);
extern bool mds_shutdown(void);
extern struct mds_ctx *mds_init_ctx(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
const struct auth_session_info *session_info,
const char *path);
extern int mds_ctx_destructor_cb(struct mds_ctx *mds_ctx);
diff --git a/source3/rpc_server/mdssvc/srv_mdssvc_nt.c b/source3/rpc_server/mdssvc/srv_mdssvc_nt.c
index cb0d759..d752140 100644
--- a/source3/rpc_server/mdssvc/srv_mdssvc_nt.c
+++ b/source3/rpc_server/mdssvc/srv_mdssvc_nt.c
@@ -18,6 +18,7 @@
*/
#include "includes.h"
+#include "messages.h"
#include "ntdomain.h"
#include "rpc_server/mdssvc/srv_mdssvc_nt.h"
#include "../librpc/gen_ndr/srv_mdssvc.h"
@@ -47,7 +48,10 @@ static NTSTATUS create_mdssvc_policy_handle(TALLOC_CTX *mem_ctx,
ZERO_STRUCTP(handle);
- mds_ctx = mds_init_ctx(mem_ctx, p->session_info, path);
+ mds_ctx = mds_init_ctx(mem_ctx,
+ messaging_tevent_context(p->msg_ctx),
+ p->session_info,
+ path);
if (mds_ctx == NULL) {
DEBUG(1, ("error in mds_init_ctx for: %s\n", path));
return NT_STATUS_UNSUCCESSFUL;
--
2.5.0
From c82af19817bd116c6e06c0108f65268d7825e1aa Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 27 Jan 2016 13:23:51 +0100
Subject: [PATCH 6/6] s3-mdssvc: use tevent_glib_glue in mdssvc RPC service
Signed-off-by: Ralph Boehme <slow at samba.org>
---
source3/rpc_server/mdssvc/mdssvc.c | 238 ++++++++++++++-----------------------
source3/rpc_server/mdssvc/mdssvc.h | 14 ++-
source3/rpc_server/wscript_build | 4 +-
3 files changed, 105 insertions(+), 151 deletions(-)
diff --git a/source3/rpc_server/mdssvc/mdssvc.c b/source3/rpc_server/mdssvc/mdssvc.c
index 9d1f206..af0d1ab 100644
--- a/source3/rpc_server/mdssvc/mdssvc.c
+++ b/source3/rpc_server/mdssvc/mdssvc.c
@@ -19,13 +19,16 @@
*/
#include "includes.h"
+#include "messages.h"
#include "librpc/gen_ndr/auth.h"
#include "dbwrap/dbwrap.h"
#include "lib/util/dlinklist.h"
#include "lib/util/util_tdb.h"
#include "lib/util/time_basic.h"
#include "lib/dbwrap/dbwrap_rbt.h"
+#include "lib/tevent_glib_glue.h"
#include "libcli/security/dom_sid.h"
+#include "rpc_server/mdssvc/srv_mdssvc_nt.h"
#include "mdssvc.h"
#include "sparql_parser.h"
@@ -65,6 +68,23 @@ struct slq_destroy_state {
};
/*
+ * Why must this be a local?
+ *
+ * Because the client will bind multiple times to the RPC service, one
+ * time for each tree connect and we don't want to end up with N*M (n
+ * client, m tree connects) connections to tracker.
+ *
+ * In the case of running the RPC service embedded (the default), this
+ * initialisation function is called from mds_init_ctx() which is
+ * called for every bind.
+ *
+ * In the case of running the RPC service external, we are called from
+ * mds_init() which is called right away when the RPC service process
+ * starts.
+ */
+static struct mdssvc_ctx *mdssvc_ctx;
+
+/*
* If these functions return an error, they hit something like a non
* recoverable talloc error. Most errors are dealt with by returning
* an errror code in the Spotlight RPC reply.
@@ -731,7 +751,6 @@ static void tracker_con_cb(GObject *object,
}
DEBUG(10, ("connected to Tracker\n"));
- g_main_loop_quit(mds_ctx->gmainloop);
}
static void tracker_cursor_cb_destroy_done(struct tevent_req *subreq);
@@ -770,7 +789,6 @@ static void tracker_cursor_cb(GObject *object,
* we return.
*/
SLQ_DEBUG(10, slq, "closed");
- g_main_loop_quit(slq->mds_ctx->gmainloop);
req = slq_destroy_send(slq, server_event_context(), &slq);
if (req == NULL) {
@@ -785,13 +803,11 @@ static void tracker_cursor_cb(GObject *object,
DEBUG(1, ("Tracker cursor: %s\n", error->message));
g_error_free(error);
slq->state = SLQ_STATE_ERROR;
- g_main_loop_quit(slq->mds_ctx->gmainloop);
return;
}
if (!more_results) {
slq->state = SLQ_STATE_DONE;
- g_main_loop_quit(slq->mds_ctx->gmainloop);
return;
}
@@ -799,31 +815,48 @@ static void tracker_cursor_cb(GObject *object,
if (uri == NULL) {
DEBUG(1, ("error fetching Tracker URI\n"));
slq->state = SLQ_STATE_ERROR;
- g_main_loop_quit(slq->mds_ctx->gmainloop);
return;
}
path = tracker_to_unix_path(slq->query_results, uri);
if (path == NULL) {
DEBUG(1, ("error converting Tracker URI to path: %s\n", uri));
slq->state = SLQ_STATE_ERROR;
- g_main_loop_quit(slq->mds_ctx->gmainloop);
return;
}
+ /*
+ * We're in a tevent callback which means in the case of
+ * running as external RPC service we're running as root and
+ * not as the user.
+ */
+ if (!become_authenticated_pipe_user(slq->mds_ctx->pipe_session_info)) {
+ DEBUG(0, ("can't become authenticated user: %d\n", slq->mds_ctx->uid));
+ smb_panic("can't become authenticated user");
+ }
+
if (geteuid() != slq->mds_ctx->uid) {
DEBUG(0, ("uid mismatch: %d/%d\n", geteuid(), slq->mds_ctx->uid));
smb_panic("uid mismatch");
}
+ /*
+ * We've changed identity to the authenticated pipe user, so
+ * any function exit below must ensure we switch back
+ */
+
result = sys_stat(path, &sb, false);
if (result != 0) {
+ unbecome_authenticated_pipe_user();
goto done;
}
result = access(path, R_OK);
if (result != 0) {
+ unbecome_authenticated_pipe_user();
goto done;
}
+ unbecome_authenticated_pipe_user();
+
ino64 = sb.st_ex_ino;
if (slq->cnids) {
/*
@@ -847,7 +880,6 @@ static void tracker_cursor_cb(GObject *object,
if (result != 0) {
DEBUG(1, ("dalloc error\n"));
slq->state = SLQ_STATE_ERROR;
- g_main_loop_quit(slq->mds_ctx->gmainloop);
return;
}
ok = add_filemeta(slq->reqinfo, slq->query_results->fm_array,
@@ -855,7 +887,6 @@ static void tracker_cursor_cb(GObject *object,
if (!ok) {
DEBUG(1, ("add_filemeta error\n"));
slq->state = SLQ_STATE_ERROR;
- g_main_loop_quit(slq->mds_ctx->gmainloop);
return;
}
@@ -863,7 +894,6 @@ static void tracker_cursor_cb(GObject *object,
if (!ok) {
DEBUG(1, ("inode_map_add error\n"));
slq->state = SLQ_STATE_ERROR;
- g_main_loop_quit(slq->mds_ctx->gmainloop);
return;
}
@@ -873,7 +903,6 @@ done:
if (slq->query_results->num_results >= MAX_SL_RESULTS) {
slq->state = SLQ_STATE_FULL;
SLQ_DEBUG(10, slq, "full");
- g_main_loop_quit(slq->mds_ctx->gmainloop);
return;
}
@@ -910,13 +939,11 @@ static void tracker_query_cb(GObject *object,
slq->state = SLQ_STATE_ERROR;
DEBUG(1, ("Tracker query error: %s\n", error->message));
g_error_free(error);
- g_main_loop_quit(slq->mds_ctx->gmainloop);
return;
}
if (slq->state == SLQ_STATE_DONE) {
SLQ_DEBUG(10, slq, "done");
- g_main_loop_quit(slq->mds_ctx->gmainloop);
talloc_free(slq);
return;
}
@@ -1273,13 +1300,11 @@ static bool slrpc_open_query(struct mds_ctx *mds_ctx,
DEBUG(10, ("SPARQL query: \"%s\"\n", slq->sparql_query));
- g_main_context_push_thread_default(mds_ctx->gcontext);
tracker_sparql_connection_query_async(mds_ctx->tracker_con,
slq->sparql_query,
slq->gcancellable,
tracker_query_cb,
slq);
- g_main_context_pop_thread_default(mds_ctx->gcontext);
slq->state = SLQ_STATE_RUNNING;
sl_result = 0;
@@ -1372,13 +1397,11 @@ static bool slrpc_fetch_query_results(struct mds_ctx *mds_ctx,
}
if (slq->state == SLQ_STATE_FULL) {
slq->state = SLQ_STATE_RESULTS;
- g_main_context_push_thread_default(mds_ctx->gcontext);
tracker_sparql_cursor_next_async(
slq->tracker_cursor,
slq->gcancellable,
tracker_cursor_cb,
slq);
- g_main_context_pop_thread_default(mds_ctx->gcontext);
}
break;
@@ -1782,35 +1805,68 @@ done:
return true;
}
-/**
- * Init callbacks at startup, nothing to do here really
- **/
-bool mds_init(struct messaging_context *msg_ctx)
+static struct mdssvc_ctx *mdssvc_init(struct tevent_context *ev)
{
- return true;
+ if (mdssvc_ctx != NULL) {
+ return mdssvc_ctx;
+ }
+
+ mdssvc_ctx = talloc_zero(ev, struct mdssvc_ctx);
+ if (mdssvc_ctx == NULL) {
+ return NULL;
+ }
+
+ mdssvc_ctx->ev_ctx = ev;
+
+ mdssvc_ctx->gmain_ctx = g_main_context_new();
+ if (mdssvc_ctx->gmain_ctx == NULL) {
+ DBG_ERR("error from g_main_context_new\n");
+ return NULL;
+ }
+
+ g_main_context_push_thread_default(mdssvc_ctx->gmain_ctx);
+
+ mdssvc_ctx->glue = samba_tevent_glib_glue_create(ev,
+ mdssvc_ctx->ev_ctx,
+ mdssvc_ctx->gmain_ctx);
+ if (mdssvc_ctx->glue == NULL) {
+ DBG_ERR("samba_tevent_glib_glue_create failed\n");
+ return NULL;
+ }
+
+ return mdssvc_ctx;
}
-bool mds_shutdown(void)
+bool mds_init(struct messaging_context *msg_ctx)
{
return true;
}
-static gboolean gmainloop_timer(gpointer user_data)
+bool mds_shutdown(void)
{
- struct mds_ctx *ctx = talloc_get_type_abort(user_data, struct mds_ctx);
+ if (mdssvc_ctx == NULL) {
+ return false;
+ }
+
+ samba_tevent_glib_glue_quit(mdssvc_ctx->glue);
+ TALLOC_FREE(mdssvc_ctx->glue);
+
+ g_main_context_pop_thread_default(mdssvc_ctx->gmain_ctx);
- DEBUG(10,("%s\n", __func__));
- g_main_loop_quit(ctx->gmainloop);
+ TALLOC_FREE(mdssvc_ctx);
- return G_SOURCE_CONTINUE;
+ return true;
}
/**
- * Initialise a context per share handle
+ * Initialise a context per RPC bind
+ *
+ * This ends up being called for every tcon, because the client does a
+ * RPC bind for every tcon, so this is acually a per tcon context.
**/
struct mds_ctx *mds_init_ctx(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
- const struct auth_session_info *session_info,
+ struct auth_session_info *session_info,
const char *path)
{
struct mds_ctx *mds_ctx;
@@ -1821,11 +1877,18 @@ struct mds_ctx *mds_init_ctx(TALLOC_CTX *mem_ctx,
}
talloc_set_destructor(mds_ctx, mds_ctx_destructor_cb);
+ mds_ctx->mdssvc_ctx = mdssvc_init(ev);
+ if (mds_ctx->mdssvc_ctx == NULL) {
+ goto error;
+ }
+
mds_ctx->spath = talloc_strdup(mds_ctx, path);
if (mds_ctx->spath == NULL) {
goto error;
}
+ mds_ctx->pipe_session_info = session_info;
+
if (session_info->security_token->num_sids < 1) {
goto error;
}
@@ -1838,22 +1901,8 @@ struct mds_ctx *mds_init_ctx(TALLOC_CTX *mem_ctx,
goto error;
}
- mds_ctx->gcontext = g_main_context_new();
- if (mds_ctx->gcontext == NULL) {
- DEBUG(1,("error from g_main_context_new\n"));
- goto error;
- }
-
- mds_ctx->gmainloop = g_main_loop_new(mds_ctx->gcontext, false);
- if (mds_ctx->gmainloop == NULL) {
- DEBUG(1,("error from g_main_loop_new\n"));
- goto error;
- }
-
- g_main_context_push_thread_default(mds_ctx->gcontext);
tracker_sparql_connection_get_async(mds_ctx->gcancellable,
tracker_con_cb, mds_ctx);
- g_main_context_pop_thread_default(mds_ctx->gcontext);
return mds_ctx;
@@ -1886,76 +1935,12 @@ int mds_ctx_destructor_cb(struct mds_ctx *mds_ctx)
g_cancellable_cancel(mds_ctx->gcancellable);
g_object_unref(mds_ctx->gcancellable);
}
- if (mds_ctx->gmainloop != NULL) {
- g_main_loop_unref(mds_ctx->gmainloop);
- }
- if (mds_ctx->gcontext != NULL) {
- g_main_context_unref(mds_ctx->gcontext);
- }
ZERO_STRUCTP(mds_ctx);
return 0;
}
-static bool mds_run_gmainloop(struct mds_ctx *mds_ctx, guint timeout)
-{
- guint timer_id;
- GSource *timer;
-
- /*
- * It seems the event processing of the libtracker-sparql
- * async subsystem defers callbacks until *all* events are
- * processes by the async subsystem main processing loop.
- *
- * g_main_context_iteration(may_block=FALSE) can't be used,
- * because a search that produces a few thousand matches
- * generates as many events that must be processed in either
- * g_main_context_iteration() or g_main_loop_run() before
- * callbacks are called.
- *
- * Unfortunately g_main_context_iteration() only processes a
- * small subset of these event (1-30) at a time when run in
- * mds_dispatch(), which happens once a second while the
- * client polls for results.
- *
- * Carefully using the blocking g_main_loop_run() fixes
- * this. It processes events until we exit from the loop at
- * defined exit points. By adding a 1 ms timeout we at least
- * try to get as close as possible to non-blocking behaviour.
- */
-
- if (!g_main_context_pending(mds_ctx->gcontext)) {
- return true;
- }
-
- g_main_context_push_thread_default(mds_ctx->gcontext);
-
- timer = g_timeout_source_new(timeout);
- if (timer == NULL) {
- DEBUG(1,("g_timeout_source_new_seconds\n"));
- g_main_context_pop_thread_default(mds_ctx->gcontext);
- return false;
- }
-
- timer_id = g_source_attach(timer, mds_ctx->gcontext);
- if (timer_id == 0) {
- DEBUG(1,("g_timeout_add failed\n"));
- g_source_destroy(timer);
- g_main_context_pop_thread_default(mds_ctx->gcontext);
- return false;
- }
-
- g_source_set_callback(timer, gmainloop_timer, mds_ctx, NULL);
-
- g_main_loop_run(mds_ctx->gmainloop);
-
- g_source_destroy(timer);
-
- g_main_context_pop_thread_default(mds_ctx->gcontext);
- return true;
-}
-
/**
* Dispatch a Spotlight RPC command
**/
@@ -1980,34 +1965,6 @@ bool mds_dispatch(struct mds_ctx *mds_ctx,
response_blob->length = 0;
- /*
- * Process finished glib events.
- *
- * FIXME: integrate with tevent instead of piggy packing it
- * onto the processing of new requests.
- *
- * mds_dispatch() is called by the client a few times in a row:
- *
- * - first in order to open/start a search query
- *
- * - later in order to fetch results asynchronously, typically
- * once a second. If no results have been retrieved from the
- * search store (Tracker) yet, we return no results.
- * The client asks for more results every second as long
- * as the "Search Window" in the client gui is open.
- *
- * - at some point the query is closed
- *
- * This means we try to iterate through the glib event loop
- * before processing the request in order to get result
- * from tracker which can be returned to the client.
- */
-
- ok = mds_run_gmainloop(mds_ctx, MDS_TRACKER_ASYNC_TIMEOUT_MS);
- if (!ok) {
- goto cleanup;
- }
-
DEBUG(10, ("share path: %s\n", mds_ctx->spath));
query = dalloc_new(mds_ctx);
@@ -2068,17 +2025,6 @@ bool mds_dispatch(struct mds_ctx *mds_ctx,
goto cleanup;
}
- /*
- * Run g_main_loop a second time in order to dispatch events
- * that may have been queued at the libtracker-sparql level.
- * As we only want to dispatch (write out requests) but not
- * wait for anything, we use a much shorter timeout here.
- */
- ok = mds_run_gmainloop(mds_ctx, MDS_TRACKER_ASYNC_TIMEOUT_MS / 10);
- if (!ok) {
- goto cleanup;
- }
-
response_blob->length = len;
cleanup:
diff --git a/source3/rpc_server/mdssvc/mdssvc.h b/source3/rpc_server/mdssvc/mdssvc.h
index 3bbcdd6..469ae90 100644
--- a/source3/rpc_server/mdssvc/mdssvc.h
+++ b/source3/rpc_server/mdssvc/mdssvc.h
@@ -92,14 +92,22 @@ struct sl_inode_path_map {
char *path;
};
+/* Per process state */
+struct mdssvc_ctx {
+ struct tevent_context *ev_ctx;
+ GMainContext *gmain_ctx;
+ struct tevent_glib_glue *glue;
+};
+
+/* Per tree connect state */
struct mds_ctx {
+ struct mdssvc_ctx *mdssvc_ctx;
+ struct auth_session_info *pipe_session_info;
struct dom_sid sid;
uid_t uid;
const char *spath;
GCancellable *gcancellable;
TrackerSparqlConnection *tracker_con;
- GMainContext *gcontext;
- GMainLoop *gmainloop;
struct sl_query *query_list; /* list of active queries */
struct db_context *ino_path_map; /* dbwrap rbt for storing inode->path mappings */
};
@@ -115,7 +123,7 @@ extern bool mds_init(struct messaging_context *msg_ctx);
extern bool mds_shutdown(void);
extern struct mds_ctx *mds_init_ctx(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
- const struct auth_session_info *session_info,
+ struct auth_session_info *session_info,
const char *path);
extern int mds_ctx_destructor_cb(struct mds_ctx *mds_ctx);
extern bool mds_dispatch(struct mds_ctx *query_ctx,
diff --git a/source3/rpc_server/wscript_build b/source3/rpc_server/wscript_build
index 278e0bd..7f0b971 100755
--- a/source3/rpc_server/wscript_build
+++ b/source3/rpc_server/wscript_build
@@ -137,7 +137,7 @@ bld.SAMBA3_SUBSYSTEM('RPC_MDSSVC',
mdssvc/sparql_lexer.c
mdssvc/srv_mdssvc_nt.c
../../librpc/gen_ndr/srv_mdssvc.c''',
- deps='samba-util ' + bld.env['libtracker'],
+ deps='samba-util tevent-glib-glue ' + bld.env['libtracker'],
enabled=bld.env.with_spotlight)
# RPC_SERVICE
@@ -189,5 +189,5 @@ bld.SAMBA3_SUBSYSTEM('FSSD',
bld.SAMBA3_SUBSYSTEM('MDSSD',
source='mdssd.c',
- deps='RPC_SOCK_HELPER samba-util',
+ deps='RPC_SOCK_HELPER samba-util tevent-glib-glue',
enabled=bld.env.with_spotlight)
--
2.5.0
More information about the samba-technical
mailing list