LCOV - code coverage report
Current view: top level - lib/tevent - tevent_req.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 174 240 72.5 %
Date: 2024-06-13 04:01:37 Functions: 31 44 70.5 %

          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 : }

Generated by: LCOV version 1.13