mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-03 03:20:57 +00:00
sched: fix and test a double deref on delete of an executing call back
sched: Avoid a double deref when AST_SCHED_DEL_UNREF is called on an executing call-back. This is done by adding a new variable 'rescheduled' to the struct sched which is set in ast_sched_runq and checked in ast_sched_del_nonrunning. ast_sched_del_nonrunning is a replacement for now deprecated ast_sched_del which returns a new possible value -2 if called on an executing call-back with rescheduled set. ast_sched_del is modified to call ast_sched_del_nonrunning to maintain existing code. AST_SCHED_DEL_UNREF is also updated to look for the -2 in which case it will not throw a warning or invoke refcall. test_sched: Add a new unit test sched_test_freebird that will check the reference count in the resolved scenario. ASTERISK-29698 Change-Id: Icfb16b3acbc29cf5b4cef74183f7531caaefe21d
This commit is contained in:
committed by
Michael Bradeen
parent
93d090147f
commit
b79a571279
@@ -72,20 +72,22 @@ extern "C" {
|
||||
/*!
|
||||
* \brief schedule task to get deleted and call unref function
|
||||
*
|
||||
* Only calls unref function if the delete succeeded.
|
||||
* Only calls the unref function if the task is actually deleted by
|
||||
* ast_sched_del_nonrunning. If a failure occurs or the task is
|
||||
* currently running and not rescheduled then refcall is not invoked.
|
||||
*
|
||||
* \sa AST_SCHED_DEL
|
||||
* \since 1.6.1
|
||||
*/
|
||||
#define AST_SCHED_DEL_UNREF(sched, id, refcall) \
|
||||
do { \
|
||||
int _count = 0, _id; \
|
||||
while ((_id = id) > -1 && ast_sched_del(sched, _id) && ++_count < 10) { \
|
||||
int _count = 0, _id, _ret = 0; \
|
||||
while ((_id = id) > -1 && (( _ret = ast_sched_del_nonrunning(sched, _id)) == -1) && ++_count < 10) { \
|
||||
usleep(1); \
|
||||
} \
|
||||
if (_count == 10) { \
|
||||
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__); \
|
||||
} else if (_id > -1) { \
|
||||
} else if (_id > -1 && _ret >-2) { \
|
||||
refcall; \
|
||||
id = -1; \
|
||||
} \
|
||||
@@ -294,9 +296,29 @@ const void *ast_sched_find_data(struct ast_sched_context *con, int id);
|
||||
*
|
||||
* \retval -1 on failure
|
||||
* \retval 0 on success
|
||||
*
|
||||
* \deprecated in favor of ast_sched_del_nonrunning which checks if the event is running and rescheduled
|
||||
*
|
||||
*/
|
||||
int ast_sched_del(struct ast_sched_context *con, int id) attribute_warn_unused_result;
|
||||
|
||||
/*!
|
||||
* \brief Deletes a scheduled event with care against the event running
|
||||
*
|
||||
* Remove this event from being run. A procedure should not remove its own
|
||||
* event, but return 0 instead. In most cases, you should not call this
|
||||
* routine directly, but use the AST_SCHED_DEL() macro instead (especially if
|
||||
* you don't intend to do something different when it returns failure).
|
||||
*
|
||||
* \param con scheduling context to delete item from
|
||||
* \param id ID of the scheduled item to delete
|
||||
*
|
||||
* \retval -1 on failure
|
||||
* \retval -2 event was running but was deleted because it was not rescheduled
|
||||
* \retval 0 on success
|
||||
*/
|
||||
int ast_sched_del_nonrunning(struct ast_sched_context *con, int id) attribute_warn_unused_result;
|
||||
|
||||
/*!
|
||||
* \brief Determines number of seconds until the next outstanding event to take place
|
||||
*
|
||||
|
Reference in New Issue
Block a user