4f5fb4217091d239162fb2d01f2184f8d5ec3084
[asterisk/asterisk.git] / include / asterisk / sched.h
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  * \brief Scheduler Routines (derived from cheops)
21  */
22
23 #ifndef _ASTERISK_SCHED_H
24 #define _ASTERISK_SCHED_H
25
26 #if defined(__cplusplus) || defined(c_plusplus)
27 extern "C" {
28 #endif
29
30
31 /*! \brief Max num of schedule structs
32  * \note The max number of schedule structs to keep around
33  * for use.  Undefine to disable schedule structure
34  * caching. (Only disable this on very low memory
35  * machines)
36  */
37 #define SCHED_MAX_CACHE 128
38
39 /*! \brief a loop construct to ensure that
40  * the scheduled task get deleted. The idea is that
41  * if we loop attempting to remove the scheduled task,
42  * then whatever callback had been running will complete
43  * and reinsert the task into the scheduler.
44  *
45  * Since macro expansion essentially works like pass-by-name
46  * parameter passing, this macro will still work correctly even
47  * if the id of the task to delete changes. This holds as long as 
48  * the name of the id which could change is passed to the macro 
49  * and not a copy of the value of the id.
50  */
51 #define AST_SCHED_DEL(sched, id) \
52         ({ \
53                 int _count = 0; \
54                 int _sched_res = -1; \
55                 while (id > -1 && (_sched_res = ast_sched_del(sched, id)) && ++_count < 10) \
56                         usleep(1); \
57                 if (_count == 10 && option_debug > 2) { \
58                         ast_log(LOG_DEBUG, "Unable to cancel schedule ID %d.\n", id); \
59                 } \
60                 id = -1; \
61                 (_sched_res); \
62         })
63
64 /*!
65  * \brief schedule task to get deleted and call unref function
66  * \sa AST_SCHED_DEL
67  * \since 1.6.1
68  */
69 #define AST_SCHED_DEL_UNREF(sched, id, refcall)                 \
70         do { \
71                 int _count = 0; \
72                 while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
73                         usleep(1); \
74                 } \
75                 if (_count == 10) \
76                         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__); \
77                 if (id > -1) \
78                         refcall; \
79                 id = -1; \
80         } while (0);
81
82 /*!
83  * \brief schedule task to get deleted releasing the lock between attempts
84  * \since 1.6.1
85  */
86 #define AST_SCHED_DEL_SPINLOCK(sched, id, lock) \
87         ({ \
88                 int _count = 0; \
89                 int _sched_res = -1; \
90                 while (id > -1 && (_sched_res = ast_sched_del(sched, id)) && ++_count < 10) { \
91                         ast_mutex_unlock(lock); \
92                         usleep(1); \
93                         ast_mutex_lock(lock); \
94                 } \
95                 if (_count == 10 && option_debug > 2) { \
96                         ast_log(LOG_DEBUG, "Unable to cancel schedule ID %d.\n", id); \
97                 } \
98                 id = -1; \
99                 (_sched_res); \
100         })
101
102 #define AST_SCHED_REPLACE_VARIABLE(id, sched, when, callback, data, variable) \
103         do { \
104                 int _count = 0; \
105                 while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
106                         usleep(1); \
107                 } \
108                 if (_count == 10) \
109                         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__); \
110                 id = ast_sched_add_variable(sched, when, callback, data, variable); \
111         } while (0);
112
113 #define AST_SCHED_REPLACE(id, sched, when, callback, data) \
114                 AST_SCHED_REPLACE_VARIABLE(id, sched, when, callback, data, 0)
115
116 /*!
117  * \note Not currently used in the source?
118  * \since 1.6.1
119  */
120 #define AST_SCHED_REPLACE_VARIABLE_UNREF(id, sched, when, callback, data, variable, unrefcall, addfailcall, refcall) \
121         do { \
122                 int _count = 0, _res=1;                                                                                  \
123                 void *_data = (void *)ast_sched_find_data(sched, id);                   \
124                 while (id > -1 && (_res = ast_sched_del(sched, id) && _count++ < 10)) { \
125                         usleep(1); \
126                 } \
127                 if (!_res && _data)                                                     \
128                         unrefcall;      /* should ref _data! */         \
129                 if (_count == 10) \
130                         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__); \
131                 refcall; \
132                 id = ast_sched_add_variable(sched, when, callback, data, variable); \
133                 if (id == -1)  \
134                         addfailcall;    \
135         } while (0);
136
137 #define AST_SCHED_REPLACE_UNREF(id, sched, when, callback, data, unrefcall, addfailcall, refcall) \
138         AST_SCHED_REPLACE_VARIABLE_UNREF(id, sched, when, callback, data, 0, unrefcall, addfailcall, refcall)
139
140 struct sched_context;
141
142 /*! \brief New schedule context
143  * \note Create a scheduling context
144  * \return Returns a malloc'd sched_context structure, NULL on failure
145  */
146 struct sched_context *sched_context_create(void);
147
148 /*! \brief destroys a schedule context
149  * Destroys (free's) the given sched_context structure
150  * \param c Context to free
151  * \return Returns 0 on success, -1 on failure
152  */
153 void sched_context_destroy(struct sched_context *c);
154
155 /*! \brief callback for a cheops scheduler
156  * A cheops scheduler callback takes a pointer with callback data and
157  * \return returns a 0 if it should not be run again, or non-zero if it should be
158  * rescheduled to run again
159  */
160 typedef int (*ast_sched_cb)(const void *data);
161 #define AST_SCHED_CB(a) ((ast_sched_cb)(a))
162
163 struct ast_cb_names {
164         int numassocs;
165         char *list[10];
166         ast_sched_cb cblist[10];
167 };
168
169 /*!
170  * \brief Show statics on what it is in the schedule queue
171  * \param con Schedule context to check
172  * \param buf dynamic string to store report
173  * \param cbnames to check against
174  * \since 1.6.1
175  */
176 void ast_sched_report(struct sched_context *con, struct ast_str **buf, struct ast_cb_names *cbnames);
177                 
178 /*! \brief Adds a scheduled event
179  * Schedule an event to take place at some point in the future.  callback
180  * will be called with data as the argument, when milliseconds into the
181  * future (approximately)
182  * If callback returns 0, no further events will be re-scheduled
183  * \param con Scheduler context to add
184  * \param when how many milliseconds to wait for event to occur
185  * \param callback function to call when the amount of time expires
186  * \param data data to pass to the callback
187  * \return Returns a schedule item ID on success, -1 on failure
188  */
189 int ast_sched_add(struct sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result;
190
191 /*!
192  * \brief replace a scheduler entry
193  * \deprecated You should use the AST_SCHED_REPLACE() macro instead.
194  *
195  * This deletes the scheduler entry for old_id if it exists, and then
196  * calls ast_sched_add to create a new entry.  A negative old_id will
197  * be ignored.
198  *
199  * \retval -1 failure
200  * \retval otherwise, returns scheduled item ID
201  */
202 int ast_sched_replace(int old_id, struct sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result;
203
204 /*!Adds a scheduled event with rescheduling support
205  * \param con Scheduler context to add
206  * \param when how many milliseconds to wait for event to occur
207  * \param callback function to call when the amount of time expires
208  * \param data data to pass to the callback
209  * \param variable If true, the result value of callback function will be
210  *       used for rescheduling
211  * Schedule an event to take place at some point in the future.  Callback
212  * will be called with data as the argument, when milliseconds into the
213  * future (approximately)
214  * If callback returns 0, no further events will be re-scheduled
215  * \return Returns a schedule item ID on success, -1 on failure
216  */
217 int ast_sched_add_variable(struct sched_context *con, int when, ast_sched_cb callback, const void *data, int variable) attribute_warn_unused_result;
218
219 /*!
220  * \brief replace a scheduler entry
221  * \deprecated You should use the AST_SCHED_REPLACE_VARIABLE() macro instead.
222  *
223  * This deletes the scheduler entry for old_id if it exists, and then
224  * calls ast_sched_add to create a new entry.  A negative old_id will
225  * be ignored.
226  *
227  * \retval -1 failure
228  * \retval otherwise, returns scheduled item ID
229  */
230 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;
231
232         
233 /*! 
234  * \brief Find a sched structure and return the data field associated with it. 
235  * \param con scheduling context in which to search fro the matching id
236  * \param id ID of the scheduled item to find
237  * \return the data field from the matching sched struct if found; else return NULL if not found.
238  * \since 1.6.1
239  */
240
241 const void *ast_sched_find_data(struct sched_context *con, int id);
242         
243 /*! \brief Deletes a scheduled event
244  * Remove this event from being run.  A procedure should not remove its own
245  * event, but return 0 instead.  In most cases, you should not call this
246  * routine directly, but use the AST_SCHED_DEL() macro instead (especially if
247  * you don't intend to do something different when it returns failure).
248  * \param con scheduling context to delete item from
249  * \param id ID of the scheduled item to delete
250  * \return Returns 0 on success, -1 on failure
251  */
252 #ifndef AST_DEVMODE
253 int ast_sched_del(struct sched_context *con, int id) attribute_warn_unused_result;
254 #else
255 int _ast_sched_del(struct sched_context *con, int id, const char *file, int line, const char *function) attribute_warn_unused_result;
256 #define ast_sched_del(a, b)     _ast_sched_del(a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
257 #endif
258
259 /*! \brief Determines number of seconds until the next outstanding event to take place
260  * Determine the number of seconds until the next outstanding event
261  * should take place, and return the number of milliseconds until
262  * it needs to be run.  This value is perfect for passing to the poll
263  * call.
264  * \param con context to act upon
265  * \return Returns "-1" if there is nothing there are no scheduled events
266  * (and thus the poll should not timeout)
267  */
268 int ast_sched_wait(struct sched_context *con) attribute_warn_unused_result;
269
270 /*! \brief Runs the queue
271  * \param con Scheduling context to run
272  * Run the queue, executing all callbacks which need to be performed
273  * at this time.
274  * \param con context to act upon
275  * \return Returns the number of events processed.
276  */
277 int ast_sched_runq(struct sched_context *con);
278
279 /*! \brief Dumps the scheduler contents
280  * Debugging: Dump the contents of the scheduler to stderr
281  * \param con Context to dump
282  */
283 void ast_sched_dump(struct sched_context *con);
284
285 /*! \brief Returns the number of seconds before an event takes place
286  * \param con Context to use
287  * \param id Id to dump
288  */
289 long ast_sched_when(struct sched_context *con,int id);
290
291 /*!
292  * \brief Convenience macro for objects and reference (add)
293  *
294  */
295 #define ast_sched_add_object(obj,con,when,callback) ast_sched_add((con),(when),(callback), ASTOBJ_REF((obj)))
296
297 /*!
298  * \brief Convenience macro for objects and reference (del)
299  *
300  */
301 #define ast_sched_del_object(obj,destructor,con,id) do { \
302         if ((id) > -1) { \
303                 ast_sched_del((con),(id)); \
304                 (id) = -1; \
305                 ASTOBJ_UNREF((obj),(destructor)); \
306         } \
307 } while(0)
308
309 /*!
310  * \brief An opaque type representing a scheduler thread
311  *
312  * The purpose of the ast_sched_thread API is to provide a common implementation
313  * of the case where a module wants to have a dedicated thread for handling the
314  * scheduler.
315  */
316 struct ast_sched_thread;
317
318 /*!
319  * \brief Create a scheduler with a dedicated thread
320  *
321  * This function should be used to allocate a scheduler context and a dedicated
322  * thread for processing scheduler entries.  The thread is started immediately.
323  *
324  * \retval NULL error
325  * \retval non-NULL a handle to the scheduler and its dedicated thread.
326  */
327 struct ast_sched_thread *ast_sched_thread_create(void);
328
329 /*!
330  * \brief Destroy a scheduler and its thread
331  *
332  * This function is used to destroy a scheduler context and the dedicated thread
333  * that was created for handling scheduler entries.  Any entries in the scheduler
334  * that have not yet been processed will be thrown away.  Once this function is
335  * called, the handle must not be used again.
336  *
337  * \param st the handle to the scheduler and thread
338  *
339  * \return NULL for convenience
340  */
341 struct ast_sched_thread *ast_sched_thread_destroy(struct ast_sched_thread *st);
342
343 /*!
344  * \brief Add a scheduler entry
345  *
346  * \param st the handle to the scheduler and thread
347  * \param when the number of ms in the future to run the task.  A value <= 0
348  *        is treated as "run now".
349  * \param cb the function to call when the scheduled time arrives
350  * \param data the parameter to pass to the scheduler callback
351  *
352  * \retval -1 Failure
353  * \retval >=0 Sched ID of added task
354  */
355 int ast_sched_thread_add(struct ast_sched_thread *st, int when, ast_sched_cb cb,
356                 const void *data);
357
358 /*!
359  * \brief Add a variable reschedule time scheduler entry
360  *
361  * \param st the handle to the scheduler and thread
362  * \param when the number of ms in the future to run the task.  A value <= 0
363  *        is treated as "run now".
364  * \param cb the function to call when the scheduled time arrives
365  * \param data the parameter to pass to the scheduler callback
366  * \param variable If this value is non-zero, then the scheduler will use the return
367  *        value of the scheduler as the amount of time in the future to run the
368  *        task again.  Normally, a return value of 0 means do not re-schedule, and
369  *        non-zero means re-schedule using the time provided when the scheduler
370  *        entry was first created.
371  *
372  * \retval -1 Failure
373  * \retval >=0 Sched ID of added task
374  */
375 int ast_sched_thread_add_variable(struct ast_sched_thread *st, int when, ast_sched_cb cb,
376                 const void *data, int variable);
377
378 /*!
379  * \brief Get the scheduler context for a given ast_sched_thread
380  *
381  * This function should be used only when direct access to the scheduler context
382  * is required.  Its use is discouraged unless necessary.  The cases where 
383  * this is currently required is when you want to take advantage of one of the 
384  * AST_SCHED macros.
385  *
386  * \param st the handle to the scheduler and thread
387  *
388  * \return the sched_context associated with an ast_sched_thread
389  */
390 struct sched_context *ast_sched_thread_get_context(struct ast_sched_thread *st);
391
392 /*!
393  * \brief Delete a scheduler entry
394  *
395  * This uses the AST_SCHED_DEL macro internally.
396  *
397  * \param st the handle to the scheduler and thread
398  * \param id scheduler entry id to delete
399  *
400  * \retval 0 success
401  * \retval non-zero failure
402  */
403 #define ast_sched_thread_del(st, id) ({ \
404         struct sched_context *__tmp_context = ast_sched_thread_get_context(st); \
405         AST_SCHED_DEL(__tmp_context, id); \
406 })
407
408 /*!
409  * \brief Force re-processing of the scheduler context
410  *
411  * \param st the handle to the scheduler and thread
412  *
413  * \return nothing
414  */
415 void ast_sched_thread_poke(struct ast_sched_thread *st);
416
417 #if defined(__cplusplus) || defined(c_plusplus)
418 }
419 #endif
420
421 #endif /* _ASTERISK_SCHED_H */