diff options
Diffstat (limited to 'source4/libcli/composite/composite.c')
-rw-r--r-- | source4/libcli/composite/composite.c | 65 |
1 files changed, 31 insertions, 34 deletions
diff --git a/source4/libcli/composite/composite.c b/source4/libcli/composite/composite.c index 3842ddfe9f..c9cc20e923 100644 --- a/source4/libcli/composite/composite.c +++ b/source4/libcli/composite/composite.c @@ -35,6 +35,8 @@ NTSTATUS composite_wait(struct composite_context *c) { if (c == NULL) return NT_STATUS_NO_MEMORY; + c->used_wait = True; + while (c->state < COMPOSITE_STATE_DONE) { if (event_loop_once(c->event_ctx) != 0) { return NT_STATUS_UNSUCCESSFUL; @@ -45,44 +47,10 @@ NTSTATUS composite_wait(struct composite_context *c) } -/* - callback from composite_trigger_done() and composite_trigger_error() -*/ -static void composite_trigger(struct event_context *ev, struct timed_event *te, - struct timeval t, void *ptr) -{ - struct composite_context *c = talloc_get_type(ptr, struct composite_context); - if (c->async.fn) { - c->async.fn(c); - } -} - - -/* - trigger an immediate 'done' event on a composite context - this is used when the composite code works out that the call - can be completed without waiting for any external event -*/ -void composite_trigger_done(struct composite_context *c) -{ - c->state = COMPOSITE_STATE_DONE; - /* a zero timeout means immediate */ - event_add_timed(c->event_ctx, c, timeval_zero(), composite_trigger, c); -} - -void composite_trigger_error(struct composite_context *c) -{ - c->state = COMPOSITE_STATE_ERROR; - /* a zero timeout means immediate */ - event_add_timed(c->event_ctx, c, timeval_zero(), composite_trigger, c); -} - - /* * Some composite helpers that are handy if you write larger composite * functions. */ - BOOL composite_is_ok(struct composite_context *ctx) { if (NT_STATUS_IS_OK(ctx->status)) { @@ -95,8 +63,34 @@ BOOL composite_is_ok(struct composite_context *ctx) return False; } +/* + callback from composite_done() and composite_error() + + this is used to allow for a composite function to complete without + going through any state transitions. When that happens the caller + has had no opportunity to fill in the async callback fields + (ctx->async.fn and ctx->async.private) which means the usual way of + dealing with composite functions doesn't work. To cope with this, + we trigger a timer event that will happen then the event loop is + re-entered. This gives the caller a chance to setup the callback, + and allows the caller to ignore the fact that the composite + function completed early +*/ +static void composite_trigger(struct event_context *ev, struct timed_event *te, + struct timeval t, void *ptr) +{ + struct composite_context *c = talloc_get_type(ptr, struct composite_context); + if (c->async.fn) { + c->async.fn(c); + } +} + + void composite_error(struct composite_context *ctx, NTSTATUS status) { + if (!ctx->used_wait && !ctx->async.fn) { + event_add_timed(ctx->event_ctx, ctx, timeval_zero(), composite_trigger, ctx); + } ctx->status = status; SMB_ASSERT(!composite_is_ok(ctx)); } @@ -112,6 +106,9 @@ BOOL composite_nomem(const void *p, struct composite_context *ctx) void composite_done(struct composite_context *ctx) { + if (!ctx->used_wait && !ctx->async.fn) { + event_add_timed(ctx->event_ctx, ctx, timeval_zero(), composite_trigger, ctx); + } ctx->state = COMPOSITE_STATE_DONE; if (ctx->async.fn != NULL) { ctx->async.fn(ctx); |