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 10 : char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
35 : {
36 20 : 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 10 : req->internal.state,
41 10 : (unsigned long long)req->internal.error,
42 10 : (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 10 : char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
51 : {
52 10 : if (req == NULL) {
53 0 : return talloc_strdup(mem_ctx, "tevent_req[NULL]");
54 : }
55 :
56 10 : if (!req->private_print) {
57 10 : 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 140200503 : 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 720121 : struct tevent_req *req;
87 720121 : struct tevent_req *parent;
88 140200503 : void **ppdata = (void **)pdata;
89 720121 : void *data;
90 720121 : size_t payload;
91 :
92 140200503 : payload = sizeof(struct tevent_immediate) + data_size;
93 140200503 : if (payload < sizeof(struct tevent_immediate)) {
94 : /* overflow */
95 0 : return NULL;
96 : }
97 :
98 140200503 : req = talloc_pooled_object(
99 : mem_ctx, struct tevent_req, 2,
100 : sizeof(struct tevent_immediate) + data_size);
101 140200503 : if (req == NULL) {
102 0 : return NULL;
103 : }
104 :
105 140920624 : *req = (struct tevent_req) {
106 : .internal = {
107 : .private_type = type,
108 : .create_location = location,
109 : .state = TEVENT_REQ_IN_PROGRESS,
110 140200503 : .trigger = tevent_create_immediate(req),
111 : },
112 : };
113 :
114 140200503 : 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 140200503 : talloc_set_name_const(data, type);
123 :
124 140200503 : req->data = data;
125 :
126 140200503 : talloc_set_destructor(req, tevent_req_destructor);
127 :
128 140200503 : parent = talloc_get_type(talloc_parent(mem_ctx), struct tevent_req);
129 140200503 : if ((parent != NULL) && (parent->internal.profile != NULL)) {
130 3233962 : bool ok = tevent_req_set_profile(req);
131 :
132 3233962 : if (!ok) {
133 0 : TALLOC_FREE(req);
134 0 : return NULL;
135 : }
136 3233962 : req->internal.profile->parent = parent->internal.profile;
137 3233962 : DLIST_ADD_END(parent->internal.profile->subprofiles,
138 : req->internal.profile);
139 : }
140 :
141 140200503 : *ppdata = data;
142 :
143 : /* Initially, talloc_zero_size() sets internal.call_depth to 0 */
144 140200503 : if (parent != NULL) {
145 113285954 : req->internal.call_depth = parent->internal.call_depth + 1;
146 : }
147 140200503 : tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_CREATE,
148 : req,
149 : req->internal.call_depth,
150 : func);
151 :
152 139480382 : return req;
153 : }
154 :
155 10493830 : static int tevent_req_destructor(struct tevent_req *req)
156 : {
157 10493830 : tevent_req_received(req);
158 10493830 : return 0;
159 : }
160 :
161 165856250 : void _tevent_req_notify_callback(struct tevent_req *req, const char *location)
162 : {
163 165856250 : req->internal.finish_location = location;
164 165856250 : if (req->internal.defer_callback_ev) {
165 5774796 : (void)tevent_req_post(req, req->internal.defer_callback_ev);
166 5774796 : req->internal.defer_callback_ev = NULL;
167 5774796 : return;
168 : }
169 160081454 : if (req->async.fn != NULL) {
170 : /* Calling back the parent code, decrement the call depth. */
171 275395966 : size_t new_depth = req->internal.call_depth > 0 ?
172 137697983 : req->internal.call_depth - 1 : 0;
173 137697983 : tevent_thread_call_depth_notify(TEVENT_CALL_FLOW_REQ_NOTIFY_CB,
174 : req,
175 : new_depth,
176 : req->async.fn_name);
177 137697983 : req->async.fn(req);
178 : }
179 : }
180 :
181 304939039 : static void tevent_req_cleanup(struct tevent_req *req)
182 : {
183 304939039 : 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 3291590 : return;
189 : }
190 :
191 301623786 : 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 301623786 : if (req->private_cleanup.fn == NULL) {
197 282406067 : return;
198 : }
199 :
200 17834817 : req->private_cleanup.state = req->internal.state;
201 17834817 : req->private_cleanup.fn(req, req->internal.state);
202 : }
203 :
204 164743916 : static void tevent_req_finish(struct tevent_req *req,
205 : enum tevent_req_state state,
206 : const char *location)
207 : {
208 814639 : struct tevent_req_profile *p;
209 : /*
210 : * make sure we do not timeout after
211 : * the request was already finished
212 : */
213 164743916 : TALLOC_FREE(req->internal.timer);
214 :
215 164743916 : req->internal.state = state;
216 164743916 : req->internal.finish_location = location;
217 :
218 164743916 : tevent_req_cleanup(req);
219 :
220 164743916 : p = req->internal.profile;
221 :
222 164743916 : if (p != NULL) {
223 3453625 : p->stop_location = location;
224 3453625 : p->stop_time = tevent_timeval_current();
225 3453625 : p->state = state;
226 3453625 : p->user_error = req->internal.error;
227 :
228 3453625 : if (p->parent != NULL) {
229 3233942 : talloc_steal(p->parent, p);
230 3233942 : req->internal.profile = NULL;
231 : }
232 : }
233 :
234 164743916 : _tevent_req_notify_callback(req, location);
235 164709914 : }
236 :
237 137335246 : void _tevent_req_done(struct tevent_req *req,
238 : const char *location)
239 : {
240 137335246 : tevent_req_finish(req, TEVENT_REQ_DONE, location);
241 137320298 : }
242 :
243 37491913 : bool _tevent_req_error(struct tevent_req *req,
244 : uint64_t error,
245 : const char *location)
246 : {
247 37491913 : if (error == 0) {
248 35338711 : return false;
249 : }
250 :
251 1926786 : req->internal.error = error;
252 1926786 : tevent_req_finish(req, TEVENT_REQ_USER_ERROR, location);
253 1923912 : 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 206751666 : bool _tevent_req_nomem(const void *p,
262 : struct tevent_req *req,
263 : const char *location)
264 : {
265 206751666 : if (p != NULL) {
266 205487776 : 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 25453325 : static void tevent_req_trigger(struct tevent_context *ev,
284 : struct tevent_immediate *im,
285 : void *private_data)
286 : {
287 110537 : struct tevent_req *req =
288 25453325 : talloc_get_type_abort(private_data,
289 : struct tevent_req);
290 :
291 25453325 : tevent_req_finish(req, req->internal.state,
292 : req->internal.finish_location);
293 25437209 : }
294 :
295 29449229 : struct tevent_req *tevent_req_post(struct tevent_req *req,
296 : struct tevent_context *ev)
297 : {
298 29449229 : tevent_schedule_immediate(req->internal.trigger,
299 132684 : ev, tevent_req_trigger, req);
300 29449229 : return req;
301 : }
302 :
303 5969843 : void tevent_req_defer_callback(struct tevent_req *req,
304 : struct tevent_context *ev)
305 : {
306 5969843 : req->internal.defer_callback_ev = ev;
307 5969843 : }
308 :
309 73709072 : bool tevent_req_is_in_progress(struct tevent_req *req)
310 : {
311 73709072 : if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
312 48020323 : return true;
313 : }
314 :
315 25578603 : return false;
316 : }
317 :
318 140195123 : void tevent_req_received(struct tevent_req *req)
319 : {
320 140195123 : talloc_set_destructor(req, NULL);
321 :
322 140195123 : req->private_print = NULL;
323 140195123 : req->private_cancel.fn = NULL;
324 140195123 : req->private_cancel.fn_name = NULL;
325 :
326 140195123 : TALLOC_FREE(req->internal.trigger);
327 140195123 : TALLOC_FREE(req->internal.timer);
328 :
329 140195123 : req->internal.state = TEVENT_REQ_RECEIVED;
330 :
331 140195123 : tevent_req_cleanup(req);
332 :
333 140195123 : TALLOC_FREE(req->data);
334 140195123 : }
335 :
336 1640866 : bool tevent_req_poll(struct tevent_req *req,
337 : struct tevent_context *ev)
338 : {
339 12424782 : while (tevent_req_is_in_progress(req)) {
340 89151 : int ret;
341 :
342 10783990 : ret = tevent_loop_once(ev);
343 10783916 : if (ret != 0) {
344 0 : return false;
345 : }
346 : }
347 :
348 1631298 : return true;
349 : }
350 :
351 139605941 : bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
352 : uint64_t *error)
353 : {
354 139605941 : if (req->internal.state == TEVENT_REQ_DONE) {
355 136950337 : return false;
356 : }
357 1961100 : if (req->internal.state == TEVENT_REQ_USER_ERROR) {
358 1932729 : *error = req->internal.error;
359 : }
360 1961100 : *state = req->internal.state;
361 1961100 : return true;
362 : }
363 :
364 28553 : static void tevent_req_timedout(struct tevent_context *ev,
365 : struct tevent_timer *te,
366 : struct timeval now,
367 : void *private_data)
368 : {
369 28 : struct tevent_req *req =
370 28553 : talloc_get_type_abort(private_data,
371 : struct tevent_req);
372 :
373 28553 : TALLOC_FREE(req->internal.timer);
374 :
375 28553 : tevent_req_finish(req, TEVENT_REQ_TIMED_OUT, __FUNCTION__);
376 28541 : }
377 :
378 6261026 : bool tevent_req_set_endtime(struct tevent_req *req,
379 : struct tevent_context *ev,
380 : struct timeval endtime)
381 : {
382 6261026 : TALLOC_FREE(req->internal.timer);
383 :
384 6261026 : req->internal.timer = tevent_add_timer(ev, req, endtime,
385 : tevent_req_timedout,
386 : req);
387 6261026 : if (tevent_req_nomem(req->internal.timer, req)) {
388 0 : return false;
389 : }
390 :
391 6172790 : return true;
392 : }
393 :
394 52203 : void tevent_req_reset_endtime(struct tevent_req *req)
395 : {
396 52203 : TALLOC_FREE(req->internal.timer);
397 52203 : }
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 138500581 : void _tevent_req_set_callback(struct tevent_req *req,
405 : tevent_req_fn fn,
406 : const char *fn_name,
407 : void *pvt)
408 : {
409 138500581 : req->async.fn = fn;
410 138500581 : req->async.fn_name = fn_name;
411 138500581 : req->async.private_data = pvt;
412 138500581 : }
413 :
414 137710915 : void *_tevent_req_callback_data(struct tevent_req *req)
415 : {
416 137710915 : return req->async.private_data;
417 : }
418 :
419 390859793 : void *_tevent_req_data(struct tevent_req *req)
420 : {
421 390859793 : 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 7274149 : void _tevent_req_set_cancel_fn(struct tevent_req *req,
435 : tevent_req_cancel_fn fn,
436 : const char *fn_name)
437 : {
438 7274149 : req->private_cancel.fn = fn;
439 7274149 : req->private_cancel.fn_name = fn != NULL ? fn_name : NULL;
440 7274149 : }
441 :
442 13347 : bool _tevent_req_cancel(struct tevent_req *req, const char *location)
443 : {
444 13347 : 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 13347 : if (req->private_cancel.fn == NULL) {
450 10 : return false;
451 : }
452 :
453 13337 : 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 15009570 : void _tevent_req_set_cleanup_fn(struct tevent_req *req,
462 : tevent_req_cleanup_fn fn,
463 : const char *fn_name)
464 : {
465 15009570 : req->private_cleanup.state = req->internal.state;
466 15009570 : req->private_cleanup.fn = fn;
467 15009570 : req->private_cleanup.fn_name = fn != NULL ? fn_name : NULL;
468 15009570 : }
469 :
470 : static int tevent_req_profile_destructor(struct tevent_req_profile *p);
471 :
472 3453645 : bool tevent_req_set_profile(struct tevent_req *req)
473 : {
474 3 : struct tevent_req_profile *p;
475 :
476 3453645 : if (req->internal.profile != NULL) {
477 0 : tevent_req_error(req, EINVAL);
478 0 : return false;
479 : }
480 :
481 3453645 : p = tevent_req_profile_create(req);
482 :
483 3453645 : if (tevent_req_nomem(p, req)) {
484 0 : return false;
485 : }
486 :
487 3453645 : p->req_name = talloc_get_name(req->data);
488 3453645 : p->start_location = req->internal.create_location;
489 3453645 : p->start_time = tevent_timeval_current();
490 :
491 3453645 : req->internal.profile = p;
492 :
493 3453645 : return true;
494 : }
495 :
496 3453647 : static int tevent_req_profile_destructor(struct tevent_req_profile *p)
497 : {
498 3453647 : if (p->parent != NULL) {
499 20 : DLIST_REMOVE(p->parent->subprofiles, p);
500 20 : p->parent = NULL;
501 : }
502 :
503 6687590 : while (p->subprofiles != NULL) {
504 3233943 : p->subprofiles->parent = NULL;
505 3233948 : DLIST_REMOVE(p->subprofiles, p->subprofiles);
506 : }
507 :
508 3453647 : return 0;
509 : }
510 :
511 219683 : struct tevent_req_profile *tevent_req_move_profile(struct tevent_req *req,
512 : TALLOC_CTX *mem_ctx)
513 : {
514 219683 : 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 219696 : void tevent_req_profile_get_start(const struct tevent_req_profile *profile,
532 : const char **start_location,
533 : struct timeval *start_time)
534 : {
535 219696 : if (start_location != NULL) {
536 14 : *start_location = profile->start_location;
537 : }
538 219696 : if (start_time != NULL) {
539 219696 : *start_time = profile->start_time;
540 : }
541 219696 : }
542 :
543 219696 : void tevent_req_profile_get_stop(const struct tevent_req_profile *profile,
544 : const char **stop_location,
545 : struct timeval *stop_time)
546 : {
547 219696 : if (stop_location != NULL) {
548 14 : *stop_location = profile->stop_location;
549 : }
550 219696 : if (stop_time != NULL) {
551 219696 : *stop_time = profile->stop_time;
552 : }
553 219696 : }
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 3453647 : struct tevent_req_profile *tevent_req_profile_create(TALLOC_CTX *mem_ctx)
584 : {
585 5 : struct tevent_req_profile *result;
586 :
587 3453647 : result = talloc_zero(mem_ctx, struct tevent_req_profile);
588 3453647 : if (result == NULL) {
589 0 : return NULL;
590 : }
591 3453647 : talloc_set_destructor(result, tevent_req_profile_destructor);
592 :
593 3453647 : 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 : }
|