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