Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Infrastructure for async requests
4 : Copyright (C) Volker Lendecke 2008
5 : Copyright (C) Stefan Metzmacher 2009
6 :
7 : ** NOTE! The following LGPL license applies to the tevent
8 : ** library. This does NOT imply that all of Samba is released
9 : ** under the LGPL
10 :
11 : This library is free software; you can redistribute it and/or
12 : modify it under the terms of the GNU Lesser General Public
13 : License as published by the Free Software Foundation; either
14 : version 3 of the License, or (at your option) any later version.
15 :
16 : This library is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 : Lesser General Public License for more details.
20 :
21 : You should have received a copy of the GNU Lesser General Public
22 : License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include "replace.h"
26 : #include "tevent.h"
27 : #include "tevent_internal.h"
28 : #include "tevent_util.h"
29 :
30 0 : char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
31 : {
32 0 : return talloc_asprintf(mem_ctx,
33 : "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
34 : " state[%s (%p)] timer[%p] finish[%s]",
35 : req, req->internal.create_location,
36 0 : req->internal.state,
37 0 : (unsigned long long)req->internal.error,
38 0 : (unsigned long long)req->internal.error,
39 : req->internal.private_type,
40 : req->data,
41 : req->internal.timer,
42 : req->internal.finish_location
43 : );
44 : }
45 :
46 0 : char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
47 : {
48 0 : if (req == NULL) {
49 0 : return talloc_strdup(mem_ctx, "tevent_req[NULL]");
50 : }
51 :
52 0 : if (!req->private_print) {
53 0 : return tevent_req_default_print(req, mem_ctx);
54 : }
55 :
56 0 : return req->private_print(req, mem_ctx);
57 : }
58 :
59 : static int tevent_req_destructor(struct tevent_req *req);
60 :
61 75415211 : struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
62 : void *pdata,
63 : size_t data_size,
64 : const char *type,
65 : const char *location)
66 : {
67 : struct tevent_req *req;
68 : struct tevent_req *parent;
69 75415211 : void **ppdata = (void **)pdata;
70 : void *data;
71 : size_t payload;
72 :
73 75415211 : payload = sizeof(struct tevent_immediate) + data_size;
74 75415211 : if (payload < sizeof(struct tevent_immediate)) {
75 : /* overflow */
76 0 : return NULL;
77 : }
78 :
79 75415211 : req = talloc_pooled_object(
80 : mem_ctx, struct tevent_req, 2,
81 : sizeof(struct tevent_immediate) + data_size);
82 75415211 : if (req == NULL) {
83 0 : return NULL;
84 : }
85 :
86 75415211 : *req = (struct tevent_req) {
87 : .internal = {
88 : .private_type = type,
89 : .create_location = location,
90 : .state = TEVENT_REQ_IN_PROGRESS,
91 75415211 : .trigger = tevent_create_immediate(req),
92 : },
93 : };
94 :
95 75415211 : data = talloc_zero_size(req, data_size);
96 :
97 : /*
98 : * No need to check for req->internal.trigger!=NULL or
99 : * data!=NULL, this can't fail: talloc_pooled_object has
100 : * already allocated sufficient memory.
101 : */
102 :
103 75415211 : talloc_set_name_const(data, type);
104 :
105 75415211 : req->data = data;
106 :
107 75415211 : talloc_set_destructor(req, tevent_req_destructor);
108 :
109 75415211 : parent = talloc_get_type(talloc_parent(mem_ctx), struct tevent_req);
110 75415211 : if ((parent != NULL) && (parent->internal.profile != NULL)) {
111 306140 : bool ok = tevent_req_set_profile(req);
112 :
113 306140 : if (!ok) {
114 0 : TALLOC_FREE(req);
115 0 : return NULL;
116 : }
117 306140 : req->internal.profile->parent = parent->internal.profile;
118 306140 : DLIST_ADD_END(parent->internal.profile->subprofiles,
119 : req->internal.profile);
120 : }
121 :
122 75415211 : *ppdata = data;
123 :
124 : /* Initially, talloc_zero_size() sets internal.call_depth to 0 */
125 75415211 : if (parent != NULL && parent->internal.call_depth > 0) {
126 0 : req->internal.call_depth = parent->internal.call_depth + 1;
127 0 : tevent_thread_call_depth_set(req->internal.call_depth);
128 : }
129 :
130 75415211 : return req;
131 : }
132 :
133 1815554 : static int tevent_req_destructor(struct tevent_req *req)
134 : {
135 1815554 : tevent_req_received(req);
136 1815554 : return 0;
137 : }
138 :
139 89066520 : void _tevent_req_notify_callback(struct tevent_req *req, const char *location)
140 : {
141 89066520 : req->internal.finish_location = location;
142 89066520 : if (req->internal.defer_callback_ev) {
143 2060808 : (void)tevent_req_post(req, req->internal.defer_callback_ev);
144 2060808 : req->internal.defer_callback_ev = NULL;
145 2060808 : return;
146 : }
147 87005712 : if (req->async.fn != NULL) {
148 : /* Calling back the parent code, decrement the call depth. */
149 74790316 : tevent_thread_call_depth_set(req->internal.call_depth > 0 ?
150 0 : req->internal.call_depth - 1 : 0);
151 74790316 : req->async.fn(req);
152 : }
153 : }
154 :
155 164396291 : static void tevent_req_cleanup(struct tevent_req *req)
156 : {
157 164396291 : if (req->private_cleanup.fn == NULL) {
158 157268637 : return;
159 : }
160 :
161 7127654 : if (req->private_cleanup.state >= req->internal.state) {
162 : /*
163 : * Don't call the cleanup_function multiple times for the same
164 : * state recursively
165 : */
166 1122332 : return;
167 : }
168 :
169 6005322 : req->private_cleanup.state = req->internal.state;
170 6005322 : req->private_cleanup.fn(req, req->internal.state);
171 : }
172 :
173 88982832 : static void tevent_req_finish(struct tevent_req *req,
174 : enum tevent_req_state state,
175 : const char *location)
176 : {
177 : struct tevent_req_profile *p;
178 : /*
179 : * make sure we do not timeout after
180 : * the request was already finished
181 : */
182 88982832 : TALLOC_FREE(req->internal.timer);
183 :
184 88982832 : req->internal.state = state;
185 88982832 : req->internal.finish_location = location;
186 :
187 88982832 : tevent_req_cleanup(req);
188 :
189 88982832 : p = req->internal.profile;
190 :
191 88982832 : if (p != NULL) {
192 378651 : p->stop_location = location;
193 378651 : p->stop_time = tevent_timeval_current();
194 378651 : p->state = state;
195 378651 : p->user_error = req->internal.error;
196 :
197 378651 : if (p->parent != NULL) {
198 306130 : talloc_steal(p->parent, p);
199 306130 : req->internal.profile = NULL;
200 : }
201 : }
202 :
203 88982832 : _tevent_req_notify_callback(req, location);
204 88951740 : }
205 :
206 73980994 : void _tevent_req_done(struct tevent_req *req,
207 : const char *location)
208 : {
209 73980994 : tevent_req_finish(req, TEVENT_REQ_DONE, location);
210 73966252 : }
211 :
212 27585993 : bool _tevent_req_error(struct tevent_req *req,
213 : uint64_t error,
214 : const char *location)
215 : {
216 27585993 : if (error == 0) {
217 26456274 : return false;
218 : }
219 :
220 1129719 : req->internal.error = error;
221 1129719 : tevent_req_finish(req, TEVENT_REQ_USER_ERROR, location);
222 1128171 : return true;
223 : }
224 :
225 4 : void _tevent_req_oom(struct tevent_req *req, const char *location)
226 : {
227 4 : tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location);
228 4 : }
229 :
230 107185666 : bool _tevent_req_nomem(const void *p,
231 : struct tevent_req *req,
232 : const char *location)
233 : {
234 107185666 : if (p != NULL) {
235 107185662 : return false;
236 : }
237 4 : _tevent_req_oom(req, location);
238 4 : return true;
239 : }
240 :
241 : /**
242 : * @internal
243 : *
244 : * @brief Immediate event callback.
245 : *
246 : * @param[in] ev The event context to use.
247 : *
248 : * @param[in] im The immediate event.
249 : *
250 : * @param[in] priv The async request to be finished.
251 : */
252 13870484 : static void tevent_req_trigger(struct tevent_context *ev,
253 : struct tevent_immediate *im,
254 : void *private_data)
255 : {
256 : struct tevent_req *req =
257 13870484 : talloc_get_type_abort(private_data,
258 : struct tevent_req);
259 :
260 13870484 : tevent_req_finish(req, req->internal.state,
261 : req->internal.finish_location);
262 13855692 : }
263 :
264 14969961 : struct tevent_req *tevent_req_post(struct tevent_req *req,
265 : struct tevent_context *ev)
266 : {
267 14969961 : tevent_schedule_immediate(req->internal.trigger,
268 : ev, tevent_req_trigger, req);
269 14969961 : return req;
270 : }
271 :
272 2094120 : void tevent_req_defer_callback(struct tevent_req *req,
273 : struct tevent_context *ev)
274 : {
275 2094120 : req->internal.defer_callback_ev = ev;
276 2094120 : }
277 :
278 33250404 : bool tevent_req_is_in_progress(struct tevent_req *req)
279 : {
280 33250404 : if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
281 20648606 : return true;
282 : }
283 :
284 12601798 : return false;
285 : }
286 :
287 75413459 : void tevent_req_received(struct tevent_req *req)
288 : {
289 75413459 : talloc_set_destructor(req, NULL);
290 :
291 75413459 : req->private_print = NULL;
292 75413459 : req->private_cancel = NULL;
293 :
294 75413459 : TALLOC_FREE(req->internal.trigger);
295 75413459 : TALLOC_FREE(req->internal.timer);
296 :
297 75413459 : req->internal.state = TEVENT_REQ_RECEIVED;
298 :
299 75413459 : tevent_req_cleanup(req);
300 :
301 75413459 : TALLOC_FREE(req->data);
302 75413459 : }
303 :
304 315506 : bool tevent_req_poll(struct tevent_req *req,
305 : struct tevent_context *ev)
306 : {
307 3461716 : while (tevent_req_is_in_progress(req)) {
308 : int ret;
309 :
310 3146231 : ret = tevent_loop_once(ev);
311 3146210 : if (ret != 0) {
312 0 : return false;
313 : }
314 : }
315 :
316 315485 : return true;
317 : }
318 :
319 75179496 : bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
320 : uint64_t *error)
321 : {
322 75179496 : if (req->internal.state == TEVENT_REQ_DONE) {
323 74048329 : return false;
324 : }
325 1131167 : if (req->internal.state == TEVENT_REQ_USER_ERROR) {
326 1129736 : *error = req->internal.error;
327 : }
328 1131167 : *state = req->internal.state;
329 1131167 : return true;
330 : }
331 :
332 1631 : static void tevent_req_timedout(struct tevent_context *ev,
333 : struct tevent_timer *te,
334 : struct timeval now,
335 : void *private_data)
336 : {
337 : struct tevent_req *req =
338 1631 : talloc_get_type_abort(private_data,
339 : struct tevent_req);
340 :
341 1631 : TALLOC_FREE(req->internal.timer);
342 :
343 1631 : tevent_req_finish(req, TEVENT_REQ_TIMED_OUT, __FUNCTION__);
344 1621 : }
345 :
346 2170223 : bool tevent_req_set_endtime(struct tevent_req *req,
347 : struct tevent_context *ev,
348 : struct timeval endtime)
349 : {
350 2170223 : TALLOC_FREE(req->internal.timer);
351 :
352 2170223 : req->internal.timer = tevent_add_timer(ev, req, endtime,
353 : tevent_req_timedout,
354 : req);
355 2170223 : if (tevent_req_nomem(req->internal.timer, req)) {
356 0 : return false;
357 : }
358 :
359 2170223 : return true;
360 : }
361 :
362 921 : void tevent_req_reset_endtime(struct tevent_req *req)
363 : {
364 921 : TALLOC_FREE(req->internal.timer);
365 921 : }
366 :
367 75086312 : void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt)
368 : {
369 75086312 : req->async.fn = fn;
370 75086312 : req->async.private_data = pvt;
371 75086312 : }
372 :
373 74794337 : void *_tevent_req_callback_data(struct tevent_req *req)
374 : {
375 74794337 : return req->async.private_data;
376 : }
377 :
378 209656087 : void *_tevent_req_data(struct tevent_req *req)
379 : {
380 209656087 : return req->data;
381 : }
382 :
383 0 : void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn)
384 : {
385 0 : req->private_print = fn;
386 0 : }
387 :
388 2512712 : void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn)
389 : {
390 2512712 : req->private_cancel = fn;
391 2512712 : }
392 :
393 4767 : bool _tevent_req_cancel(struct tevent_req *req, const char *location)
394 : {
395 4767 : if (req->private_cancel == NULL) {
396 0 : return false;
397 : }
398 :
399 4767 : return req->private_cancel(req);
400 : }
401 :
402 5041196 : void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn)
403 : {
404 5041196 : req->private_cleanup.state = req->internal.state;
405 5041196 : req->private_cleanup.fn = fn;
406 5041196 : }
407 :
408 : static int tevent_req_profile_destructor(struct tevent_req_profile *p);
409 :
410 378661 : bool tevent_req_set_profile(struct tevent_req *req)
411 : {
412 : struct tevent_req_profile *p;
413 :
414 378661 : if (req->internal.profile != NULL) {
415 0 : tevent_req_error(req, EINVAL);
416 0 : return false;
417 : }
418 :
419 378661 : p = tevent_req_profile_create(req);
420 :
421 378661 : if (tevent_req_nomem(p, req)) {
422 0 : return false;
423 : }
424 :
425 378661 : p->req_name = talloc_get_name(req->data);
426 378661 : p->start_location = req->internal.create_location;
427 378661 : p->start_time = tevent_timeval_current();
428 :
429 378661 : req->internal.profile = p;
430 :
431 378661 : return true;
432 : }
433 :
434 378661 : static int tevent_req_profile_destructor(struct tevent_req_profile *p)
435 : {
436 378661 : if (p->parent != NULL) {
437 10 : DLIST_REMOVE(p->parent->subprofiles, p);
438 10 : p->parent = NULL;
439 : }
440 :
441 684791 : while (p->subprofiles != NULL) {
442 306130 : p->subprofiles->parent = NULL;
443 306130 : DLIST_REMOVE(p->subprofiles, p->subprofiles);
444 : }
445 :
446 378661 : return 0;
447 : }
448 :
449 72521 : struct tevent_req_profile *tevent_req_move_profile(struct tevent_req *req,
450 : TALLOC_CTX *mem_ctx)
451 : {
452 72521 : return talloc_move(mem_ctx, &req->internal.profile);
453 : }
454 :
455 0 : const struct tevent_req_profile *tevent_req_get_profile(
456 : struct tevent_req *req)
457 : {
458 0 : return req->internal.profile;
459 : }
460 :
461 0 : void tevent_req_profile_get_name(const struct tevent_req_profile *profile,
462 : const char **req_name)
463 : {
464 0 : if (req_name != NULL) {
465 0 : *req_name = profile->req_name;
466 : }
467 0 : }
468 :
469 72521 : void tevent_req_profile_get_start(const struct tevent_req_profile *profile,
470 : const char **start_location,
471 : struct timeval *start_time)
472 : {
473 72521 : if (start_location != NULL) {
474 0 : *start_location = profile->start_location;
475 : }
476 72521 : if (start_time != NULL) {
477 72521 : *start_time = profile->start_time;
478 : }
479 72521 : }
480 :
481 72521 : void tevent_req_profile_get_stop(const struct tevent_req_profile *profile,
482 : const char **stop_location,
483 : struct timeval *stop_time)
484 : {
485 72521 : if (stop_location != NULL) {
486 0 : *stop_location = profile->stop_location;
487 : }
488 72521 : if (stop_time != NULL) {
489 72521 : *stop_time = profile->stop_time;
490 : }
491 72521 : }
492 :
493 0 : void tevent_req_profile_get_status(const struct tevent_req_profile *profile,
494 : pid_t *pid,
495 : enum tevent_req_state *state,
496 : uint64_t *user_error)
497 : {
498 0 : if (pid != NULL) {
499 0 : *pid = profile->pid;
500 : }
501 0 : if (state != NULL) {
502 0 : *state = profile->state;
503 : }
504 0 : if (user_error != NULL) {
505 0 : *user_error = profile->user_error;
506 : }
507 0 : }
508 :
509 0 : const struct tevent_req_profile *tevent_req_profile_get_subprofiles(
510 : const struct tevent_req_profile *profile)
511 : {
512 0 : return profile->subprofiles;
513 : }
514 :
515 0 : const struct tevent_req_profile *tevent_req_profile_next(
516 : const struct tevent_req_profile *profile)
517 : {
518 0 : return profile->next;
519 : }
520 :
521 378661 : struct tevent_req_profile *tevent_req_profile_create(TALLOC_CTX *mem_ctx)
522 : {
523 : struct tevent_req_profile *result;
524 :
525 378661 : result = talloc_zero(mem_ctx, struct tevent_req_profile);
526 378661 : if (result == NULL) {
527 0 : return NULL;
528 : }
529 378661 : talloc_set_destructor(result, tevent_req_profile_destructor);
530 :
531 378661 : return result;
532 : }
533 :
534 0 : bool tevent_req_profile_set_name(struct tevent_req_profile *profile,
535 : const char *req_name)
536 : {
537 0 : profile->req_name = talloc_strdup(profile, req_name);
538 0 : return (profile->req_name != NULL);
539 : }
540 :
541 0 : bool tevent_req_profile_set_start(struct tevent_req_profile *profile,
542 : const char *start_location,
543 : struct timeval start_time)
544 : {
545 0 : profile->start_time = start_time;
546 :
547 0 : profile->start_location = talloc_strdup(profile, start_location);
548 0 : return (profile->start_location != NULL);
549 : }
550 :
551 0 : bool tevent_req_profile_set_stop(struct tevent_req_profile *profile,
552 : const char *stop_location,
553 : struct timeval stop_time)
554 : {
555 0 : profile->stop_time = stop_time;
556 :
557 0 : profile->stop_location = talloc_strdup(profile, stop_location);
558 0 : return (profile->stop_location != NULL);
559 : }
560 :
561 0 : void tevent_req_profile_set_status(struct tevent_req_profile *profile,
562 : pid_t pid,
563 : enum tevent_req_state state,
564 : uint64_t user_error)
565 : {
566 0 : profile->pid = pid;
567 0 : profile->state = state;
568 0 : profile->user_error = user_error;
569 0 : }
570 :
571 0 : void tevent_req_profile_append_sub(struct tevent_req_profile *parent_profile,
572 : struct tevent_req_profile **sub_profile)
573 : {
574 : struct tevent_req_profile *sub;
575 :
576 0 : sub = talloc_move(parent_profile, sub_profile);
577 :
578 0 : sub->parent = parent_profile;
579 0 : DLIST_ADD_END(parent_profile->subprofiles, sub);
580 0 : }
|