librpc/rpc: add dcesrv_async_reply() helper that disconnects as needed
[Samba.git] / lib / tevent / tevent_immediate.c
blob82f92f1bd7862a6d046380ccd497d34eebd4e9ff
1 /*
2 Unix SMB/CIFS implementation.
4 common events code for immediate events
6 Copyright (C) Stefan Metzmacher 2009
8 ** NOTE! The following LGPL license applies to the tevent
9 ** library. This does NOT imply that all of Samba is released
10 ** under the LGPL
12 This library is free software; you can redistribute it and/or
13 modify it under the terms of the GNU Lesser General Public
14 License as published by the Free Software Foundation; either
15 version 3 of the License, or (at your option) any later version.
17 This library is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 Lesser General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public
23 License along with this library; if not, see <http://www.gnu.org/licenses/>.
26 #include "replace.h"
27 #define TEVENT_DEPRECATED 1
28 #include "tevent.h"
29 #include "tevent_internal.h"
30 #include "tevent_util.h"
32 static void tevent_common_immediate_cancel(struct tevent_immediate *im)
34 const char *create_location = im->create_location;
35 bool busy = im->busy;
36 uint64_t tag = im->tag;
37 struct tevent_context *detach_ev_ctx = NULL;
39 if (im->destroyed) {
40 tevent_abort(im->event_ctx, "tevent_immediate use after free");
41 return;
44 if (im->detach_ev_ctx != NULL) {
45 detach_ev_ctx = im->detach_ev_ctx;
46 im->detach_ev_ctx = NULL;
47 tevent_trace_immediate_callback(detach_ev_ctx,
48 im,
49 TEVENT_EVENT_TRACE_DETACH);
50 return;
53 if (!im->event_ctx) {
54 return;
57 if (im->handler_name != NULL) {
58 TEVENT_DEBUG(im->event_ctx, TEVENT_DEBUG_TRACE,
59 "Cancel immediate event %p \"%s\"\n",
60 im, im->handler_name);
63 /* let the backend free im->additional_data */
64 if (im->cancel_fn) {
65 im->cancel_fn(im);
68 if (busy && im->handler_name == NULL) {
69 detach_ev_ctx = im->event_ctx;
70 } else {
71 tevent_trace_immediate_callback(im->event_ctx,
72 im,
73 TEVENT_EVENT_TRACE_DETACH);
75 DLIST_REMOVE(im->event_ctx->immediate_events, im);
77 *im = (struct tevent_immediate) {
78 .create_location = create_location,
79 .busy = busy,
80 .tag = tag,
81 .detach_ev_ctx = detach_ev_ctx,
84 if (!busy) {
85 talloc_set_destructor(im, NULL);
90 destroy an immediate event
92 static int tevent_common_immediate_destructor(struct tevent_immediate *im)
94 if (im->destroyed) {
95 tevent_common_check_double_free(im,
96 "tevent_immediate double free");
97 goto done;
100 tevent_common_immediate_cancel(im);
102 im->destroyed = true;
104 done:
105 if (im->busy) {
106 return -1;
109 return 0;
113 * schedule an immediate event on
115 void tevent_common_schedule_immediate(struct tevent_immediate *im,
116 struct tevent_context *ev,
117 tevent_immediate_handler_t handler,
118 void *private_data,
119 const char *handler_name,
120 const char *location)
122 const char *create_location = im->create_location;
123 bool busy = im->busy;
124 uint64_t tag = im->tag;
125 struct tevent_wrapper_glue *glue = im->wrapper;
127 tevent_common_immediate_cancel(im);
129 if (!handler) {
130 return;
133 *im = (struct tevent_immediate) {
134 .event_ctx = ev,
135 .wrapper = glue,
136 .handler = handler,
137 .private_data = private_data,
138 .handler_name = handler_name,
139 .create_location = create_location,
140 .schedule_location = location,
141 .busy = busy,
142 .tag = tag,
145 tevent_trace_immediate_callback(im->event_ctx, im, TEVENT_EVENT_TRACE_ATTACH);
146 DLIST_ADD_END(ev->immediate_events, im);
147 talloc_set_destructor(im, tevent_common_immediate_destructor);
149 TEVENT_DEBUG(ev, TEVENT_DEBUG_TRACE,
150 "Schedule immediate event \"%s\": %p\n",
151 handler_name, im);
154 int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
155 bool *removed)
157 struct tevent_context *handler_ev = im->event_ctx;
158 struct tevent_context *ev = im->event_ctx;
159 struct tevent_immediate cur = *im;
161 if (removed != NULL) {
162 *removed = false;
165 TEVENT_DEBUG(ev, TEVENT_DEBUG_TRACE,
166 "Run immediate event \"%s\": %p\n",
167 im->handler_name, im);
170 * remember the handler and then clear the event
171 * the handler might reschedule the event
174 im->busy = true;
175 im->handler_name = NULL;
176 tevent_common_immediate_cancel(im);
177 if (cur.wrapper != NULL) {
178 handler_ev = cur.wrapper->wrap_ev;
180 tevent_wrapper_push_use_internal(handler_ev, cur.wrapper);
181 cur.wrapper->ops->before_immediate_handler(
182 cur.wrapper->wrap_ev,
183 cur.wrapper->private_state,
184 cur.wrapper->main_ev,
186 cur.handler_name,
187 cur.schedule_location);
189 tevent_trace_immediate_callback(cur.event_ctx, im, TEVENT_EVENT_TRACE_BEFORE_HANDLER);
190 cur.handler(handler_ev, im, cur.private_data);
191 if (cur.wrapper != NULL) {
192 cur.wrapper->ops->after_immediate_handler(
193 cur.wrapper->wrap_ev,
194 cur.wrapper->private_state,
195 cur.wrapper->main_ev,
197 cur.handler_name,
198 cur.schedule_location);
199 tevent_wrapper_pop_use_internal(handler_ev, cur.wrapper);
201 im->busy = false;
203 /* The event was removed in tevent_common_immediate_cancel(). */
204 if (im->detach_ev_ctx != NULL) {
205 struct tevent_context *detach_ev_ctx = im->detach_ev_ctx;
206 im->detach_ev_ctx = NULL;
207 tevent_trace_immediate_callback(detach_ev_ctx,
209 TEVENT_EVENT_TRACE_DETACH);
212 if (im->destroyed) {
213 talloc_set_destructor(im, NULL);
214 TALLOC_FREE(im);
215 if (removed != NULL) {
216 *removed = true;
220 return 0;
224 trigger the first immediate event and return true
225 if no event was triggered return false
227 bool tevent_common_loop_immediate(struct tevent_context *ev)
229 struct tevent_immediate *im = ev->immediate_events;
230 int ret;
232 if (!im) {
233 return false;
236 ret = tevent_common_invoke_immediate_handler(im, NULL);
237 if (ret != 0) {
238 tevent_abort(ev, "tevent_common_invoke_immediate_handler() failed");
241 return true;
245 void tevent_immediate_set_tag(struct tevent_immediate *im, uint64_t tag)
247 if (im == NULL) {
248 return;
251 im->tag = tag;
254 uint64_t tevent_immediate_get_tag(const struct tevent_immediate *im)
256 if (im == NULL) {
257 return 0;
260 return im->tag;