messaging: Add an indirection for messaging_dgm_register_tevent_context
authorVolker Lendecke <vl@samba.org>
Sat, 1 Oct 2016 04:53:44 +0000 (21:53 -0700)
committerVolker Lendecke <vl@samba.org>
Wed, 5 Oct 2016 09:47:17 +0000 (11:47 +0200)
Only one tevent_fd is possible for every file descriptor.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/lib/messages.c
source3/lib/messages_dgm.c
source3/lib/messages_dgm.h
source3/lib/messages_dgm_ref.c

index fd128e92018dee731c1c927dbc75472b9d03c160..08942a6d8abfab006429f4ff11b5a111b87f6b4c 100644 (file)
@@ -637,7 +637,7 @@ static struct messaging_rec *messaging_rec_dup(TALLOC_CTX *mem_ctx,
 struct messaging_filtered_read_state {
        struct tevent_context *ev;
        struct messaging_context *msg_ctx;
-       void *tevent_handle;
+       struct messaging_dgm_fde *fde;
 
        bool (*filter)(struct messaging_rec *rec, void *private_data);
        void *private_data;
@@ -674,9 +674,8 @@ struct tevent_req *messaging_filtered_read_send(
         */
        tevent_req_defer_callback(req, state->ev);
 
-       state->tevent_handle = messaging_dgm_register_tevent_context(
-               state, ev);
-       if (tevent_req_nomem(state->tevent_handle, req)) {
+       state->fde = messaging_dgm_register_tevent_context(state, ev);
+       if (tevent_req_nomem(state->fde, req)) {
                return tevent_req_post(req, ev);
        }
 
@@ -718,7 +717,7 @@ static void messaging_filtered_read_cleanup(struct tevent_req *req,
 
        tevent_req_set_cleanup_fn(req, NULL);
 
-       TALLOC_FREE(state->tevent_handle);
+       TALLOC_FREE(state->fde);
 
        /*
         * Just set the [new_]waiters entry to NULL, be careful not to mess
index 1ca163202fd9ed029813ffc378fc00bfcef66c4c..39b779bc24eb53100fb08d21d34c6d4837dd69fd 100644 (file)
@@ -41,6 +41,25 @@ struct sun_path_buf {
        char buf[sizeof(struct sockaddr_un)];
 };
 
+/*
+ * We can only have one tevent_fd per dgm_context and per
+ * tevent_context. Maintain a list of registered tevent_contexts per
+ * dgm_context.
+ */
+struct messaging_dgm_fde_ev {
+       struct messaging_dgm_fde_ev *prev, *next;
+
+       /*
+        * Backreference to enable DLIST_REMOVE from our
+        * destructor. Also, set to NULL when the dgm_context dies
+        * before the messaging_dgm_fde_ev.
+        */
+       struct messaging_dgm_context *ctx;
+
+       struct tevent_context *ev;
+       struct tevent_fd *fde;
+};
+
 struct messaging_dgm_out {
        struct messaging_dgm_out *prev, *next;
        struct messaging_dgm_context *ctx;
@@ -75,6 +94,7 @@ struct messaging_dgm_context {
        int sock;
        struct messaging_dgm_in_msg *in_msgs;
 
+       struct messaging_dgm_fde_ev *fde_evs;
        void (*recv_cb)(struct tevent_context *ev,
                        const uint8_t *msg,
                        size_t msg_len,
@@ -936,6 +956,11 @@ static int messaging_dgm_context_destructor(struct messaging_dgm_context *c)
        while (c->in_msgs != NULL) {
                TALLOC_FREE(c->in_msgs);
        }
+       while (c->fde_evs != NULL) {
+               tevent_fd_set_flags(c->fde_evs->fde, 0);
+               c->fde_evs->ctx = NULL;
+               DLIST_REMOVE(c->fde_evs, c->fde_evs);
+       }
 
        close(c->sock);
 
@@ -1349,14 +1374,83 @@ int messaging_dgm_wipe(void)
        return 0;
 }
 
-struct tevent_fd *messaging_dgm_register_tevent_context(
+struct messaging_dgm_fde {
+       struct tevent_fd *fde;
+};
+
+static int messaging_dgm_fde_ev_destructor(struct messaging_dgm_fde_ev *fde_ev)
+{
+       if (fde_ev->ctx != NULL) {
+               DLIST_REMOVE(fde_ev->ctx->fde_evs, fde_ev);
+               fde_ev->ctx = NULL;
+       }
+       return 0;
+}
+
+struct messaging_dgm_fde *messaging_dgm_register_tevent_context(
        TALLOC_CTX *mem_ctx, struct tevent_context *ev)
 {
        struct messaging_dgm_context *ctx = global_dgm_context;
+       struct messaging_dgm_fde_ev *fde_ev;
+       struct messaging_dgm_fde *fde;
 
        if (ctx == NULL) {
                return NULL;
        }
-       return tevent_add_fd(ev, mem_ctx, ctx->sock, TEVENT_FD_READ,
-                            messaging_dgm_read_handler, ctx);
+
+       fde = talloc(mem_ctx, struct messaging_dgm_fde);
+       if (fde == NULL) {
+               return NULL;
+       }
+
+       for (fde_ev = ctx->fde_evs; fde_ev != NULL; fde_ev = fde_ev->next) {
+               if ((fde_ev->ev == ev) &&
+                   (tevent_fd_get_flags(fde_ev->fde) != 0)) {
+                       break;
+               }
+       }
+
+       if (fde_ev == NULL) {
+               fde_ev = talloc(fde, struct messaging_dgm_fde_ev);
+               if (fde_ev == NULL) {
+                       return NULL;
+               }
+               fde_ev->fde = tevent_add_fd(
+                       ev, fde_ev, ctx->sock, TEVENT_FD_READ,
+                       messaging_dgm_read_handler, ctx);
+               if (fde_ev->fde == NULL) {
+                       TALLOC_FREE(fde);
+                       return NULL;
+               }
+               fde_ev->ev = ev;
+               fde_ev->ctx = ctx;
+               DLIST_ADD(ctx->fde_evs, fde_ev);
+               talloc_set_destructor(
+                       fde_ev, messaging_dgm_fde_ev_destructor);
+       } else {
+               /*
+                * Same trick as with tdb_wrap: The caller will never
+                * see the talloc_referenced object, the
+                * messaging_dgm_fde_ev, so problems with
+                * talloc_unlink will not happen.
+                */
+               if (talloc_reference(fde, fde_ev) == NULL) {
+                       TALLOC_FREE(fde);
+                       return NULL;
+               }
+       }
+
+       fde->fde = fde_ev->fde;
+       return fde;
+}
+
+bool messaging_dgm_fde_active(struct messaging_dgm_fde *fde)
+{
+       uint16_t flags;
+
+       if (fde == NULL) {
+               return false;
+       }
+       flags = tevent_fd_get_flags(fde->fde);
+       return (flags != 0);
 }
index 3d450a186fd93c6ac01a8c9ccaf6156f7e07bd14..ca11db1dacf1a516e06a3190e5f82c6d404687e5 100644 (file)
@@ -42,7 +42,10 @@ int messaging_dgm_send(pid_t pid,
                       const int *fds, size_t num_fds);
 int messaging_dgm_cleanup(pid_t pid);
 int messaging_dgm_wipe(void);
-struct tevent_fd *messaging_dgm_register_tevent_context(
+
+struct messaging_dgm_fde;
+struct messaging_dgm_fde *messaging_dgm_register_tevent_context(
        TALLOC_CTX *mem_ctx, struct tevent_context *ev);
+bool messaging_dgm_fde_active(struct messaging_dgm_fde *fde);
 
 #endif
index bc6b69fb62ed988dad33f93235e734b59c995b20..39d22700740c1492baade795db393077cdffceb4 100644 (file)
@@ -26,7 +26,7 @@
 
 struct msg_dgm_ref {
        struct msg_dgm_ref *prev, *next;
-       struct tevent_fd *tevent_handle;
+       struct messaging_dgm_fde *fde;
        void (*recv_cb)(struct tevent_context *ev,
                        const uint8_t *msg, size_t msg_len,
                        int *fds, size_t num_fds, void *private_data);
@@ -59,7 +59,7 @@ void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
                *err = ENOMEM;
                return NULL;
        }
-       result->tevent_handle = NULL;
+       result->fde = NULL;
 
        tmp_refs = refs;
 
@@ -98,9 +98,8 @@ void *messaging_dgm_ref(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
 
        }
 
-       result->tevent_handle = messaging_dgm_register_tevent_context(
-               result, ev);
-       if (result->tevent_handle == NULL) {
+       result->fde = messaging_dgm_register_tevent_context(result, ev);
+       if (result->fde == NULL) {
                TALLOC_FREE(result);
                *err = ENOMEM;
                return NULL;
@@ -129,12 +128,12 @@ static void msg_dgm_ref_recv(struct tevent_context *ev,
         * that grabs the fd's will get them.
         */
        for (r = refs; r != NULL; r = next) {
-               uint16_t flags;
+               bool active;
 
                next = r->next;
 
-               flags = tevent_fd_get_flags(r->tevent_handle);
-               if (flags == 0) {
+               active = messaging_dgm_fde_active(r->fde);
+               if (!active) {
                        /*
                         * r's tevent_context has died.
                         */
@@ -153,7 +152,7 @@ static int msg_dgm_ref_destructor(struct msg_dgm_ref *r)
        }
        DLIST_REMOVE(refs, r);
 
-       TALLOC_FREE(r->tevent_handle);
+       TALLOC_FREE(r->fde);
 
        DBG_DEBUG("refs=%p\n", refs);