root/lib/tevent/tevent_req.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tevent_req_default_print
  2. tevent_req_print
  3. _tevent_req_create
  4. _tevent_req_notify_callback
  5. tevent_req_finish
  6. _tevent_req_done
  7. _tevent_req_error
  8. _tevent_req_nomem
  9. tevent_req_trigger
  10. tevent_req_post
  11. tevent_req_is_in_progress
  12. tevent_req_received
  13. tevent_req_poll
  14. tevent_req_is_error
  15. tevent_req_timedout
  16. tevent_req_set_endtime
  17. tevent_req_set_callback
  18. _tevent_req_callback_data
  19. _tevent_req_data
  20. tevent_req_set_print_fn
  21. tevent_req_set_cancel_fn
  22. _tevent_req_cancel

   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 /**
  31  * @brief The default print function for creating debug messages
  32  * @param[in] req       The request to be printed
  33  * @param[in] mem_ctx   The memory context for the result
  34  * @retval              Text representation of req
  35  *
  36  * The function should not be used by users of the asynx API,
  37  * but custom print function can use it and append custom text
  38  * to the string.
  39  */
  40 
  41 char *tevent_req_default_print(struct tevent_req *req, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
  42 {
  43         return talloc_asprintf(mem_ctx,
  44                                "tevent_req[%p/%s]: state[%d] error[%lld (0x%llX)] "
  45                                " state[%s (%p)] timer[%p]",
  46                                req, req->internal.create_location,
  47                                req->internal.state,
  48                                (unsigned long long)req->internal.error,
  49                                (unsigned long long)req->internal.error,
  50                                talloc_get_name(req->data),
  51                                req->data,
  52                                req->internal.timer
  53                                );
  54 }
  55 
  56 /**
  57  * @brief Print an tevent_req structure in debug messages
  58  * @param[in] mem_ctx   The memory context for the result
  59  * @param[in] req       The request to be printed
  60  * @retval              Text representation of req
  61  *
  62  * This function should be used by callers of the async API
  63  */
  64 
  65 char *tevent_req_print(TALLOC_CTX *mem_ctx, struct tevent_req *req)
     /* [<][>][^][v][top][bottom][index][help] */
  66 {
  67         if (!req->private_print) {
  68                 return tevent_req_default_print(req, mem_ctx);
  69         }
  70 
  71         return req->private_print(req, mem_ctx);
  72 }
  73 
  74 /**
  75  * @brief Create an async request
  76  * @param[in] mem_ctx   The memory context for the result
  77  * @param[in] ev        The event context this async request will be driven by
  78  * @retval              A new async request
  79  *
  80  * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS
  81  */
  82 
  83 struct tevent_req *_tevent_req_create(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
  84                                     void *pdata,
  85                                     size_t data_size,
  86                                     const char *type,
  87                                     const char *location)
  88 {
  89         struct tevent_req *req;
  90         void **ppdata = (void **)pdata;
  91         void *data;
  92 
  93         req = talloc_zero(mem_ctx, struct tevent_req);
  94         if (req == NULL) {
  95                 return NULL;
  96         }
  97         req->internal.private_type      = type;
  98         req->internal.create_location   = location;
  99         req->internal.finish_location   = NULL;
 100         req->internal.state             = TEVENT_REQ_IN_PROGRESS;
 101         req->internal.trigger           = tevent_create_immediate(req);
 102         if (!req->internal.trigger) {
 103                 talloc_free(req);
 104                 return NULL;
 105         }
 106 
 107         data = talloc_zero_size(req, data_size);
 108         if (data == NULL) {
 109                 talloc_free(req);
 110                 return NULL;
 111         }
 112         talloc_set_name_const(data, type);
 113 
 114         req->data = data;
 115 
 116         *ppdata = data;
 117         return req;
 118 }
 119 
 120 void _tevent_req_notify_callback(struct tevent_req *req, const char *location)
     /* [<][>][^][v][top][bottom][index][help] */
 121 {
 122         req->internal.finish_location = location;
 123         if (req->async.fn != NULL) {
 124                 req->async.fn(req);
 125         }
 126 }
 127 
 128 static void tevent_req_finish(struct tevent_req *req,
     /* [<][>][^][v][top][bottom][index][help] */
 129                               enum tevent_req_state state,
 130                               const char *location)
 131 {
 132         req->internal.state = state;
 133         _tevent_req_notify_callback(req, location);
 134 }
 135 
 136 /**
 137  * @brief An async request has successfully finished
 138  * @param[in] req       The finished request
 139  *
 140  * tevent_req_done is to be used by implementors of async requests. When a
 141  * request is successfully finished, this function calls the user's completion
 142  * function.
 143  */
 144 
 145 void _tevent_req_done(struct tevent_req *req,
     /* [<][>][^][v][top][bottom][index][help] */
 146                       const char *location)
 147 {
 148         tevent_req_finish(req, TEVENT_REQ_DONE, location);
 149 }
 150 
 151 /**
 152  * @brief An async request has seen an error
 153  * @param[in] req       The request with an error
 154  * @param[in] error     The error code
 155  *
 156  * tevent_req_done is to be used by implementors of async requests. When a
 157  * request can not successfully completed, the implementation should call this
 158  * function with the appropriate status code.
 159  *
 160  * If error is 0 the function returns false and does nothing more.
 161  *
 162  * Call pattern would be
 163  * \code
 164  * int error = first_function();
 165  * if (tevent_req_error(req, error)) {
 166  *      return;
 167  * }
 168  *
 169  * error = second_function();
 170  * if (tevent_req_error(req, error)) {
 171  *      return;
 172  * }
 173  *
 174  * tevent_req_done(req);
 175  * return;
 176  * \endcode
 177  */
 178 
 179 bool _tevent_req_error(struct tevent_req *req,
     /* [<][>][^][v][top][bottom][index][help] */
 180                        uint64_t error,
 181                        const char *location)
 182 {
 183         if (error == 0) {
 184                 return false;
 185         }
 186 
 187         req->internal.error = error;
 188         tevent_req_finish(req, TEVENT_REQ_USER_ERROR, location);
 189         return true;
 190 }
 191 
 192 /**
 193  * @brief Helper function for nomem check
 194  * @param[in] p         The pointer to be checked
 195  * @param[in] req       The request being processed
 196  *
 197  * Convenience helper to easily check alloc failure within a callback
 198  * implementing the next step of an async request.
 199  *
 200  * Call pattern would be
 201  * \code
 202  * p = talloc(mem_ctx, bla);
 203  * if (tevent_req_nomem(p, req)) {
 204  *      return;
 205  * }
 206  * \endcode
 207  */
 208 
 209 bool _tevent_req_nomem(const void *p,
     /* [<][>][^][v][top][bottom][index][help] */
 210                        struct tevent_req *req,
 211                        const char *location)
 212 {
 213         if (p != NULL) {
 214                 return false;
 215         }
 216         tevent_req_finish(req, TEVENT_REQ_NO_MEMORY, location);
 217         return true;
 218 }
 219 
 220 /**
 221  * @brief Immediate event callback
 222  * @param[in] ev        Event context
 223  * @param[in] im        The immediate event
 224  * @param[in] priv      The async request to be finished
 225  */
 226 static void tevent_req_trigger(struct tevent_context *ev,
     /* [<][>][^][v][top][bottom][index][help] */
 227                                struct tevent_immediate *im,
 228                                void *private_data)
 229 {
 230         struct tevent_req *req = talloc_get_type(private_data,
 231                                  struct tevent_req);
 232 
 233         tevent_req_finish(req, req->internal.state,
 234                           req->internal.finish_location);
 235 }
 236 
 237 /**
 238  * @brief Finish a request before the caller had the change to set the callback
 239  * @param[in] req       The finished request
 240  * @param[in] ev        The tevent_context for the timed event
 241  * @retval              req will be returned
 242  *
 243  * An implementation of an async request might find that it can either finish
 244  * the request without waiting for an external event, or it can't even start
 245  * the engine. To present the illusion of a callback to the user of the API,
 246  * the implementation can call this helper function which triggers an
 247  * immediate timed event. This way the caller can use the same calling
 248  * conventions, independent of whether the request was actually deferred.
 249  */
 250 
 251 struct tevent_req *tevent_req_post(struct tevent_req *req,
     /* [<][>][^][v][top][bottom][index][help] */
 252                                    struct tevent_context *ev)
 253 {
 254         tevent_schedule_immediate(req->internal.trigger,
 255                                   ev, tevent_req_trigger, req);
 256         return req;
 257 }
 258 
 259 /**
 260  * @brief This function destroys the attached private data
 261  * @param[in] req       The request to poll
 262  * @retval              The boolean form of "is in progress".
 263  *
 264  * This function can be used to ask if the given request
 265  * is still in progress.
 266  *
 267  * This function is typically used by sync wrapper functions.
 268  */
 269 bool tevent_req_is_in_progress(struct tevent_req *req)
     /* [<][>][^][v][top][bottom][index][help] */
 270 {
 271         if (req->internal.state == TEVENT_REQ_IN_PROGRESS) {
 272                 return true;
 273         }
 274 
 275         return false;
 276 }
 277 
 278 /**
 279  * @brief This function destroys the attached private data
 280  * @param[in] req       The finished request
 281  *
 282  * This function can be called as last action of a _recv()
 283  * function, it destroys the data attached to the tevent_req.
 284  */
 285 void tevent_req_received(struct tevent_req *req)
     /* [<][>][^][v][top][bottom][index][help] */
 286 {
 287         TALLOC_FREE(req->data);
 288         req->private_print = NULL;
 289 
 290         TALLOC_FREE(req->internal.trigger);
 291         TALLOC_FREE(req->internal.timer);
 292 
 293         req->internal.state = TEVENT_REQ_RECEIVED;
 294 }
 295 
 296 /**
 297  * @brief This function destroys the attached private data
 298  * @param[in] req       The request to poll
 299  * @param[in] ev        The tevent_context to be used
 300  * @retval              If a critical error has happened in the
 301  *                      tevent loop layer false is returned.
 302  *                      Otherwise true is returned.
 303  *                      This is not the return value of the given request!
 304  *
 305  * This function can be used to actively poll for the
 306  * given request to finish.
 307  *
 308  * Note: this should only be used if the given tevent context
 309  *       was created by the caller, to avoid event loop nesting.
 310  *
 311  * This function is typically used by sync wrapper functions.
 312  */
 313 bool tevent_req_poll(struct tevent_req *req,
     /* [<][>][^][v][top][bottom][index][help] */
 314                      struct tevent_context *ev)
 315 {
 316         while (tevent_req_is_in_progress(req)) {
 317                 int ret;
 318 
 319                 ret = tevent_loop_once(ev);
 320                 if (ret != 0) {
 321                         return false;
 322                 }
 323         }
 324 
 325         return true;
 326 }
 327 
 328 bool tevent_req_is_error(struct tevent_req *req, enum tevent_req_state *state,
     /* [<][>][^][v][top][bottom][index][help] */
 329                         uint64_t *error)
 330 {
 331         if (req->internal.state == TEVENT_REQ_DONE) {
 332                 return false;
 333         }
 334         if (req->internal.state == TEVENT_REQ_USER_ERROR) {
 335                 *error = req->internal.error;
 336         }
 337         *state = req->internal.state;
 338         return true;
 339 }
 340 
 341 static void tevent_req_timedout(struct tevent_context *ev,
     /* [<][>][^][v][top][bottom][index][help] */
 342                                struct tevent_timer *te,
 343                                struct timeval now,
 344                                void *private_data)
 345 {
 346         struct tevent_req *req = talloc_get_type(private_data,
 347                                  struct tevent_req);
 348 
 349         TALLOC_FREE(req->internal.timer);
 350 
 351         tevent_req_finish(req, TEVENT_REQ_TIMED_OUT, __FUNCTION__);
 352 }
 353 
 354 bool tevent_req_set_endtime(struct tevent_req *req,
     /* [<][>][^][v][top][bottom][index][help] */
 355                             struct tevent_context *ev,
 356                             struct timeval endtime)
 357 {
 358         TALLOC_FREE(req->internal.timer);
 359 
 360         req->internal.timer = tevent_add_timer(ev, req, endtime,
 361                                                tevent_req_timedout,
 362                                                req);
 363         if (tevent_req_nomem(req->internal.timer, req)) {
 364                 return false;
 365         }
 366 
 367         return true;
 368 }
 369 
 370 void tevent_req_set_callback(struct tevent_req *req, tevent_req_fn fn, void *pvt)
     /* [<][>][^][v][top][bottom][index][help] */
 371 {
 372         req->async.fn = fn;
 373         req->async.private_data = pvt;
 374 }
 375 
 376 void *_tevent_req_callback_data(struct tevent_req *req)
     /* [<][>][^][v][top][bottom][index][help] */
 377 {
 378         return req->async.private_data;
 379 }
 380 
 381 void *_tevent_req_data(struct tevent_req *req)
     /* [<][>][^][v][top][bottom][index][help] */
 382 {
 383         return req->data;
 384 }
 385 
 386 /**
 387  * @brief This function sets a print function for the given request
 388  * @param[in] req       The given request
 389  * @param[in] fn        A pointer to the print function
 390  *
 391  * This function can be used to setup a print function for the given request.
 392  * This will be triggered if the tevent_req_print() function was
 393  * called on the given request.
 394  *
 395  * Note: this function should only be used for debugging.
 396  */
 397 void tevent_req_set_print_fn(struct tevent_req *req, tevent_req_print_fn fn)
     /* [<][>][^][v][top][bottom][index][help] */
 398 {
 399         req->private_print = fn;
 400 }
 401 
 402 /**
 403  * @brief This function sets a cancel function for the given request
 404  * @param[in] req       The given request
 405  * @param[in] fn        A pointer to the cancel function
 406  *
 407  * This function can be used to setup a cancel function for the given request.
 408  * This will be triggered if the tevent_req_cancel() function was
 409  * called on the given request.
 410  *
 411  */
 412 void tevent_req_set_cancel_fn(struct tevent_req *req, tevent_req_cancel_fn fn)
     /* [<][>][^][v][top][bottom][index][help] */
 413 {
 414         req->private_cancel = fn;
 415 }
 416 
 417 /**
 418  * @brief This function tries to cancel the given request
 419  * @param[in] req       The given request
 420  * @param[in] location  Automaticly filled with the __location__ macro
 421  *                      via the tevent_req_cancel() macro. This is for debugging
 422  *                      only!
 423  * @retval              This function returns true is the request is cancelable.
 424  *                      Otherwise false is returned.
 425  *
 426  * This function can be used to cancel the given request.
 427  *
 428  * It is only possible to cancel a request when the implementation
 429  * has registered a cancel function via the tevent_req_set_cancel_fn().
 430  *
 431  * Note: Even if the function returns true, the caller need to wait
 432  *       for the function to complete normally.
 433  *       Only the _recv() function of the given request indicates
 434  *       if the request was really canceled.
 435  */
 436 bool _tevent_req_cancel(struct tevent_req *req, const char *location)
     /* [<][>][^][v][top][bottom][index][help] */
 437 {
 438         if (req->private_cancel == NULL) {
 439                 return false;
 440         }
 441 
 442         return req->private_cancel(req);
 443 }

/* [<][>][^][v][top][bottom][index][help] */