f9e1ca5d2df840c6811b7cec16c561740e3ebbef
[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 #define AST_SCHED_DEL_UNREF(sched, id, refcall)                 \
65         do { \
66                 int _count = 0; \
67                 while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
68                         usleep(1); \
69                 } \
70                 if (_count == 10) \
71                         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__); \
72                 if (id > -1) \
73                         refcall; \
74                 id = -1; \
75         } while (0);
76
77 #define AST_SCHED_DEL_SPINLOCK(sched, id, lock) \
78         ({ \
79                 int _count = 0; \
80                 int _sched_res = -1; \
81                 while (id > -1 && (_sched_res = ast_sched_del(sched, id)) && ++_count < 10) { \
82                         ast_mutex_unlock(lock); \
83                         usleep(1); \
84                         ast_mutex_lock(lock); \
85                 } \
86                 if (_count == 10 && option_debug > 2) { \
87                         ast_log(LOG_DEBUG, "Unable to cancel schedule ID %d.\n", id); \
88                 } \
89                 id = -1; \
90                 (_sched_res); \
91         })
92
93 #define AST_SCHED_REPLACE_VARIABLE(id, sched, when, callback, data, variable) \
94         do { \
95                 int _count = 0; \
96                 while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
97                         usleep(1); \
98                 } \
99                 if (_count == 10) \
100                         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__); \
101                 id = ast_sched_add_variable(sched, when, callback, data, variable); \
102         } while (0);
103
104 #define AST_SCHED_REPLACE(id, sched, when, callback, data) \
105                 AST_SCHED_REPLACE_VARIABLE(id, sched, when, callback, data, 0)
106
107 #define AST_SCHED_REPLACE_VARIABLE_UNREF(id, sched, when, callback, data, variable, unrefcall, addfailcall, refcall) \
108         do { \
109                 int _count = 0, _res=1;                                                                                  \
110                 void *_data = (void *)ast_sched_find_data(sched, id);                   \
111                 while (id > -1 && (_res = ast_sched_del(sched, id) && _count++ < 10)) { \
112                         usleep(1); \
113                 } \
114                 if (!_res && _data)                                                     \
115                         unrefcall;      /* should ref _data! */         \
116                 if (_count == 10) \
117                         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__); \
118                 refcall; \
119                 id = ast_sched_add_variable(sched, when, callback, data, variable); \
120                 if (id == -1)  \
121                         addfailcall;    \
122         } while (0);
123
124 #define AST_SCHED_REPLACE_UNREF(id, sched, when, callback, data, unrefcall, addfailcall, refcall) \
125         AST_SCHED_REPLACE_VARIABLE_UNREF(id, sched, when, callback, data, 0, unrefcall, addfailcall, refcall)
126
127 struct sched_context;
128
129 /*! \brief New schedule context
130  * \note Create a scheduling context
131  * \return Returns a malloc'd sched_context structure, NULL on failure
132  */
133 struct sched_context *sched_context_create(void);
134
135 /*! \brief destroys a schedule context
136  * Destroys (free's) the given sched_context structure
137  * \param c Context to free
138  * \return Returns 0 on success, -1 on failure
139  */
140 void sched_context_destroy(struct sched_context *c);
141
142 /*! \brief callback for a cheops scheduler
143  * A cheops scheduler callback takes a pointer with callback data and
144  * \return returns a 0 if it should not be run again, or non-zero if it should be
145  * rescheduled to run again
146  */
147 typedef int (*ast_sched_cb)(const void *data);
148 #define AST_SCHED_CB(a) ((ast_sched_cb)(a))
149
150 struct ast_cb_names
151 {
152         int numassocs;
153         char *list[10];
154         ast_sched_cb cblist[10];
155 };
156 char *ast_sched_report(struct sched_context *con, char *buf, int bufsiz, struct ast_cb_names *cbnames);
157                 
158 /*! \brief Adds a scheduled event
159  * Schedule an event to take place at some point in the future.  callback
160  * will be called with data as the argument, when milliseconds into the
161  * future (approximately)
162  * If callback returns 0, no further events will be re-scheduled
163  * \param con Scheduler context to add
164  * \param when how many milliseconds to wait for event to occur
165  * \param callback function to call when the amount of time expires
166  * \param data data to pass to the callback
167  * \return Returns a schedule item ID on success, -1 on failure
168  */
169 int ast_sched_add(struct sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result;
170
171 /*!
172  * \brief replace a scheduler entry
173  * \deprecated You should use the AST_SCHED_REPLACE() macro instead.
174  *
175  * This deletes the scheduler entry for old_id if it exists, and then
176  * calls ast_sched_add to create a new entry.  A negative old_id will
177  * be ignored.
178  *
179  * \retval -1 failure
180  * \retval otherwise, returns scheduled item ID
181  */
182 int ast_sched_replace(int old_id, struct sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result;
183
184 /*!Adds a scheduled event with rescheduling support
185  * \param con Scheduler context to add
186  * \param when how many milliseconds to wait for event to occur
187  * \param callback function to call when the amount of time expires
188  * \param data data to pass to the callback
189  * \param variable If true, the result value of callback function will be
190  *       used for rescheduling
191  * Schedule an event to take place at some point in the future.  Callback
192  * will be called with data as the argument, when milliseconds into the
193  * future (approximately)
194  * If callback returns 0, no further events will be re-scheduled
195  * \return Returns a schedule item ID on success, -1 on failure
196  */
197 int ast_sched_add_variable(struct sched_context *con, int when, ast_sched_cb callback, const void *data, int variable) attribute_warn_unused_result;
198
199 /*!
200  * \brief replace a scheduler entry
201  * \deprecated You should use the AST_SCHED_REPLACE_VARIABLE() macro instead.
202  *
203  * This deletes the scheduler entry for old_id if it exists, and then
204  * calls ast_sched_add to create a new entry.  A negative old_id will
205  * be ignored.
206  *
207  * \retval -1 failure
208  * \retval otherwise, returns scheduled item ID
209  */
210 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;
211
212         
213 /*! \brief Find a sched structure and return the data field associated with it. 
214  * \param con scheduling context in which to search fro the matching id
215  * \param id ID of the scheduled item to find
216  * \return the data field from the matching sched struct if found; else return NULL if not found.
217  */
218
219 const void *ast_sched_find_data(struct sched_context *con, int id);
220         
221 /*! \brief Deletes a scheduled event
222  * Remove this event from being run.  A procedure should not remove its own
223  * event, but return 0 instead.  In most cases, you should not call this
224  * routine directly, but use the AST_SCHED_DEL() macro instead (especially if
225  * you don't intend to do something different when it returns failure).
226  * \param con scheduling context to delete item from
227  * \param id ID of the scheduled item to delete
228  * \return Returns 0 on success, -1 on failure
229  */
230 #ifndef AST_DEVMODE
231 int ast_sched_del(struct sched_context *con, int id) attribute_warn_unused_result;
232 #else
233 int _ast_sched_del(struct sched_context *con, int id, const char *file, int line, const char *function) attribute_warn_unused_result;
234 #define ast_sched_del(a, b)     _ast_sched_del(a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
235 #endif
236
237 /*! \brief Determines number of seconds until the next outstanding event to take place
238  * Determine the number of seconds until the next outstanding event
239  * should take place, and return the number of milliseconds until
240  * it needs to be run.  This value is perfect for passing to the poll
241  * call.
242  * \param con context to act upon
243  * \return Returns "-1" if there is nothing there are no scheduled events
244  * (and thus the poll should not timeout)
245  */
246 int ast_sched_wait(struct sched_context *con) attribute_warn_unused_result;
247
248 /*! \brief Runs the queue
249  * \param con Scheduling context to run
250  * Run the queue, executing all callbacks which need to be performed
251  * at this time.
252  * \param con context to act upon
253  * \return Returns the number of events processed.
254  */
255 int ast_sched_runq(struct sched_context *con);
256
257 /*! \brief Dumps the scheduler contents
258  * Debugging: Dump the contents of the scheduler to stderr
259  * \param con Context to dump
260  */
261 void ast_sched_dump(const struct sched_context *con);
262
263 /*! \brief Returns the number of seconds before an event takes place
264  * \param con Context to use
265  * \param id Id to dump
266  */
267 long ast_sched_when(struct sched_context *con,int id);
268
269 /*!
270  * \brief Convenience macro for objects and reference (add)
271  *
272  */
273 #define ast_sched_add_object(obj,con,when,callback) ast_sched_add((con),(when),(callback), ASTOBJ_REF((obj)))
274
275 /*!
276  * \brief Convenience macro for objects and reference (del)
277  *
278  */
279 #define ast_sched_del_object(obj,destructor,con,id) do { \
280         if ((id) > -1) { \
281                 ast_sched_del((con),(id)); \
282                 (id) = -1; \
283                 ASTOBJ_UNREF((obj),(destructor)); \
284         } \
285 } while(0)
286
287 /*!
288  * \brief An opaque type representing a scheduler thread
289  *
290  * The purpose of the ast_sched_thread API is to provide a common implementation
291  * of the case where a module wants to have a dedicated thread for handling the
292  * scheduler.
293  */
294 struct ast_sched_thread;
295
296 /*!
297  * \brief Create a scheduler with a dedicated thread
298  *
299  * This function should be used to allocate a scheduler context and a dedicated
300  * thread for processing scheduler entries.  The thread is started immediately.
301  *
302  * \retval NULL error
303  * \retval non-NULL a handle to the scheduler and its dedicated thread.
304  */
305 struct ast_sched_thread *ast_sched_thread_create(void);
306
307 /*!
308  * \brief Destroy a scheduler and its thread
309  *
310  * This function is used to destroy a scheduler context and the dedicated thread
311  * that was created for handling scheduler entries.  Any entries in the scheduler
312  * that have not yet been processed will be thrown away.  Once this function is
313  * called, the handle must not be used again.
314  *
315  * \param st the handle to the scheduler and thread
316  *
317  * \return NULL for convenience
318  */
319 struct ast_sched_thread *ast_sched_thread_destroy(struct ast_sched_thread *st);
320
321 /*!
322  * \brief Add a scheduler entry
323  *
324  * \param st the handle to the scheduler and thread
325  * \param when the number of ms in the future to run the task.  A value <= 0
326  *        is treated as "run now".
327  * \param cb the function to call when the scheduled time arrives
328  * \param data the parameter to pass to the scheduler callback
329  *
330  * \retval 0 success
331  * \retval non-zero failure
332  */
333 int ast_sched_thread_add(struct ast_sched_thread *st, int when, ast_sched_cb cb,
334                 const void *data);
335
336 /*!
337  * \brief Add a variable reschedule time scheduler entry
338  *
339  * \param st the handle to the scheduler and thread
340  * \param when the number of ms in the future to run the task.  A value <= 0
341  *        is treated as "run now".
342  * \param cb the function to call when the scheduled time arrives
343  * \param data the parameter to pass to the scheduler callback
344  * \param variable If this value is non-zero, then the scheduler will use the return
345  *        value of the scheduler as the amount of time in the future to run the
346  *        task again.  Normally, a return value of 0 means do not re-schedule, and
347  *        non-zero means re-schedule using the time provided when the scheduler
348  *        entry was first created.
349  *
350  * \retval 0 success
351  * \retval non-zero failure
352  */
353 int ast_sched_thread_add_variable(struct ast_sched_thread *st, int when, ast_sched_cb cb,
354                 const void *data, int variable);
355
356 /*!
357  * \brief Get the scheduler context for a given ast_sched_thread
358  *
359  * This function should be used only when direct access to the scheduler context
360  * is required.  Its use is discouraged unless necessary.  The cases where 
361  * this is currently required is when you want to take advantage of one of the 
362  * AST_SCHED macros.
363  *
364  * \param st the handle to the scheduler and thread
365  *
366  * \return the sched_context associated with an ast_sched_thread
367  */
368 struct sched_context *ast_sched_thread_get_context(struct ast_sched_thread *st);
369
370 /*!
371  * \brief Delete a scheduler entry
372  *
373  * This uses the AST_SCHED_DEL macro internally.
374  *
375  * \param st the handle to the scheduler and thread
376  * \param id scheduler entry id to delete
377  *
378  * \retval 0 success
379  * \retval non-zero failure
380  */
381 #define ast_sched_thread_del(st, id) ({ \
382         struct sched_context *__tmp_context = ast_sched_thread_get_context(st); \
383         AST_SCHED_DEL(__tmp_context, id); \
384 })
385
386 /*!
387  * \brief Force re-processing of the scheduler context
388  *
389  * \param st the handle to the scheduler and thread
390  *
391  * \return nothing
392  */
393 void ast_sched_thread_poke(struct ast_sched_thread *st);
394
395 #if defined(__cplusplus) || defined(c_plusplus)
396 }
397 #endif
398
399 #endif /* _ASTERISK_SCHED_H */