Merged revisions 131985 via svnmerge from
[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         do { \
53                 int _count = 0; \
54                 while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
55                         usleep(1); \
56                 } \
57                 if (_count == 10) \
58                         ast_debug(3, "Unable to cancel schedule ID %d.\n", id); \
59                 id = -1; \
60         } while (0);
61
62 #define AST_SCHED_DEL_UNREF(sched, id, refcall)                 \
63         do { \
64                 int _count = 0; \
65                 while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
66                         usleep(1); \
67                 } \
68                 if (_count == 10) \
69                         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__); \
70                 if (id > -1) \
71                         refcall; \
72                 id = -1; \
73         } while (0);
74
75 #define AST_SCHED_REPLACE_VARIABLE(id, sched, when, callback, data, variable) \
76         do { \
77                 int _count = 0; \
78                 while (id > -1 && ast_sched_del(sched, id) && ++_count < 10) { \
79                         usleep(1); \
80                 } \
81                 if (_count == 10) \
82                         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__); \
83                 id = ast_sched_add_variable(sched, when, callback, data, variable); \
84         } while (0);
85
86 #define AST_SCHED_REPLACE(id, sched, when, callback, data) \
87                 AST_SCHED_REPLACE_VARIABLE(id, sched, when, callback, data, 0)
88
89 #define AST_SCHED_REPLACE_VARIABLE_UNREF(id, sched, when, callback, data, variable, unrefcall, addfailcall, refcall) \
90         do { \
91                 int _count = 0, _res=1;                                                                                  \
92                 void *_data = (void *)ast_sched_find_data(sched, id);                   \
93                 while (id > -1 && (_res = ast_sched_del(sched, id) && _count++ < 10)) { \
94                         usleep(1); \
95                 } \
96                 if (!_res && _data)                                                     \
97                         unrefcall;      /* should ref _data! */         \
98                 if (_count == 10) \
99                         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__); \
100                 id = ast_sched_add_variable(sched, when, callback, data, variable); \
101                 if (id == -1)  \
102                         addfailcall;    \
103                 else \
104                         refcall; \
105         } while (0);
106
107 #define AST_SCHED_REPLACE_UNREF(id, sched, when, callback, data, unrefcall, addfailcall, refcall) \
108         AST_SCHED_REPLACE_VARIABLE_UNREF(id, sched, when, callback, data, 0, unrefcall, addfailcall, refcall)
109
110 struct sched_context;
111
112 /*! \brief New schedule context
113  * \note Create a scheduling context
114  * \return Returns a malloc'd sched_context structure, NULL on failure
115  */
116 struct sched_context *sched_context_create(void);
117
118 /*! \brief destroys a schedule context
119  * Destroys (free's) the given sched_context structure
120  * \param c Context to free
121  * \return Returns 0 on success, -1 on failure
122  */
123 void sched_context_destroy(struct sched_context *c);
124
125 /*! \brief callback for a cheops scheduler
126  * A cheops scheduler callback takes a pointer with callback data and
127  * \return returns a 0 if it should not be run again, or non-zero if it should be
128  * rescheduled to run again
129  */
130 typedef int (*ast_sched_cb)(const void *data);
131 #define AST_SCHED_CB(a) ((ast_sched_cb)(a))
132
133 struct ast_cb_names
134 {
135         int numassocs;
136         char *list[10];
137         ast_sched_cb cblist[10];
138 };
139 char *ast_sched_report(struct sched_context *con, char *buf, int bufsiz, struct ast_cb_names *cbnames);
140                 
141 /*! \brief Adds a scheduled event
142  * Schedule an event to take place at some point in the future.  callback
143  * will be called with data as the argument, when milliseconds into the
144  * future (approximately)
145  * If callback returns 0, no further events will be re-scheduled
146  * \param con Scheduler context to add
147  * \param when how many milliseconds to wait for event to occur
148  * \param callback function to call when the amount of time expires
149  * \param data data to pass to the callback
150  * \return Returns a schedule item ID on success, -1 on failure
151  */
152 int ast_sched_add(struct sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result;
153
154 /*!
155  * \brief replace a scheduler entry
156  * \deprecated You should use the AST_SCHED_REPLACE() macro instead.
157  *
158  * This deletes the scheduler entry for old_id if it exists, and then
159  * calls ast_sched_add to create a new entry.  A negative old_id will
160  * be ignored.
161  *
162  * \retval -1 failure
163  * \retval otherwise, returns scheduled item ID
164  */
165 int ast_sched_replace(int old_id, struct sched_context *con, int when, ast_sched_cb callback, const void *data) attribute_warn_unused_result;
166
167 /*!Adds a scheduled event with rescheduling support
168  * \param con Scheduler context to add
169  * \param when how many milliseconds to wait for event to occur
170  * \param callback function to call when the amount of time expires
171  * \param data data to pass to the callback
172  * \param variable If true, the result value of callback function will be
173  *       used for rescheduling
174  * Schedule an event to take place at some point in the future.  Callback
175  * will be called with data as the argument, when milliseconds into the
176  * future (approximately)
177  * If callback returns 0, no further events will be re-scheduled
178  * \return Returns a schedule item ID on success, -1 on failure
179  */
180 int ast_sched_add_variable(struct sched_context *con, int when, ast_sched_cb callback, const void *data, int variable) attribute_warn_unused_result;
181
182 /*!
183  * \brief replace a scheduler entry
184  * \deprecated You should use the AST_SCHED_REPLACE_VARIABLE() macro instead.
185  *
186  * This deletes the scheduler entry for old_id if it exists, and then
187  * calls ast_sched_add to create a new entry.  A negative old_id will
188  * be ignored.
189  *
190  * \retval -1 failure
191  * \retval otherwise, returns scheduled item ID
192  */
193 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;
194
195         
196 /*! \brief Find a sched structure and return the data field associated with it. 
197  * \param con scheduling context in which to search fro the matching id
198  * \param id ID of the scheduled item to find
199  * \return the data field from the matching sched struct if found; else return NULL if not found.
200  */
201
202 const void *ast_sched_find_data(struct sched_context *con, int id);
203         
204 /*! \brief Deletes a scheduled event
205  * Remove this event from being run.  A procedure should not remove its own
206  * event, but return 0 instead.  In most cases, you should not call this
207  * routine directly, but use the AST_SCHED_DEL() macro instead (especially if
208  * you don't intend to do something different when it returns failure).
209  * \param con scheduling context to delete item from
210  * \param id ID of the scheduled item to delete
211  * \return Returns 0 on success, -1 on failure
212  */
213 #ifndef DEVMODE
214 int ast_sched_del(struct sched_context *con, int id) attribute_warn_unused_result;
215 #else
216 int _ast_sched_del(struct sched_context *con, int id, const char *file, int line, const char *function) attribute_warn_unused_result;
217 #define ast_sched_del(a, b)     _ast_sched_del(a, b, __FILE__, __LINE__, __PRETTY_FUNCTION__)
218 #endif
219
220 /*! \brief Determines number of seconds until the next outstanding event to take place
221  * Determine the number of seconds until the next outstanding event
222  * should take place, and return the number of milliseconds until
223  * it needs to be run.  This value is perfect for passing to the poll
224  * call.
225  * \param con context to act upon
226  * \return Returns "-1" if there is nothing there are no scheduled events
227  * (and thus the poll should not timeout)
228  */
229 int ast_sched_wait(struct sched_context *con) attribute_warn_unused_result;
230
231 /*! \brief Runs the queue
232  * \param con Scheduling context to run
233  * Run the queue, executing all callbacks which need to be performed
234  * at this time.
235  * \param con context to act upon
236  * \return Returns the number of events processed.
237  */
238 int ast_sched_runq(struct sched_context *con);
239
240 /*! \brief Dumps the scheduler contents
241  * Debugging: Dump the contents of the scheduler to stderr
242  * \param con Context to dump
243  */
244 void ast_sched_dump(const struct sched_context *con);
245
246 /*! \brief Returns the number of seconds before an event takes place
247  * \param con Context to use
248  * \param id Id to dump
249  */
250 long ast_sched_when(struct sched_context *con,int id);
251
252 /*!
253  * \brief Convenience macro for objects and reference (add)
254  *
255  */
256 #define ast_sched_add_object(obj,con,when,callback) ast_sched_add((con),(when),(callback), ASTOBJ_REF((obj)))
257
258 /*!
259  * \brief Convenience macro for objects and reference (del)
260  *
261  */
262 #define ast_sched_del_object(obj,destructor,con,id) do { \
263         if ((id) > -1) { \
264                 ast_sched_del((con),(id)); \
265                 (id) = -1; \
266                 ASTOBJ_UNREF((obj),(destructor)); \
267         } \
268 } while(0)
269
270 #if defined(__cplusplus) || defined(c_plusplus)
271 }
272 #endif
273
274 #endif /* _ASTERISK_SCHED_H */