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