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 : #undef tevent_req_set_callback
31 : #undef tevent_req_set_cancel_fn
32 : #undef tevent_req_set_cleanup_fn
33 :
34 14 : char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
35 : {
36 28 : return talloc_asprintf(mem_ctx,
37 : "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
38 : " state[%s (%p)] timer[%p] finish[%s]",
39 : req, req->internal.create_location,
40 14 : req->internal.state,
41 14 : (unsigned long long)req->internal.error,
42 14 : (unsigned long long)req->internal.error,
43 : req->internal.private_type,
44 : req->data,
45 : req->internal.timer,
46 : req->internal.finish_location
47 : );
48 : }
49 :
50 14 : char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
51 : {
52 14 : if (req == NULL) {
53 0 : return talloc_strdup(mem_ctx, "tevent_req[NULL]");
54 : }
55 :
56 14 : if (!req->private_print) {
57 14 : return tevent_req_default_print(req, mem_ctx);
58 : }
59 :
60 0 : return req->private_print(req, mem_ctx);
61 : }
62 :
63 : static int tevent_req_destructor(struct tevent_req *req);
64 :
65 0 : struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
66 : void *pdata,
67 : size_t data_size,
68 : const char *type,
69 : const char *location)
70 : {
71 0 : return __tevent_req_create(mem_ctx,
72 : pdata,
73 : data_size,
74 : type,
75 : NULL,
76 : location);
77 : }
78 :
79 138032402 : struct tevent_req *__tevent_req_create(TALLOC_CTX *mem_ctx,
80 : void *pdata,
81 : size_t data_size,
82 : const char *type,
83 : const char *func,
84 : const char *location)
85 : {
86 776249 : struct tevent_req *req;
87 776249 : struct tevent_req *parent;
88 138032402 : void **ppdata = (void **)pdata;
89 776249 : void *data;
90 776249 : size_t payload;
91 :
92 138032402 : payload = sizeof(struct tevent_immediate) + data_size;
93 138032402 : if (payload < sizeof(struct tevent_immediate)) {
94 : /* overflow */
95 0 : return NULL;
96 : }
97 :
98 138032402 : req = talloc_pooled_object(
99 : mem_ctx, struct tevent_req, 2,
100 : sizeof(struct tevent_immediate) + data_size);
101 138032402 : if (req == NULL) {
102 0 : return NULL;
103 : }
104 :
105 138808651 : *req = (struct tevent_req) {
106 : .internal = {
107 : .private_type = type,
108 : .create_location = location,
109 : .state = TEVENT_REQ_IN_PROGRESS,
110 138032402 : .trigger = tevent_create_immediate(req),
111 : },
112 : };
113 :
114 138032402 : data = talloc_zero_size(req, data_size);
115 :
116 : /*
117 : * No need to check for req->internal.trigger!=NULL or
118 : * data!=NULL, this can't fail: talloc_pooled_object has
119 : * already allocated sufficient memory.
120 : */
121 :
122 138032402 : talloc_set_name_const(data, type);
123 :
124 138032402 : req->data = data;
125 :
126 138032402 : talloc_set_destructor(req, tevent_req_destructor);
127 :
128 138032402 : parent = talloc_get_type(talloc_parent(mem_ctx), struct tevent_req);
129 138032402 : if ((parent != NULL) && (parent->internal.profile != NULL)) {
130 3515038 : bool ok = tevent_req_set_profile(req);
131 :
132 3515038 : if (!ok) {
133 0 : TALLOC_FREE(req);
134 0 : return NULL;
135 : }
136 3515038 : req->internal.profile->parent = parent->internal.profile;
137 3515038 : DLIST_ADD_END(parent->internal.profile->subprofiles,
138 : req->internal.profile);
139 : }
140 :
141 138032402 : *ppdata = data;
142 :
143 : /* Initially, talloc_zero_size() sets internal.call_depth to 0 */
144 138032402 : if (parent != NULL) {
145 111461713 : req->internal.call_depth = parent->internal.call_depth + 1;
146 : }
147 138032402 : tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_CREATE,
148 : req,
149 : req->internal.call_depth,
150 : func);
151 :
152 137256153 : return req;
153 : }
154 :
155 10717885 : static int tevent_req_destructor(struct tevent_req *req)
156 : {
157 10717885 : tevent_req_received(req);
158 10717885 : return 0;
159 : }
160 :
161 163125407 : void _tevent_req_notify_callback(struct tevent_req *req, const char *location)
162 : {
163 163125407 : req->internal.finish_location = location;
164 163125407 : if (req->internal.defer_callback_ev) {
165 5839301 : (void)tevent_req_post(req, req->internal.defer_callback_ev);
166 5839301 : req->internal.defer_callback_ev = NULL;
167 5839301 : return;
168 : }
169 157286106 : if (req->async.fn != NULL) {
170 : /* Calling back the parent code, decrement the call depth. */
171 270829120 : size_t new_depth = req->internal.call_depth > 0 ?
172 135414560 : req->internal.call_depth - 1 : 0;
173 135414560 : tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_NOTIFY_CB,
174 : req,
175 : new_depth,
176 : req->async.fn_name);
177 135414560 : req->async.fn(req);
178 : }
179 : }
180 :
181 299965837 : static void tevent_req_cleanup(struct tevent_req *req)
182 : {
183 299965837 : if (req->private_cleanup.state >= req->internal.state) {
184 : /*
185 : * Don't call the cleanup_function multiple times for the same
186 : * state recursively
187 : */
188 3341751 : return;
189 : }
190 :
191 296600357 : tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_CLEANUP,
192 : req,
193 : req->internal.call_depth,
194 : req->private_cleanup.fn_name);
195 :
196 296600357 : if (req->private_cleanup.fn == NULL) {
197 277008938 : return;
198 : }
199 :
200 18095991 : req->private_cleanup.state = req->internal.state;
201 18095991 : req->private_cleanup.fn(req, req->internal.state);
202 : }
203 :
204 162004661 : static void tevent_req_finish(struct tevent_req *req,
205 : enum tevent_req_state state,
206 : const char *location)
207 : {
208 871400 : struct tevent_req_profile *p;
209 : /*
210 : * make sure we do not timeout after
211 : * the request was already finished
212 : */
213 162004661 : TALLOC_FREE(req->internal.timer);
214 :
215 162004661 : req->internal.state = state;
216 162004661 : req->internal.finish_location = location;
217 :
218 162004661 : tevent_req_cleanup(req);
219 :
220 162004661 : p = req->internal.profile;
221 :
222 162004661 : if (p != NULL) {
223 3769827 : p->stop_location = location;
224 3769827 : p->stop_time = tevent_timeval_current();
225 3769827 : p->state = state;
226 3769827 : p->user_error = req->internal.error;
227 :
228 3769827 : if (p->parent != NULL) {
229 3515018 : talloc_steal(p->parent, p);
230 3515018 : req->internal.profile = NULL;
231 : }
232 : }
233 :
234 162004661 : _tevent_req_notify_callback(req, location);
235 161970385 : }
236 :
237 135070373 : void _tevent_req_done(struct tevent_req *req,
238 : const char *location)
239 : {
240 135070373 : tevent_req_finish(req, TEVENT_REQ_DONE, location);
241 135055344 : }
242 :
243 36607673 : bool _tevent_req_error(struct tevent_req *req,
244 : uint64_t error,
245 : const char *location)
246 : {
247 36607673 : if (error == 0) {
248 34410695 : return false;
249 : }
250 :
251 1915497 : req->internal.error = error;
252 1915497 : tevent_req_finish(req, TEVENT_REQ_USER_ERROR, location);
253 1912511 : return true;
254 : }
255 :
256 6 : void _tevent_req_oom(struct tevent_req *req, const char *location)
257 : {
258 6 : tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location);
259 6 : }
260 :
261 204680067 : bool _tevent_req_nomem(const void *p,
262 : struct tevent_req *req,
263 : const char *location)
264 : {
265 204680067 : if (p != NULL) {
266 203264964 : return false;
267 : }
268 6 : _tevent_req_oom(req, location);
269 6 : return true;
270 : }
271 :
272 : /**
273 : * @internal
274 : *
275 : * @brief Immediate event callback.
276 : *
277 : * @param[in] ev The event context to use.
278 : *
279 : * @param[in] im The immediate event.
280 : *
281 : * @param[in] priv The async request to be finished.
282 : */
283 24991010 : static void tevent_req_trigger(struct tevent_context *ev,
284 : struct tevent_immediate *im,
285 : void *private_data)
286 : {
287 111187 : struct tevent_req *req =
288 24991010 : talloc_get_type_abort(private_data,
289 : struct tevent_req);
290 :
291 24991010 : tevent_req_finish(req, req->internal.state,
292 : req->internal.finish_location);
293 24974813 : }
294 :
295 29039999 : struct tevent_req *tevent_req_post(struct tevent_req *req,
296 : struct tevent_context *ev)
297 : {
298 29039999 : tevent_schedule_immediate(req->internal.trigger,
299 133400 : ev, tevent_req_trigger, req);
300 29039999 : return req;
301 : }
302 :
303 6037288 : void tevent_req_defer_callback(struct tevent_req *req,
304 : struct tevent_context *ev)
305 : {
306 6037288 : req->internal.defer_callback_ev = ev;
307 6037288 : }
308 :
309 72883597 : bool tevent_req_is_in_progress(struct tevent_req *req)
310 : {
311 72883597 : if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
312 47541310 : return true;
313 : }
314 :
315 25231557 : return false;
316 : }
317 :
318 137961176 : void tevent_req_received(struct tevent_req *req)
319 : {
320 137961176 : talloc_set_destructor(req, NULL);
321 :
322 137961176 : req->private_print = NULL;
323 137961176 : req->private_cancel.fn = NULL;
324 137961176 : req->private_cancel.fn_name = NULL;
325 :
326 137961176 : TALLOC_FREE(req->internal.trigger);
327 137961176 : TALLOC_FREE(req->internal.timer);
328 :
329 137961176 : req->internal.state = TEVENT_REQ_RECEIVED;
330 :
331 137961176 : tevent_req_cleanup(req);
332 :
333 137961176 : TALLOC_FREE(req->data);
334 137961176 : }
335 :
336 1649160 : bool tevent_req_poll(struct tevent_req *req,
337 : struct tevent_context *ev)
338 : {
339 12514869 : while (tevent_req_is_in_progress(req)) {
340 89871 : int ret;
341 :
342 10865784 : ret = tevent_loop_once(ev);
343 10865709 : if (ret != 0) {
344 0 : return false;
345 : }
346 : }
347 :
348 1639527 : return true;
349 : }
350 :
351 137333503 : bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
352 : uint64_t *error)
353 : {
354 137333503 : if (req->internal.state == TEVENT_REQ_DONE) {
355 134633619 : return false;
356 : }
357 1949187 : if (req->internal.state == TEVENT_REQ_USER_ERROR) {
358 1921594 : *error = req->internal.error;
359 : }
360 1949187 : *state = req->internal.state;
361 1949187 : return true;
362 : }
363 :
364 27775 : static void tevent_req_timedout(struct tevent_context *ev,
365 : struct tevent_timer *te,
366 : struct timeval now,
367 : void *private_data)
368 : {
369 31 : struct tevent_req *req =
370 27775 : talloc_get_type_abort(private_data,
371 : struct tevent_req);
372 :
373 27775 : TALLOC_FREE(req->internal.timer);
374 :
375 27775 : tevent_req_finish(req, TEVENT_REQ_TIMED_OUT, __FUNCTION__);
376 27763 : }
377 :
378 6341757 : bool tevent_req_set_endtime(struct tevent_req *req,
379 : struct tevent_context *ev,
380 : struct timeval endtime)
381 : {
382 6341757 : TALLOC_FREE(req->internal.timer);
383 :
384 6341757 : req->internal.timer = tevent_add_timer(ev, req, endtime,
385 : tevent_req_timedout,
386 : req);
387 6341757 : if (tevent_req_nomem(req->internal.timer, req)) {
388 0 : return false;
389 : }
390 :
391 6231211 : return true;
392 : }
393 :
394 70328 : void tevent_req_reset_endtime(struct tevent_req *req)
395 : {
396 70328 : TALLOC_FREE(req->internal.timer);
397 70328 : }
398 :
399 0 : void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt)
400 : {
401 0 : return _tevent_req_set_callback(req, fn, NULL, pvt);
402 : }
403 :
404 136323404 : void _tevent_req_set_callback(struct tevent_req *req,
405 : tevent_req_fn fn,
406 : const char *fn_name,
407 : void *pvt)
408 : {
409 136323404 : req->async.fn = fn;
410 136323404 : req->async.fn_name = fn_name;
411 136323404 : req->async.private_data = pvt;
412 136323404 : }
413 :
414 135428220 : void *_tevent_req_callback_data(struct tevent_req *req)
415 : {
416 135428220 : return req->async.private_data;
417 : }
418 :
419 385159435 : void *_tevent_req_data(struct tevent_req *req)
420 : {
421 385159435 : return req->data;
422 : }
423 :
424 0 : void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn)
425 : {
426 0 : req->private_print = fn;
427 0 : }
428 :
429 0 : void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn)
430 : {
431 0 : _tevent_req_set_cancel_fn(req, fn, NULL);
432 0 : }
433 :
434 7348354 : void _tevent_req_set_cancel_fn(struct tevent_req *req,
435 : tevent_req_cancel_fn fn,
436 : const char *fn_name)
437 : {
438 7348354 : req->private_cancel.fn = fn;
439 7348354 : req->private_cancel.fn_name = fn != NULL ? fn_name : NULL;
440 7348354 : }
441 :
442 13301 : bool _tevent_req_cancel(struct tevent_req *req, const char *location)
443 : {
444 13301 : tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_CANCEL,
445 : req,
446 : req->internal.call_depth,
447 : req->private_cancel.fn_name);
448 :
449 13301 : if (req->private_cancel.fn == NULL) {
450 10 : return false;
451 : }
452 :
453 13291 : return req->private_cancel.fn(req);
454 : }
455 :
456 0 : void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn)
457 : {
458 0 : _tevent_req_set_cleanup_fn(req, fn, NULL);
459 0 : }
460 :
461 15186875 : void _tevent_req_set_cleanup_fn(struct tevent_req *req,
462 : tevent_req_cleanup_fn fn,
463 : const char *fn_name)
464 : {
465 15186875 : req->private_cleanup.state = req->internal.state;
466 15186875 : req->private_cleanup.fn = fn;
467 15186875 : req->private_cleanup.fn_name = fn != NULL ? fn_name : NULL;
468 15186875 : }
469 :
470 : static int tevent_req_profile_destructor(struct tevent_req_profile *p);
471 :
472 3769847 : bool tevent_req_set_profile(struct tevent_req *req)
473 : {
474 3 : struct tevent_req_profile *p;
475 :
476 3769847 : if (req->internal.profile != NULL) {
477 0 : tevent_req_error(req, EINVAL);
478 0 : return false;
479 : }
480 :
481 3769847 : p = tevent_req_profile_create(req);
482 :
483 3769847 : if (tevent_req_nomem(p, req)) {
484 0 : return false;
485 : }
486 :
487 3769847 : p->req_name = talloc_get_name(req->data);
488 3769847 : p->start_location = req->internal.create_location;
489 3769847 : p->start_time = tevent_timeval_current();
490 :
491 3769847 : req->internal.profile = p;
492 :
493 3769847 : return true;
494 : }
495 :
496 3769849 : static int tevent_req_profile_destructor(struct tevent_req_profile *p)
497 : {
498 3769849 : if (p->parent != NULL) {
499 20 : DLIST_REMOVE(p->parent->subprofiles, p);
500 20 : p->parent = NULL;
501 : }
502 :
503 7284868 : while (p->subprofiles != NULL) {
504 3515019 : p->subprofiles->parent = NULL;
505 3515024 : DLIST_REMOVE(p->subprofiles, p->subprofiles);
506 : }
507 :
508 3769849 : return 0;
509 : }
510 :
511 254809 : struct tevent_req_profile *tevent_req_move_profile(struct tevent_req *req,
512 : TALLOC_CTX *mem_ctx)
513 : {
514 254809 : return talloc_move(mem_ctx, &req->internal.profile);
515 : }
516 :
517 1 : const struct tevent_req_profile *tevent_req_get_profile(
518 : struct tevent_req *req)
519 : {
520 1 : return req->internal.profile;
521 : }
522 :
523 14 : void tevent_req_profile_get_name(const struct tevent_req_profile *profile,
524 : const char **req_name)
525 : {
526 14 : if (req_name != NULL) {
527 14 : *req_name = profile->req_name;
528 : }
529 14 : }
530 :
531 254822 : void tevent_req_profile_get_start(const struct tevent_req_profile *profile,
532 : const char **start_location,
533 : struct timeval *start_time)
534 : {
535 254822 : if (start_location != NULL) {
536 14 : *start_location = profile->start_location;
537 : }
538 254822 : if (start_time != NULL) {
539 254822 : *start_time = profile->start_time;
540 : }
541 254822 : }
542 :
543 254822 : void tevent_req_profile_get_stop(const struct tevent_req_profile *profile,
544 : const char **stop_location,
545 : struct timeval *stop_time)
546 : {
547 254822 : if (stop_location != NULL) {
548 14 : *stop_location = profile->stop_location;
549 : }
550 254822 : if (stop_time != NULL) {
551 254822 : *stop_time = profile->stop_time;
552 : }
553 254822 : }
554 :
555 14 : void tevent_req_profile_get_status(const struct tevent_req_profile *profile,
556 : pid_t *pid,
557 : enum tevent_req_state *state,
558 : uint64_t *user_error)
559 : {
560 14 : if (pid != NULL) {
561 14 : *pid = profile->pid;
562 : }
563 14 : if (state != NULL) {
564 14 : *state = profile->state;
565 : }
566 14 : if (user_error != NULL) {
567 14 : *user_error = profile->user_error;
568 : }
569 14 : }
570 :
571 16 : const struct tevent_req_profile *tevent_req_profile_get_subprofiles(
572 : const struct tevent_req_profile *profile)
573 : {
574 16 : return profile->subprofiles;
575 : }
576 :
577 8 : const struct tevent_req_profile *tevent_req_profile_next(
578 : const struct tevent_req_profile *profile)
579 : {
580 8 : return profile->next;
581 : }
582 :
583 3769849 : struct tevent_req_profile *tevent_req_profile_create(TALLOC_CTX *mem_ctx)
584 : {
585 5 : struct tevent_req_profile *result;
586 :
587 3769849 : result = talloc_zero(mem_ctx, struct tevent_req_profile);
588 3769849 : if (result == NULL) {
589 0 : return NULL;
590 : }
591 3769849 : talloc_set_destructor(result, tevent_req_profile_destructor);
592 :
593 3769849 : return result;
594 : }
595 :
596 2 : bool tevent_req_profile_set_name(struct tevent_req_profile *profile,
597 : const char *req_name)
598 : {
599 2 : profile->req_name = talloc_strdup(profile, req_name);
600 2 : return (profile->req_name != NULL);
601 : }
602 :
603 2 : bool tevent_req_profile_set_start(struct tevent_req_profile *profile,
604 : const char *start_location,
605 : struct timeval start_time)
606 : {
607 2 : profile->start_time = start_time;
608 :
609 2 : profile->start_location = talloc_strdup(profile, start_location);
610 2 : return (profile->start_location != NULL);
611 : }
612 :
613 2 : bool tevent_req_profile_set_stop(struct tevent_req_profile *profile,
614 : const char *stop_location,
615 : struct timeval stop_time)
616 : {
617 2 : profile->stop_time = stop_time;
618 :
619 2 : profile->stop_location = talloc_strdup(profile, stop_location);
620 2 : return (profile->stop_location != NULL);
621 : }
622 :
623 2 : void tevent_req_profile_set_status(struct tevent_req_profile *profile,
624 : pid_t pid,
625 : enum tevent_req_state state,
626 : uint64_t user_error)
627 : {
628 2 : profile->pid = pid;
629 2 : profile->state = state;
630 2 : profile->user_error = user_error;
631 2 : }
632 :
633 1 : void tevent_req_profile_append_sub(struct tevent_req_profile *parent_profile,
634 : struct tevent_req_profile **sub_profile)
635 : {
636 1 : struct tevent_req_profile *sub;
637 :
638 1 : sub = talloc_move(parent_profile, sub_profile);
639 :
640 1 : sub->parent = parent_profile;
641 1 : DLIST_ADD_END(parent_profile->subprofiles, sub);
642 1 : }
|