work_q: Make k_delayed_work_cancel cancel work already pending

This has been a limitation caused by k_fifo which could only remove
items from the beggining, but with the change to use k_queue in
k_work_q it is now possible to remove items from any position with
use of k_queue_remove.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
Luiz Augusto von Dentz 2017-07-03 19:24:10 +03:00 committed by Anas Nashif
commit c1fa82b3c6
3 changed files with 18 additions and 14 deletions

View file

@ -2049,7 +2049,7 @@ static inline void k_work_submit_to_queue(struct k_work_q *work_q,
struct k_work *work)
{
if (!atomic_test_and_set_bit(work->flags, K_WORK_STATE_PENDING)) {
k_fifo_put(&work_q->queue, work);
k_queue_append(&work_q->queue, work);
}
}

View file

@ -27,6 +27,9 @@ static void work_q_main(void *work_q_ptr, void *p2, void *p3)
k_work_handler_t handler;
work = k_queue_get(&work_q->queue, K_FOREVER);
if (!work) {
continue;
}
handler = work->handler;
@ -60,8 +63,6 @@ static void work_timeout(struct _timeout *t)
/* submit work to workqueue */
k_work_submit_to_queue(w->work_q, &w->work);
/* detach from workqueue, for cancel to return appropriate status */
w->work_q = NULL;
}
void k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler)
@ -116,18 +117,20 @@ int k_delayed_work_cancel(struct k_delayed_work *work)
{
int key = irq_lock();
if (k_work_pending(&work->work)) {
irq_unlock(key);
return -EINPROGRESS;
}
if (!work->work_q) {
irq_unlock(key);
return -EINVAL;
}
/* Abort timeout, if it has expired this will do nothing */
_abort_timeout(&work->timeout);
if (k_work_pending(&work->work)) {
/* Remove from the queue if already submitted */
if (!k_queue_remove(&work->work_q->queue, &work->work)) {
irq_unlock(key);
return -EINVAL;
}
} else {
_abort_timeout(&work->timeout);
}
/* Detach from workqueue */
work->work_q = NULL;

View file

@ -124,10 +124,10 @@ static void tdelayed_work_cancel(void *data)
* >t0: cancel delayed_work[0], expected cancellation success
* >t0+TIMEOUT: handling delayed_work_sleepy, which do k_sleep TIMEOUT
* pending delayed_work[1], check pending flag, expected 1
* cancel delayed_work[1], expected -EINPROGRESS
* cancel delayed_work[1], expected 0
* >t0+2*TIMEOUT: delayed_work_sleepy completed
* delayed_work[1] completed
* cancel delayed_work_sleepy, expected -EINVAL
* cancel delayed_work_sleepy, expected 0
*/
zassert_true(ret == 0, NULL);
/**TESTPOINT: delayed work cancel when countdown*/
@ -143,7 +143,8 @@ static void tdelayed_work_cancel(void *data)
NULL);
/**TESTPOINT: delayed work cancel when pending*/
ret = k_delayed_work_cancel(&delayed_work[1]);
zassert_equal(ret, -EINPROGRESS, NULL);
zassert_equal(ret, 0, NULL);
k_sem_give(&sync_sema);
/*wait for completed work_sleepy and delayed_work[1]*/
k_sleep(TIMEOUT);
/**TESTPOINT: check pending when work completed*/
@ -151,7 +152,7 @@ static void tdelayed_work_cancel(void *data)
(struct k_work *)&delayed_work_sleepy), NULL);
/**TESTPOINT: delayed work cancel when completed*/
ret = k_delayed_work_cancel(&delayed_work_sleepy);
zassert_equal(ret, -EINVAL, NULL);
zassert_equal(ret, 0, NULL);
}
/*work items not cancelled: delayed_work[1], delayed_work_sleepy*/
}