Sat Apr 26 2014 22:01:41

Asterisk developer's documentation


sched.h
Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2010, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  * Russell Bryant <russell@digium.com>
00008  *
00009  * See http://www.asterisk.org for more information about
00010  * the Asterisk project. Please do not directly contact
00011  * any of the maintainers of this project for assistance;
00012  * the project provides a web site, mailing lists and IRC
00013  * channels for your use.
00014  *
00015  * This program is free software, distributed under the terms of
00016  * the GNU General Public License Version 2. See the LICENSE file
00017  * at the top of the source tree.
00018  */
00019 
00020 /*! \file
00021  * \brief Scheduler Routines (derived from cheops)
00022  */
00023 
00024 #ifndef _ASTERISK_SCHED_H
00025 #define _ASTERISK_SCHED_H
00026 
00027 #if defined(__cplusplus) || defined(c_plusplus)
00028 extern "C" {
00029 #endif
00030 
00031 /*! 
00032  * \brief Remove a scheduler entry
00033  *
00034  * This is a loop construct to ensure that
00035  * the scheduled task get deleted. The idea is that
00036  * if we loop attempting to remove the scheduled task,
00037  * then whatever callback had been running will complete
00038  * and reinsert the task into the scheduler.
00039  *
00040  * Since macro expansion essentially works like pass-by-name
00041  * parameter passing, this macro will still work correctly even
00042  * if the id of the task to delete changes. This holds as long as 
00043  * the name of the id which could change is passed to the macro 
00044  * and not a copy of the value of the id.
00045  */
00046 #define AST_SCHED_DEL(sched, id) \
00047    ({ \
00048       int _count = 0; \
00049       int _sched_res = -1; \
00050       while (id > -1 && (_sched_res = ast_sched_del(sched, id)) && ++_count < 10) \
00051          usleep(1); \
00052       if (_count == 10) { \
00053          ast_debug(3, "Unable to cancel schedule ID %d.\n", id); \
00054       } \
00055       id = -1; \
00056       (_sched_res); \
00057    })
00058 
00059 #define AST_SCHED_DEL_ACCESSOR(sched, obj, getter, setter) \
00060    ({ \
00061       int _count = 0; \
00062       int _sched_res = -1; \
00063       while (getter(obj) > -1 && (_sched_res = ast_sched_del(sched, getter(obj))) && ++_count < 10) \
00064          usleep(1); \
00065       if (_count == 10) { \
00066          ast_debug(3, "Unable to cancel schedule ID %d.\n", getter(obj)); \
00067       } \
00068       setter(obj, -1); \
00069       (_sched_res); \
00070    })
00071 
00072 /*!
00073  * \brief schedule task to get deleted and call unref function
00074  * \sa AST_SCHED_DEL
00075  * \since 1.6.1
00076  */
00077 #define AST_SCHED_DEL_UNREF(sched, id, refcall)       \
00078    do { \
00079       int _count = 0; \
00080       while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
00081          usleep(1); \
00082       } \
00083       if (_count == 10) \
00084          ast_log(LOG_WARNING, "Unable to cancel schedule ID %d.  This is probably a bug (%s: %s, line %d).\n", id, __FILE__, __PRETTY_FUNCTION__, __LINE__); \
00085       if (id > -1) \
00086          refcall; \
00087       id = -1; \
00088    } while (0);
00089 
00090 /*!
00091  * \brief schedule task to get deleted releasing the lock between attempts
00092  * \since 1.6.1
00093  */
00094 #define AST_SCHED_DEL_SPINLOCK(sched, id, lock) \
00095    ({ \
00096       int _count = 0; \
00097       int _sched_res = -1; \
00098       while (id > -1 && (_sched_res = ast_sched_del(sched, id)) && ++_count < 10) { \
00099          ast_mutex_unlock(lock); \
00100          usleep(1); \
00101          ast_mutex_lock(lock); \
00102       } \
00103       if (_count == 10) { \
00104          ast_debug(3, "Unable to cancel schedule ID %d.\n", id); \
00105       } \
00106       id = -1; \
00107       (_sched_res); \
00108    })
00109 
00110 #define AST_SCHED_REPLACE_VARIABLE(id, sched, when, callback, data, variable) \
00111    do { \
00112       int _count = 0; \
00113       while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
00114          usleep(1); \
00115       } \
00116       if (_count == 10) \
00117          ast_log(LOG_WARNING, "Unable to cancel schedule ID %d.  This is probably a bug (%s: %s, line %d).\n", id, __FILE__, __PRETTY_FUNCTION__, __LINE__); \
00118       id = ast_sched_add_variable(sched, when, callback, data, variable); \
00119    } while (0);
00120 
00121 #define AST_SCHED_REPLACE(id, sched, when, callback, data) \
00122       AST_SCHED_REPLACE_VARIABLE(id, sched, when, callback, data, 0)
00123 
00124 /*!
00125  * \note Not currently used in the source?
00126  * \since 1.6.1
00127  */
00128 #define AST_SCHED_REPLACE_VARIABLE_UNREF(id, sched, when, callback, data, variable, unrefcall, addfailcall, refcall) \
00129    do { \
00130       int _count = 0, _res=1;                                \
00131       void *_data = (void *)ast_sched_find_data(sched, id);       \
00132       while (id > -1 && (_res = ast_sched_del(sched, id) && _count++ < 10)) { \
00133          usleep(1); \
00134       } \
00135       if (!_res && _data)                    \
00136          unrefcall;  /* should ref _data! */    \
00137       if (_count == 10) \
00138          ast_log(LOG_WARNING, "Unable to cancel schedule ID %d.  This is probably a bug (%s: %s, line %d).\n", id, __FILE__, __PRETTY_FUNCTION__, __LINE__); \
00139       refcall; \
00140       id = ast_sched_add_variable(sched, when, callback, data, variable); \
00141       if (id == -1)  \
00142          addfailcall;   \
00143    } while (0);
00144 
00145 #define AST_SCHED_REPLACE_UNREF(id, sched, when, callback, data, unrefcall, addfailcall, refcall) \
00146    AST_SCHED_REPLACE_VARIABLE_UNREF(id, sched, when, callback, data, 0, unrefcall, addfailcall, refcall)
00147 
00148 /*!
00149  * \brief Create a scheduler context
00150  *
00151  * \return Returns a malloc'd sched_context structure, NULL on failure
00152  */
00153 struct ast_sched_context *ast_sched_context_create(void);
00154 
00155 /*!
00156  * \brief destroys a schedule context
00157  *
00158  * \param c Context to free
00159  */
00160 void ast_sched_context_destroy(struct ast_sched_context *c);
00161 
00162 /*!
00163  * \brief scheduler callback
00164  *
00165  * A scheduler callback takes a pointer with callback data and
00166  *
00167  * \retval 0 if the callback should not be rescheduled
00168  * \retval non-zero if the callback should be scheduled agai
00169  */
00170 typedef int (*ast_sched_cb)(const void *data);
00171 #define AST_SCHED_CB(a) ((ast_sched_cb)(a))
00172 
00173 struct ast_cb_names {
00174    int numassocs;
00175    char *list[10];
00176    ast_sched_cb cblist[10];
00177 };
00178 
00179 /*!
00180  * \brief Show statics on what it is in the schedule queue
00181  * \param con Schedule context to check
00182  * \param buf dynamic string to store report
00183  * \param cbnames to check against
00184  * \since 1.6.1
00185  */
00186 void ast_sched_report(struct ast_sched_context *con, struct ast_str **buf, struct ast_cb_names *cbnames);
00187 
00188 /*!
00189  * \brief Adds a scheduled event
00190  *
00191  * Schedule an event to take place at some point in the future.  callback
00192  * will be called with data as the argument, when milliseconds into the
00193  * future (approximately)
00194  *
00195  * If callback returns 0, no further events will be re-scheduled
00196  *
00197  * \param con Scheduler context to add
00198  * \param when how many milliseconds to wait for event to occur
00199  * \param callback function to call when the amount of time expires
00200  * \param data data to pass to the callback
00201  *
00202  * \return Returns a schedule item ID on success, -1 on failure
00203  */
00204 int ast_sched_add(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result;
00205 
00206 /*!
00207  * \brief replace a scheduler entry
00208  * \deprecated You should use the AST_SCHED_REPLACE() macro instead.
00209  *
00210  * This deletes the scheduler entry for old_id if it exists, and then
00211  * calls ast_sched_add to create a new entry.  A negative old_id will
00212  * be ignored.
00213  *
00214  * \retval -1 failure
00215  * \retval otherwise, returns scheduled item ID
00216  */
00217 int ast_sched_replace(int old_id, struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result;
00218 
00219 /*!
00220  * \brief Adds a scheduled event with rescheduling support
00221  *
00222  * \param con Scheduler context to add
00223  * \param when how many milliseconds to wait for event to occur
00224  * \param callback function to call when the amount of time expires
00225  * \param data data to pass to the callback
00226  * \param variable If true, the result value of callback function will be
00227  *       used for rescheduling
00228  *
00229  * Schedule an event to take place at some point in the future.  Callback
00230  * will be called with data as the argument, when milliseconds into the
00231  * future (approximately)
00232  *
00233  * If callback returns 0, no further events will be re-scheduled
00234  *
00235  * \return Returns a schedule item ID on success, -1 on failure
00236  */
00237 int ast_sched_add_variable(struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data, int variable) attribute_warn_unused_result;
00238 
00239 /*!
00240  * \brief replace a scheduler entry
00241  * \deprecated You should use the AST_SCHED_REPLACE_VARIABLE() macro instead.
00242  *
00243  * This deletes the scheduler entry for old_id if it exists, and then
00244  * calls ast_sched_add to create a new entry.  A negative old_id will
00245  * be ignored.
00246  *
00247  * \retval -1 failure
00248  * \retval otherwise, returns scheduled item ID
00249  */
00250 int ast_sched_replace_variable(int old_id, struct ast_sched_context *con, int when, ast_sched_cb callback, const void *data, int variable) attribute_warn_unused_result;
00251 
00252 /*! 
00253  * \brief Find a sched structure and return the data field associated with it. 
00254  *
00255  * \param con scheduling context in which to search fro the matching id
00256  * \param id ID of the scheduled item to find
00257  * \return the data field from the matching sched struct if found; else return NULL if not found.
00258  *
00259  * \since 1.6.1
00260  */
00261 const void *ast_sched_find_data(struct ast_sched_context *con, int id);
00262 
00263 /*!
00264  * \brief Deletes a scheduled event
00265  *
00266  * Remove this event from being run.  A procedure should not remove its own
00267  * event, but return 0 instead.  In most cases, you should not call this
00268  * routine directly, but use the AST_SCHED_DEL() macro instead (especially if
00269  * you don't intend to do something different when it returns failure).
00270  *
00271  * \param con scheduling context to delete item from
00272  * \param id ID of the scheduled item to delete
00273  *
00274  * \return Returns 0 on success, -1 on failure
00275  */
00276 #ifndef AST_DEVMODE
00277 int ast_sched_del(struct ast_sched_context *con, int id) attribute_warn_unused_result;
00278 #else
00279 int _ast_sched_del(struct ast_sched_context *con, int id, const char *file, int line, const char *function) attribute_warn_unused_result;
00280 #define  ast_sched_del(a, b)  _ast_sched_del(a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
00281 #endif
00282 
00283 /*!
00284  * \brief Determines number of seconds until the next outstanding event to take place
00285  *
00286  * Determine the number of seconds until the next outstanding event
00287  * should take place, and return the number of milliseconds until
00288  * it needs to be run.  This value is perfect for passing to the poll
00289  * call.
00290  *
00291  * \param con context to act upon
00292  *
00293  * \return Returns "-1" if there is nothing there are no scheduled events
00294  * (and thus the poll should not timeout)
00295  */
00296 int ast_sched_wait(struct ast_sched_context *con) attribute_warn_unused_result;
00297 
00298 /*!
00299  * \brief Runs the queue
00300  *
00301  * Run the queue, executing all callbacks which need to be performed
00302  * at this time.
00303  *
00304  * \param con Scheduling context to run
00305  * \param con context to act upon
00306  *
00307  * \return Returns the number of events processed.
00308  */
00309 int ast_sched_runq(struct ast_sched_context *con);
00310 
00311 /*!
00312  * \brief Dumps the scheduler contents
00313  *
00314  * Debugging: Dump the contents of the scheduler to stderr
00315  *
00316  * \param con Context to dump
00317  */
00318 void ast_sched_dump(struct ast_sched_context *con);
00319 
00320 /*!
00321  * \brief Returns the number of seconds before an event takes place
00322  *
00323  * \param con Context to use
00324  * \param id Id to dump
00325  */
00326 long ast_sched_when(struct ast_sched_context *con,int id);
00327 
00328 /*!
00329  * \brief Convenience macro for objects and reference (add)
00330  *
00331  */
00332 #define ast_sched_add_object(obj,con,when,callback) ast_sched_add((con),(when),(callback), ASTOBJ_REF((obj)))
00333 
00334 /*!
00335  * \brief Convenience macro for objects and reference (del)
00336  *
00337  */
00338 #define ast_sched_del_object(obj,destructor,con,id) do { \
00339    if ((id) > -1) { \
00340       ast_sched_del((con),(id)); \
00341       (id) = -1; \
00342       ASTOBJ_UNREF((obj),(destructor)); \
00343    } \
00344 } while(0)
00345 
00346 /*!
00347  * \brief Start a thread for processing scheduler entries
00348  *
00349  * \param con the scheduler context this thread will manage
00350  *
00351  * \retval 0 success
00352  * \retval non-zero failure
00353  */
00354 int ast_sched_start_thread(struct ast_sched_context *con);
00355 
00356 #if defined(__cplusplus) || defined(c_plusplus)
00357 }
00358 #endif
00359 
00360 #endif /* _ASTERISK_SCHED_H */