Skip to content

Commit

Permalink
kernel: Add support for stopping workqueues
Browse files Browse the repository at this point in the history
This patch adds support for stopping workqueues. This is useful for freeing
resources from workqueues when subsystems/modules is deactivated or
cleaning up the system between tests in ztest to reach a fully normalized
state.

The patch adds a new function k_work_queue_stop() that releases the
workqueues thread and stack when a workqueue is unwanted.
k_work_queue_stop(...) should be viewed as a counterpart to
k_work_queue_start(...).

This would allow to:
k_work_queue_start(...);

k_work_drain(..., true);
k_work_queue_stop(...);

Signed-off-by: Måns Ansgariusson <[email protected]>
  • Loading branch information
Mattemagikern committed Dec 6, 2024
1 parent b775c0d commit ecf9d13
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 0 deletions.
15 changes: 15 additions & 0 deletions include/zephyr/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -3606,6 +3606,19 @@ int k_work_queue_drain(struct k_work_q *queue, bool plug);
*/
int k_work_queue_unplug(struct k_work_q *queue);

/** @brief Stop a work queue.
*
* This stops the work queue thread and releases its resources. This should be
* invoked when the work queue is no longer needed.
*
* @param queue pointer to the queue structure.
*
* @retval 0 if the work queue was stopped
* @retval -ENODEV if the work queue was not started
* @retval -EBUSY if the work queue is actively processing work items
*/
int k_work_queue_stop(struct k_work_q *queue);

/** @brief Initialize a delayable work structure.
*
* This must be invoked before scheduling a delayable work structure for the
Expand Down Expand Up @@ -3915,6 +3928,8 @@ enum {
K_WORK_QUEUE_DRAIN = BIT(K_WORK_QUEUE_DRAIN_BIT),
K_WORK_QUEUE_PLUGGED_BIT = 3,
K_WORK_QUEUE_PLUGGED = BIT(K_WORK_QUEUE_PLUGGED_BIT),
K_WORK_QUEUE_STOP_BIT = 4,
K_WORK_QUEUE_STOP = BIT(K_WORK_QUEUE_STOP_BIT),

/* Static work queue flags */
K_WORK_QUEUE_NO_YIELD_BIT = 8,
Expand Down
30 changes: 30 additions & 0 deletions kernel/work.c
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,12 @@ static void work_queue_main(void *workq_ptr, void *p2, void *p3)
* submissions.
*/
(void)z_sched_wake_all(&queue->drainq, 1, NULL);
} else if (flag_test(&queue->flags, K_WORK_QUEUE_STOP_BIT)) {
/* User has requested that the queue stop. Clear the status flags and exit.
*/
flags_set(&queue->flags, 0);
k_spin_unlock(&lock, key);
return;
} else {
/* No work is available and no queue state requires
* special handling.
Expand Down Expand Up @@ -812,6 +818,30 @@ int k_work_queue_unplug(struct k_work_q *queue)
return ret;
}

int k_work_queue_stop(struct k_work_q *queue)
{
__ASSERT_NO_MSG(queue);

k_spinlock_key_t key = k_spin_lock(&lock);

if (!flag_test(&queue->flags, K_WORK_QUEUE_STARTED_BIT)) {
k_spin_unlock(&lock, key);
return -ENODEV;
}

if (!flag_test(&queue->flags, K_WORK_QUEUE_PLUGGED_BIT)) {
k_spin_unlock(&lock, key);
return -EBUSY;
}

flag_set(&queue->flags, K_WORK_QUEUE_STOP_BIT);
notify_queue_locked(queue);
k_spin_unlock(&lock, key);
k_thread_join(&queue->thread, K_FOREVER);

return 0;
}

#ifdef CONFIG_SYS_CLOCK_EXISTS

/* Timeout handler for delayable work.
Expand Down

0 comments on commit ecf9d13

Please sign in to comment.