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 76000450 : 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 76000450 : void **ppdata = (void **)pdata;
70 : void *data;
71 : size_t payload;
72 :
73 76000450 : payload = sizeof(struct tevent_immediate) + data_size;
74 76000450 : if (payload < sizeof(struct tevent_immediate)) {
75 : /* overflow */
76 0 : return NULL;
77 : }
78 :
79 76000450 : req = talloc_pooled_object(
80 : mem_ctx, struct tevent_req, 2,
81 : sizeof(struct tevent_immediate) + data_size);
82 76000450 : if (req == NULL) {
83 0 : return NULL;
84 : }
85 :
86 76000450 : *req = (struct tevent_req) {
87 : .internal = {
88 : .private_type = type,
89 : .create_location = location,
90 : .state = TEVENT_REQ_IN_PROGRESS,
91 76000450 : .trigger = tevent_create_immediate(req),
92 : },
93 : };
94 :
95 76000450 : 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 76000450 : talloc_set_name_const(data, type);
104 :
105 76000450 : req->data = data;
106 :
107 76000450 : talloc_set_destructor(req, tevent_req_destructor);
108 :
109 76000450 : parent = talloc_get_type(talloc_parent(mem_ctx), struct tevent_req);
110 76000450 : if ((parent != NULL) && (parent->internal.profile != NULL)) {
111 281748 : bool ok = tevent_req_set_profile(req);
112 :
113 281748 : if (!ok) {
114 0 : TALLOC_FREE(req);
115 0 : return NULL;
116 : }
117 281748 : req->internal.profile->parent = parent->internal.profile;
118 281748 : DLIST_ADD_END(parent->internal.profile->subprofiles,
119 : req->internal.profile);
120 : }
121 :
122 76000450 : *ppdata = data;
123 76000450 : return req;
124 : }
125 :
126 1859823 : static int tevent_req_destructor(struct tevent_req *req)
127 : {
128 1859823 : tevent_req_received(req);
129 1859823 : return 0;
130 : }
131 :
132 89841790 : void _tevent_req_notify_callback(struct tevent_req *req, const char *location)
133 : {
134 89841790 : req->internal.finish_location = location;
135 89841790 : if (req->internal.defer_callback_ev) {
136 2035283 : (void)tevent_req_post(req, req->internal.defer_callback_ev);
137 2035283 : req->internal.defer_callback_ev = NULL;
138 2035283 : return;
139 : }
140 87806507 : if (req->async.fn != NULL) {
141 75394631 : req->async.fn(req);
142 : }
143 : }
144 :
145 165758746 : static void tevent_req_cleanup(struct tevent_req *req)
146 : {
147 165758746 : if (req->private_cleanup.fn == NULL) {
148 158816758 : return;
149 : }
150 :
151 6941988 : if (req->private_cleanup.state >= req->internal.state) {
152 : /*
153 : * Don't call the cleanup_function multiple times for the same
154 : * state recursively
155 : */
156 1101369 : return;
157 : }
158 :
159 5840619 : req->private_cleanup.state = req->internal.state;
160 5840619 : req->private_cleanup.fn(req, req->internal.state);
161 : }
162 :
163 89760057 : static void tevent_req_finish(struct tevent_req *req,
164 : enum tevent_req_state state,
165 : const char *location)
166 : {
167 : struct tevent_req_profile *p;
168 : /*
169 : * make sure we do not timeout after
170 : * the request was already finished
171 : */
172 89760057 : TALLOC_FREE(req->internal.timer);
173 :
174 89760057 : req->internal.state = state;
175 89760057 : req->internal.finish_location = location;
176 :
177 89760057 : tevent_req_cleanup(req);
178 :
179 89760057 : p = req->internal.profile;
180 :
181 89760057 : if (p != NULL) {
182 339652 : p->stop_location = location;
183 339652 : p->stop_time = tevent_timeval_current();
184 339652 : p->state = state;
185 339652 : p->user_error = req->internal.error;
186 :
187 339652 : if (p->parent != NULL) {
188 281738 : talloc_steal(p->parent, p);
189 281738 : req->internal.profile = NULL;
190 : }
191 : }
192 :
193 89760057 : _tevent_req_notify_callback(req, location);
194 89733419 : }
195 :
196 74568560 : void _tevent_req_done(struct tevent_req *req,
197 : const char *location)
198 : {
199 74568560 : tevent_req_finish(req, TEVENT_REQ_DONE, location);
200 74556035 : }
201 :
202 28118485 : bool _tevent_req_error(struct tevent_req *req,
203 : uint64_t error,
204 : const char *location)
205 : {
206 28118485 : if (error == 0) {
207 26975853 : return false;
208 : }
209 :
210 1142632 : req->internal.error = error;
211 1142632 : tevent_req_finish(req, TEVENT_REQ_USER_ERROR, location);
212 1141104 : return true;
213 : }
214 :
215 4 : void _tevent_req_oom(struct tevent_req *req, const char *location)
216 : {
217 4 : tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location);
218 4 : }
219 :
220 106814598 : bool _tevent_req_nomem(const void *p,
221 : struct tevent_req *req,
222 : const char *location)
223 : {
224 106814598 : if (p != NULL) {
225 106814594 : return false;
226 : }
227 4 : _tevent_req_oom(req, location);
228 4 : return true;
229 : }
230 :
231 : /**
232 : * @internal
233 : *
234 : * @brief Immediate event callback.
235 : *
236 : * @param[in] ev The event context to use.
237 : *
238 : * @param[in] im The immediate event.
239 : *
240 : * @param[in] priv The async request to be finished.
241 : */
242 14047283 : static void tevent_req_trigger(struct tevent_context *ev,
243 : struct tevent_immediate *im,
244 : void *private_data)
245 : {
246 12414465 : struct tevent_req *req =
247 1632818 : talloc_get_type_abort(private_data,
248 : struct tevent_req);
249 :
250 14047283 : tevent_req_finish(req, req->internal.state,
251 : req->internal.finish_location);
252 14034708 : }
253 :
254 15126590 : struct tevent_req *tevent_req_post(struct tevent_req *req,
255 : struct tevent_context *ev)
256 : {
257 15126590 : tevent_schedule_immediate(req->internal.trigger,
258 : ev, tevent_req_trigger, req);
259 15126590 : return req;
260 : }
261 :
262 2068704 : void tevent_req_defer_callback(struct tevent_req *req,
263 : struct tevent_context *ev)
264 : {
265 2068704 : req->internal.defer_callback_ev = ev;
266 2068704 : }
267 :
268 33457426 : bool tevent_req_is_in_progress(struct tevent_req *req)
269 : {
270 33457426 : if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
271 20718010 : return true;
272 : }
273 :
274 12739416 : return false;
275 : }
276 :
277 75998689 : void tevent_req_received(struct tevent_req *req)
278 : {
279 75998689 : talloc_set_destructor(req, NULL);
280 :
281 75998689 : req->private_print = NULL;
282 75998689 : req->private_cancel = NULL;
283 :
284 75998689 : TALLOC_FREE(req->internal.trigger);
285 75998689 : TALLOC_FREE(req->internal.timer);
286 :
287 75998689 : req->internal.state = TEVENT_REQ_RECEIVED;
288 :
289 75998689 : tevent_req_cleanup(req);
290 :
291 75998689 : TALLOC_FREE(req->data);
292 75998689 : }
293 :
294 311548 : bool tevent_req_poll(struct tevent_req *req,
295 : struct tevent_context *ev)
296 : {
297 3718945 : while (tevent_req_is_in_progress(req)) {
298 : int ret;
299 :
300 3150061 : ret = tevent_loop_once(ev);
301 3150040 : if (ret != 0) {
302 0 : return false;
303 : }
304 : }
305 :
306 311527 : return true;
307 : }
308 :
309 75780041 : bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
310 : uint64_t *error)
311 : {
312 75780041 : if (req->internal.state == TEVENT_REQ_DONE) {
313 74636013 : return false;
314 : }
315 1144028 : if (req->internal.state == TEVENT_REQ_USER_ERROR) {
316 1142650 : *error = req->internal.error;
317 : }
318 1144028 : *state = req->internal.state;
319 1144028 : return true;
320 : }
321 :
322 1578 : static void tevent_req_timedout(struct tevent_context *ev,
323 : struct tevent_timer *te,
324 : struct timeval now,
325 : void *private_data)
326 : {
327 1435 : struct tevent_req *req =
328 143 : talloc_get_type_abort(private_data,
329 : struct tevent_req);
330 :
331 1578 : TALLOC_FREE(req->internal.timer);
332 :
333 1578 : tevent_req_finish(req, TEVENT_REQ_TIMED_OUT, __FUNCTION__);
334 1568 : }
335 :
336 2064560 : bool tevent_req_set_endtime(struct tevent_req *req,
337 : struct tevent_context *ev,
338 : struct timeval endtime)
339 : {
340 2064560 : TALLOC_FREE(req->internal.timer);
341 :
342 2064560 : req->internal.timer = tevent_add_timer(ev, req, endtime,
343 : tevent_req_timedout,
344 : req);
345 2064560 : if (tevent_req_nomem(req->internal.timer, req)) {
346 0 : return false;
347 : }
348 :
349 2064560 : return true;
350 : }
351 :
352 1036 : void tevent_req_reset_endtime(struct tevent_req *req)
353 : {
354 1036 : TALLOC_FREE(req->internal.timer);
355 1036 : }
356 :
357 75675873 : void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt)
358 : {
359 75675873 : req->async.fn = fn;
360 75675873 : req->async.private_data = pvt;
361 75675873 : }
362 :
363 75398624 : void *_tevent_req_callback_data(struct tevent_req *req)
364 : {
365 75398624 : return req->async.private_data;
366 : }
367 :
368 210821961 : void *_tevent_req_data(struct tevent_req *req)
369 : {
370 210821961 : return req->data;
371 : }
372 :
373 0 : void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn)
374 : {
375 0 : req->private_print = fn;
376 0 : }
377 :
378 2489313 : void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn)
379 : {
380 2489313 : req->private_cancel = fn;
381 2489313 : }
382 :
383 4807 : bool _tevent_req_cancel(struct tevent_req *req, const char *location)
384 : {
385 4807 : if (req->private_cancel == NULL) {
386 0 : return false;
387 : }
388 :
389 4807 : return req->private_cancel(req);
390 : }
391 :
392 4943735 : void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn)
393 : {
394 4943735 : req->private_cleanup.state = req->internal.state;
395 4943735 : req->private_cleanup.fn = fn;
396 4943735 : }
397 :
398 : static int tevent_req_profile_destructor(struct tevent_req_profile *p);
399 :
400 339662 : bool tevent_req_set_profile(struct tevent_req *req)
401 : {
402 : struct tevent_req_profile *p;
403 :
404 339662 : if (req->internal.profile != NULL) {
405 0 : tevent_req_error(req, EINVAL);
406 0 : return false;
407 : }
408 :
409 339662 : p = tevent_req_profile_create(req);
410 :
411 339662 : if (tevent_req_nomem(p, req)) {
412 0 : return false;
413 : }
414 :
415 339662 : p->req_name = talloc_get_name(req->data);
416 339662 : p->start_location = req->internal.create_location;
417 339662 : p->start_time = tevent_timeval_current();
418 :
419 339662 : req->internal.profile = p;
420 :
421 339662 : return true;
422 : }
423 :
424 339662 : static int tevent_req_profile_destructor(struct tevent_req_profile *p)
425 : {
426 339662 : if (p->parent != NULL) {
427 10 : DLIST_REMOVE(p->parent->subprofiles, p);
428 10 : p->parent = NULL;
429 : }
430 :
431 789042 : while (p->subprofiles != NULL) {
432 281738 : p->subprofiles->parent = NULL;
433 281738 : DLIST_REMOVE(p->subprofiles, p->subprofiles);
434 : }
435 :
436 339662 : return 0;
437 : }
438 :
439 57914 : struct tevent_req_profile *tevent_req_move_profile(struct tevent_req *req,
440 : TALLOC_CTX *mem_ctx)
441 : {
442 57914 : return talloc_move(mem_ctx, &req->internal.profile);
443 : }
444 :
445 0 : const struct tevent_req_profile *tevent_req_get_profile(
446 : struct tevent_req *req)
447 : {
448 0 : return req->internal.profile;
449 : }
450 :
451 0 : void tevent_req_profile_get_name(const struct tevent_req_profile *profile,
452 : const char **req_name)
453 : {
454 0 : if (req_name != NULL) {
455 0 : *req_name = profile->req_name;
456 : }
457 0 : }
458 :
459 57914 : void tevent_req_profile_get_start(const struct tevent_req_profile *profile,
460 : const char **start_location,
461 : struct timeval *start_time)
462 : {
463 57914 : if (start_location != NULL) {
464 0 : *start_location = profile->start_location;
465 : }
466 57914 : if (start_time != NULL) {
467 57914 : *start_time = profile->start_time;
468 : }
469 57914 : }
470 :
471 57914 : void tevent_req_profile_get_stop(const struct tevent_req_profile *profile,
472 : const char **stop_location,
473 : struct timeval *stop_time)
474 : {
475 57914 : if (stop_location != NULL) {
476 0 : *stop_location = profile->stop_location;
477 : }
478 57914 : if (stop_time != NULL) {
479 57914 : *stop_time = profile->stop_time;
480 : }
481 57914 : }
482 :
483 0 : void tevent_req_profile_get_status(const struct tevent_req_profile *profile,
484 : pid_t *pid,
485 : enum tevent_req_state *state,
486 : uint64_t *user_error)
487 : {
488 0 : if (pid != NULL) {
489 0 : *pid = profile->pid;
490 : }
491 0 : if (state != NULL) {
492 0 : *state = profile->state;
493 : }
494 0 : if (user_error != NULL) {
495 0 : *user_error = profile->user_error;
496 : }
497 0 : }
498 :
499 0 : const struct tevent_req_profile *tevent_req_profile_get_subprofiles(
500 : const struct tevent_req_profile *profile)
501 : {
502 0 : return profile->subprofiles;
503 : }
504 :
505 0 : const struct tevent_req_profile *tevent_req_profile_next(
506 : const struct tevent_req_profile *profile)
507 : {
508 0 : return profile->next;
509 : }
510 :
511 339662 : struct tevent_req_profile *tevent_req_profile_create(TALLOC_CTX *mem_ctx)
512 : {
513 : struct tevent_req_profile *result;
514 :
515 339662 : result = talloc_zero(mem_ctx, struct tevent_req_profile);
516 339662 : if (result == NULL) {
517 0 : return NULL;
518 : }
519 339662 : talloc_set_destructor(result, tevent_req_profile_destructor);
520 :
521 339662 : return result;
522 : }
523 :
524 0 : bool tevent_req_profile_set_name(struct tevent_req_profile *profile,
525 : const char *req_name)
526 : {
527 0 : profile->req_name = talloc_strdup(profile, req_name);
528 0 : return (profile->req_name != NULL);
529 : }
530 :
531 0 : bool tevent_req_profile_set_start(struct tevent_req_profile *profile,
532 : const char *start_location,
533 : struct timeval start_time)
534 : {
535 0 : profile->start_time = start_time;
536 :
537 0 : profile->start_location = talloc_strdup(profile, start_location);
538 0 : return (profile->start_location != NULL);
539 : }
540 :
541 0 : bool tevent_req_profile_set_stop(struct tevent_req_profile *profile,
542 : const char *stop_location,
543 : struct timeval stop_time)
544 : {
545 0 : profile->stop_time = stop_time;
546 :
547 0 : profile->stop_location = talloc_strdup(profile, stop_location);
548 0 : return (profile->stop_location != NULL);
549 : }
550 :
551 0 : void tevent_req_profile_set_status(struct tevent_req_profile *profile,
552 : pid_t pid,
553 : enum tevent_req_state state,
554 : uint64_t user_error)
555 : {
556 0 : profile->pid = pid;
557 0 : profile->state = state;
558 0 : profile->user_error = user_error;
559 0 : }
560 :
561 0 : void tevent_req_profile_append_sub(struct tevent_req_profile *parent_profile,
562 : struct tevent_req_profile **sub_profile)
563 : {
564 : struct tevent_req_profile *sub;
565 :
566 0 : sub = talloc_move(parent_profile, sub_profile);
567 :
568 0 : sub->parent = parent_profile;
569 0 : DLIST_ADD_END(parent_profile->subprofiles, sub);
570 0 : }
|