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 75283496 : 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 75283496 : void **ppdata = (void **)pdata;
70 : void *data;
71 : size_t payload;
72 :
73 75283496 : payload = sizeof(struct tevent_immediate) + data_size;
74 75283496 : if (payload < sizeof(struct tevent_immediate)) {
75 : /* overflow */
76 0 : return NULL;
77 : }
78 :
79 75283496 : req = talloc_pooled_object(
80 : mem_ctx, struct tevent_req, 2,
81 : sizeof(struct tevent_immediate) + data_size);
82 75283496 : if (req == NULL) {
83 0 : return NULL;
84 : }
85 :
86 75283496 : *req = (struct tevent_req) {
87 : .internal = {
88 : .private_type = type,
89 : .create_location = location,
90 : .state = TEVENT_REQ_IN_PROGRESS,
91 75283496 : .trigger = tevent_create_immediate(req),
92 : },
93 : };
94 :
95 75283496 : 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 75283496 : talloc_set_name_const(data, type);
104 :
105 75283496 : req->data = data;
106 :
107 75283496 : talloc_set_destructor(req, tevent_req_destructor);
108 :
109 75283496 : parent = talloc_get_type(talloc_parent(mem_ctx), struct tevent_req);
110 75283496 : if ((parent != NULL) && (parent->internal.profile != NULL)) {
111 277938 : bool ok = tevent_req_set_profile(req);
112 :
113 277938 : if (!ok) {
114 0 : TALLOC_FREE(req);
115 0 : return NULL;
116 : }
117 277938 : req->internal.profile->parent = parent->internal.profile;
118 277938 : DLIST_ADD_END(parent->internal.profile->subprofiles,
119 : req->internal.profile);
120 : }
121 :
122 75283496 : *ppdata = data;
123 75283496 : return req;
124 : }
125 :
126 1848564 : static int tevent_req_destructor(struct tevent_req *req)
127 : {
128 1848564 : tevent_req_received(req);
129 1848564 : return 0;
130 : }
131 :
132 88975947 : void _tevent_req_notify_callback(struct tevent_req *req, const char *location)
133 : {
134 88975947 : req->internal.finish_location = location;
135 88975947 : if (req->internal.defer_callback_ev) {
136 2029281 : (void)tevent_req_post(req, req->internal.defer_callback_ev);
137 2029281 : req->internal.defer_callback_ev = NULL;
138 2029281 : return;
139 : }
140 86946666 : if (req->async.fn != NULL) {
141 74683474 : req->async.fn(req);
142 : }
143 : }
144 :
145 164177089 : static void tevent_req_cleanup(struct tevent_req *req)
146 : {
147 164177089 : if (req->private_cleanup.fn == NULL) {
148 157252788 : return;
149 : }
150 :
151 6924301 : 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 1098378 : return;
157 : }
158 :
159 5825923 : req->private_cleanup.state = req->internal.state;
160 5825923 : req->private_cleanup.fn(req, req->internal.state);
161 : }
162 :
163 88895359 : 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 88895359 : TALLOC_FREE(req->internal.timer);
173 :
174 88895359 : req->internal.state = state;
175 88895359 : req->internal.finish_location = location;
176 :
177 88895359 : tevent_req_cleanup(req);
178 :
179 88895359 : p = req->internal.profile;
180 :
181 88895359 : if (p != NULL) {
182 333845 : p->stop_location = location;
183 333845 : p->stop_time = tevent_timeval_current();
184 333845 : p->state = state;
185 333845 : p->user_error = req->internal.error;
186 :
187 333845 : if (p->parent != NULL) {
188 277928 : talloc_steal(p->parent, p);
189 277928 : req->internal.profile = NULL;
190 : }
191 : }
192 :
193 88895359 : _tevent_req_notify_callback(req, location);
194 88868699 : }
195 :
196 73855946 : void _tevent_req_done(struct tevent_req *req,
197 : const char *location)
198 : {
199 73855946 : tevent_req_finish(req, TEVENT_REQ_DONE, location);
200 73843420 : }
201 :
202 27861107 : bool _tevent_req_error(struct tevent_req *req,
203 : uint64_t error,
204 : const char *location)
205 : {
206 27861107 : if (error == 0) {
207 26718856 : return false;
208 : }
209 :
210 1142251 : req->internal.error = error;
211 1142251 : tevent_req_finish(req, TEVENT_REQ_USER_ERROR, location);
212 1140703 : 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 105840103 : bool _tevent_req_nomem(const void *p,
221 : struct tevent_req *req,
222 : const char *location)
223 : {
224 105840103 : if (p != NULL) {
225 105840099 : 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 13895793 : static void tevent_req_trigger(struct tevent_context *ev,
243 : struct tevent_immediate *im,
244 : void *private_data)
245 : {
246 12264366 : struct tevent_req *req =
247 1631427 : talloc_get_type_abort(private_data,
248 : struct tevent_req);
249 :
250 13895793 : tevent_req_finish(req, req->internal.state,
251 : req->internal.finish_location);
252 13883217 : }
253 :
254 14971010 : struct tevent_req *tevent_req_post(struct tevent_req *req,
255 : struct tevent_context *ev)
256 : {
257 14971010 : tevent_schedule_immediate(req->internal.trigger,
258 : ev, tevent_req_trigger, req);
259 14971010 : return req;
260 : }
261 :
262 2062690 : void tevent_req_defer_callback(struct tevent_req *req,
263 : struct tevent_context *ev)
264 : {
265 2062690 : req->internal.defer_callback_ev = ev;
266 2062690 : }
267 :
268 33113767 : bool tevent_req_is_in_progress(struct tevent_req *req)
269 : {
270 33113767 : if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
271 20528946 : return true;
272 : }
273 :
274 12584821 : return false;
275 : }
276 :
277 75281730 : void tevent_req_received(struct tevent_req *req)
278 : {
279 75281730 : talloc_set_destructor(req, NULL);
280 :
281 75281730 : req->private_print = NULL;
282 75281730 : req->private_cancel = NULL;
283 :
284 75281730 : TALLOC_FREE(req->internal.trigger);
285 75281730 : TALLOC_FREE(req->internal.timer);
286 :
287 75281730 : req->internal.state = TEVENT_REQ_RECEIVED;
288 :
289 75281730 : tevent_req_cleanup(req);
290 :
291 75281730 : TALLOC_FREE(req->data);
292 75281730 : }
293 :
294 309512 : bool tevent_req_poll(struct tevent_req *req,
295 : struct tevent_context *ev)
296 : {
297 3691370 : while (tevent_req_is_in_progress(req)) {
298 : int ret;
299 :
300 3126532 : ret = tevent_loop_once(ev);
301 3126511 : if (ret != 0) {
302 0 : return false;
303 : }
304 : }
305 :
306 309491 : return true;
307 : }
308 :
309 75066843 : bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
310 : uint64_t *error)
311 : {
312 75066843 : if (req->internal.state == TEVENT_REQ_DONE) {
313 73923408 : return false;
314 : }
315 1143435 : if (req->internal.state == TEVENT_REQ_USER_ERROR) {
316 1142270 : *error = req->internal.error;
317 : }
318 1143435 : *state = req->internal.state;
319 1143435 : return true;
320 : }
321 :
322 1365 : static void tevent_req_timedout(struct tevent_context *ev,
323 : struct tevent_timer *te,
324 : struct timeval now,
325 : void *private_data)
326 : {
327 1222 : struct tevent_req *req =
328 143 : talloc_get_type_abort(private_data,
329 : struct tevent_req);
330 :
331 1365 : TALLOC_FREE(req->internal.timer);
332 :
333 1365 : tevent_req_finish(req, TEVENT_REQ_TIMED_OUT, __FUNCTION__);
334 1355 : }
335 :
336 2062881 : bool tevent_req_set_endtime(struct tevent_req *req,
337 : struct tevent_context *ev,
338 : struct timeval endtime)
339 : {
340 2062881 : TALLOC_FREE(req->internal.timer);
341 :
342 2062881 : req->internal.timer = tevent_add_timer(ev, req, endtime,
343 : tevent_req_timedout,
344 : req);
345 2062881 : if (tevent_req_nomem(req->internal.timer, req)) {
346 0 : return false;
347 : }
348 :
349 2062881 : return true;
350 : }
351 :
352 920 : void tevent_req_reset_endtime(struct tevent_req *req)
353 : {
354 920 : TALLOC_FREE(req->internal.timer);
355 920 : }
356 :
357 74961019 : void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt)
358 : {
359 74961019 : req->async.fn = fn;
360 74961019 : req->async.private_data = pvt;
361 74961019 : }
362 :
363 74687488 : void *_tevent_req_callback_data(struct tevent_req *req)
364 : {
365 74687488 : return req->async.private_data;
366 : }
367 :
368 208966217 : void *_tevent_req_data(struct tevent_req *req)
369 : {
370 208966217 : 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 2485314 : void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn)
379 : {
380 2485314 : req->private_cancel = fn;
381 2485314 : }
382 :
383 4767 : bool _tevent_req_cancel(struct tevent_req *req, const char *location)
384 : {
385 4767 : if (req->private_cancel == NULL) {
386 0 : return false;
387 : }
388 :
389 4767 : return req->private_cancel(req);
390 : }
391 :
392 4933386 : void tevent_req_set_cleanup_fn(struct tevent_req *req, tevent_req_cleanup_fn fn)
393 : {
394 4933386 : req->private_cleanup.state = req->internal.state;
395 4933386 : req->private_cleanup.fn = fn;
396 4933386 : }
397 :
398 : static int tevent_req_profile_destructor(struct tevent_req_profile *p);
399 :
400 333855 : bool tevent_req_set_profile(struct tevent_req *req)
401 : {
402 : struct tevent_req_profile *p;
403 :
404 333855 : if (req->internal.profile != NULL) {
405 0 : tevent_req_error(req, EINVAL);
406 0 : return false;
407 : }
408 :
409 333855 : p = tevent_req_profile_create(req);
410 :
411 333855 : if (tevent_req_nomem(p, req)) {
412 0 : return false;
413 : }
414 :
415 333855 : p->req_name = talloc_get_name(req->data);
416 333855 : p->start_location = req->internal.create_location;
417 333855 : p->start_time = tevent_timeval_current();
418 :
419 333855 : req->internal.profile = p;
420 :
421 333855 : return true;
422 : }
423 :
424 333855 : static int tevent_req_profile_destructor(struct tevent_req_profile *p)
425 : {
426 333855 : if (p->parent != NULL) {
427 10 : DLIST_REMOVE(p->parent->subprofiles, p);
428 10 : p->parent = NULL;
429 : }
430 :
431 777691 : while (p->subprofiles != NULL) {
432 277928 : p->subprofiles->parent = NULL;
433 277928 : DLIST_REMOVE(p->subprofiles, p->subprofiles);
434 : }
435 :
436 333855 : return 0;
437 : }
438 :
439 55917 : struct tevent_req_profile *tevent_req_move_profile(struct tevent_req *req,
440 : TALLOC_CTX *mem_ctx)
441 : {
442 55917 : 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 55917 : void tevent_req_profile_get_start(const struct tevent_req_profile *profile,
460 : const char **start_location,
461 : struct timeval *start_time)
462 : {
463 55917 : if (start_location != NULL) {
464 0 : *start_location = profile->start_location;
465 : }
466 55917 : if (start_time != NULL) {
467 55917 : *start_time = profile->start_time;
468 : }
469 55917 : }
470 :
471 55917 : void tevent_req_profile_get_stop(const struct tevent_req_profile *profile,
472 : const char **stop_location,
473 : struct timeval *stop_time)
474 : {
475 55917 : if (stop_location != NULL) {
476 0 : *stop_location = profile->stop_location;
477 : }
478 55917 : if (stop_time != NULL) {
479 55917 : *stop_time = profile->stop_time;
480 : }
481 55917 : }
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 333855 : struct tevent_req_profile *tevent_req_profile_create(TALLOC_CTX *mem_ctx)
512 : {
513 : struct tevent_req_profile *result;
514 :
515 333855 : result = talloc_zero(mem_ctx, struct tevent_req_profile);
516 333855 : if (result == NULL) {
517 0 : return NULL;
518 : }
519 333855 : talloc_set_destructor(result, tevent_req_profile_destructor);
520 :
521 333855 : 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 : }
|