Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : common events code for immediate events
5 :
6 : Copyright (C) Stefan Metzmacher 2009
7 :
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
11 :
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.
16 :
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.
21 :
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/>.
24 : */
25 :
26 : #include "replace.h"
27 : #define TEVENT_DEPRECATED 1
28 : #include "tevent.h"
29 : #include "tevent_internal.h"
30 : #include "tevent_util.h"
31 :
32 47658032 : static void tevent_common_immediate_cancel(struct tevent_immediate *im)
33 : {
34 47658032 : const char *create_location = im->create_location;
35 47658032 : bool busy = im->busy;
36 47658032 : uint64_t tag = im->tag;
37 47658032 : struct tevent_context *detach_ev_ctx = NULL;
38 :
39 47658032 : if (im->destroyed) {
40 0 : tevent_abort(im->event_ctx, "tevent_immediate use after free");
41 30258859 : return;
42 : }
43 :
44 47658032 : if (im->detach_ev_ctx != NULL) {
45 14259293 : detach_ev_ctx = im->detach_ev_ctx;
46 14259293 : im->detach_ev_ctx = NULL;
47 14259293 : tevent_trace_immediate_callback(detach_ev_ctx,
48 : im,
49 : TEVENT_EVENT_TRACE_DETACH);
50 14259293 : return;
51 : }
52 :
53 33398739 : if (!im->event_ctx) {
54 15999566 : return;
55 : }
56 :
57 17399173 : if (im->handler_name != NULL) {
58 1218564 : tevent_debug(im->event_ctx, TEVENT_DEBUG_TRACE,
59 : "Cancel immediate event %p \"%s\"\n",
60 : im, im->handler_name);
61 : }
62 :
63 : /* let the backend free im->additional_data */
64 17399173 : if (im->cancel_fn) {
65 0 : im->cancel_fn(im);
66 : }
67 :
68 17399173 : if (busy && im->handler_name == NULL) {
69 16178886 : detach_ev_ctx = im->event_ctx;
70 : } else {
71 1220287 : tevent_trace_immediate_callback(im->event_ctx,
72 : im,
73 : TEVENT_EVENT_TRACE_DETACH);
74 : }
75 17399173 : DLIST_REMOVE(im->event_ctx->immediate_events, im);
76 :
77 17399173 : *im = (struct tevent_immediate) {
78 : .create_location = create_location,
79 : .busy = busy,
80 : .tag = tag,
81 : .detach_ev_ctx = detach_ev_ctx,
82 : };
83 :
84 17399173 : if (!busy) {
85 1220286 : talloc_set_destructor(im, NULL);
86 : }
87 : }
88 :
89 : /*
90 : destroy an immediate event
91 : */
92 88892503 : static int tevent_common_immediate_destructor(struct tevent_immediate *im)
93 : {
94 88892503 : if (im->destroyed) {
95 74810905 : tevent_common_check_double_free(im,
96 : "tevent_immediate double free");
97 74810905 : goto done;
98 : }
99 :
100 14081598 : tevent_common_immediate_cancel(im);
101 :
102 14081598 : im->destroyed = true;
103 :
104 88892503 : done:
105 88892503 : if (im->busy) {
106 88779130 : return -1;
107 : }
108 :
109 113373 : return 0;
110 : }
111 :
112 : /*
113 : * schedule an immediate event on
114 : */
115 17397548 : 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)
121 : {
122 17397548 : const char *create_location = im->create_location;
123 17397548 : bool busy = im->busy;
124 17397548 : uint64_t tag = im->tag;
125 17397548 : struct tevent_wrapper_glue *glue = im->wrapper;
126 :
127 17397548 : tevent_common_immediate_cancel(im);
128 :
129 17397548 : if (!handler) {
130 0 : return;
131 : }
132 :
133 17397548 : *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,
143 : };
144 :
145 17397548 : tevent_trace_immediate_callback(im->event_ctx, im, TEVENT_EVENT_TRACE_ATTACH);
146 17397548 : DLIST_ADD_END(ev->immediate_events, im);
147 17397548 : talloc_set_destructor(im, tevent_common_immediate_destructor);
148 :
149 17397548 : tevent_debug(ev, TEVENT_DEBUG_TRACE,
150 : "Schedule immediate event \"%s\": %p\n",
151 : handler_name, im);
152 : }
153 :
154 16178886 : int tevent_common_invoke_immediate_handler(struct tevent_immediate *im,
155 : bool *removed)
156 : {
157 16178886 : struct tevent_context *handler_ev = im->event_ctx;
158 16178886 : struct tevent_context *ev = im->event_ctx;
159 16178886 : struct tevent_immediate cur = *im;
160 :
161 16178886 : if (removed != NULL) {
162 0 : *removed = false;
163 : }
164 :
165 16178886 : tevent_debug(ev, TEVENT_DEBUG_TRACE,
166 : "Run immediate event \"%s\": %p\n",
167 : im->handler_name, im);
168 :
169 : /*
170 : * remember the handler and then clear the event
171 : * the handler might reschedule the event
172 : */
173 :
174 16178886 : im->busy = true;
175 16178886 : im->handler_name = NULL;
176 16178886 : tevent_common_immediate_cancel(im);
177 16178886 : if (cur.wrapper != NULL) {
178 0 : handler_ev = cur.wrapper->wrap_ev;
179 :
180 0 : tevent_wrapper_push_use_internal(handler_ev, cur.wrapper);
181 0 : cur.wrapper->ops->before_immediate_handler(
182 0 : cur.wrapper->wrap_ev,
183 0 : cur.wrapper->private_state,
184 0 : cur.wrapper->main_ev,
185 : im,
186 : cur.handler_name,
187 : cur.schedule_location);
188 : }
189 16178886 : tevent_trace_immediate_callback(cur.event_ctx, im, TEVENT_EVENT_TRACE_BEFORE_HANDLER);
190 16178886 : cur.handler(handler_ev, im, cur.private_data);
191 16164094 : if (cur.wrapper != NULL) {
192 0 : cur.wrapper->ops->after_immediate_handler(
193 0 : cur.wrapper->wrap_ev,
194 0 : cur.wrapper->private_state,
195 0 : cur.wrapper->main_ev,
196 : im,
197 : cur.handler_name,
198 : cur.schedule_location);
199 0 : tevent_wrapper_pop_use_internal(handler_ev, cur.wrapper);
200 : }
201 16164094 : im->busy = false;
202 :
203 : /* The event was removed in tevent_common_immediate_cancel(). */
204 16164094 : if (im->detach_ev_ctx != NULL) {
205 1919593 : struct tevent_context *detach_ev_ctx = im->detach_ev_ctx;
206 1919593 : im->detach_ev_ctx = NULL;
207 1919593 : tevent_trace_immediate_callback(detach_ev_ctx,
208 : im,
209 : TEVENT_EVENT_TRACE_DETACH);
210 : }
211 :
212 16164094 : if (im->destroyed) {
213 13953433 : talloc_set_destructor(im, NULL);
214 13953433 : TALLOC_FREE(im);
215 13953433 : if (removed != NULL) {
216 0 : *removed = true;
217 : }
218 : }
219 :
220 16164094 : return 0;
221 : }
222 :
223 : /*
224 : trigger the first immediate event and return true
225 : if no event was triggered return false
226 : */
227 16178886 : bool tevent_common_loop_immediate(struct tevent_context *ev)
228 : {
229 16178886 : struct tevent_immediate *im = ev->immediate_events;
230 : int ret;
231 :
232 16178886 : if (!im) {
233 0 : return false;
234 : }
235 :
236 16178886 : ret = tevent_common_invoke_immediate_handler(im, NULL);
237 16164094 : if (ret != 0) {
238 0 : tevent_abort(ev, "tevent_common_invoke_immediate_handler() failed");
239 : }
240 :
241 16164094 : return true;
242 : }
243 :
244 :
245 9 : void tevent_immediate_set_tag(struct tevent_immediate *im, uint64_t tag)
246 : {
247 9 : if (im == NULL) {
248 0 : return;
249 : }
250 :
251 9 : im->tag = tag;
252 : }
253 :
254 30 : uint64_t tevent_immediate_get_tag(const struct tevent_immediate *im)
255 : {
256 30 : if (im == NULL) {
257 0 : return 0;
258 : }
259 :
260 30 : return im->tag;
261 : }
|