kernel/work_q: Spinlockify
Each work_q object gets a separate spinlock to synchronize access instead of the global lock. Note that there was a recursive lock condition in k_delayed_work_cancel(), so that's been split out into an internal unlocked version and the API entry point that wraps it with a lock. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
parent
5aa7460e5c
commit
a37a981b21
3 changed files with 33 additions and 22 deletions
|
@ -2526,6 +2526,7 @@ typedef void (*k_work_handler_t)(struct k_work *work);
|
||||||
struct k_work_q {
|
struct k_work_q {
|
||||||
struct k_queue queue;
|
struct k_queue queue;
|
||||||
struct k_thread thread;
|
struct k_thread thread;
|
||||||
|
struct k_spinlock lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
@ -34,5 +34,6 @@
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
#include <misc/rb.h>
|
#include <misc/rb.h>
|
||||||
#include <sys_clock.h>
|
#include <sys_clock.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
|
||||||
#endif /* ZEPHYR_INCLUDE_KERNEL_INCLUDES_H_ */
|
#endif /* ZEPHYR_INCLUDE_KERNEL_INCLUDES_H_ */
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include <kernel_structs.h>
|
#include <kernel_structs.h>
|
||||||
#include <wait_q.h>
|
#include <wait_q.h>
|
||||||
|
#include <spinlock.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
@ -47,11 +48,32 @@ void k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler)
|
||||||
work->work_q = NULL;
|
work->work_q = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int work_cancel(struct k_delayed_work *work)
|
||||||
|
{
|
||||||
|
__ASSERT(work->work_q != NULL, "");
|
||||||
|
|
||||||
|
if (k_work_pending(&work->work)) {
|
||||||
|
/* Remove from the queue if already submitted */
|
||||||
|
if (!k_queue_remove(&work->work_q->queue, &work->work)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(void)_abort_timeout(&work->timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detach from workqueue */
|
||||||
|
work->work_q = NULL;
|
||||||
|
|
||||||
|
atomic_clear_bit(work->work.flags, K_WORK_STATE_PENDING);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int k_delayed_work_submit_to_queue(struct k_work_q *work_q,
|
int k_delayed_work_submit_to_queue(struct k_work_q *work_q,
|
||||||
struct k_delayed_work *work,
|
struct k_delayed_work *work,
|
||||||
s32_t delay)
|
s32_t delay)
|
||||||
{
|
{
|
||||||
unsigned int key = irq_lock();
|
k_spinlock_key_t key = k_spin_lock(&work_q->lock);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* Work cannot be active in multiple queues */
|
/* Work cannot be active in multiple queues */
|
||||||
|
@ -62,7 +84,7 @@ int k_delayed_work_submit_to_queue(struct k_work_q *work_q,
|
||||||
|
|
||||||
/* Cancel if work has been submitted */
|
/* Cancel if work has been submitted */
|
||||||
if (work->work_q == work_q) {
|
if (work->work_q == work_q) {
|
||||||
err = k_delayed_work_cancel(work);
|
err = work_cancel(work);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -83,36 +105,23 @@ int k_delayed_work_submit_to_queue(struct k_work_q *work_q,
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
irq_unlock(key);
|
k_spin_unlock(&work_q->lock, key);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int k_delayed_work_cancel(struct k_delayed_work *work)
|
int k_delayed_work_cancel(struct k_delayed_work *work)
|
||||||
{
|
{
|
||||||
unsigned int key = irq_lock();
|
|
||||||
|
|
||||||
if (!work->work_q) {
|
if (!work->work_q) {
|
||||||
irq_unlock(key);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (k_work_pending(&work->work)) {
|
struct k_spinlock *lock = &work->work_q->lock;
|
||||||
/* Remove from the queue if already submitted */
|
k_spinlock_key_t key = k_spin_lock(lock);
|
||||||
if (!k_queue_remove(&work->work_q->queue, &work->work)) {
|
int ret = work_cancel(work);
|
||||||
irq_unlock(key);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
(void)_abort_timeout(&work->timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Detach from workqueue */
|
k_spin_unlock(lock, key);
|
||||||
work->work_q = NULL;
|
return ret;
|
||||||
|
|
||||||
atomic_clear_bit(work->work.flags, K_WORK_STATE_PENDING);
|
|
||||||
irq_unlock(key);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_SYS_CLOCK_EXISTS */
|
#endif /* CONFIG_SYS_CLOCK_EXISTS */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue