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

Generated by: LCOV version 1.14