Skip to content

Commit 82a9bc4

Browse files
Mattemagikernkartben
authored andcommitted
kernel: Add support for stopping workqueues
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]>
1 parent 2907a96 commit 82a9bc4

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

include/zephyr/kernel.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3606,6 +3606,22 @@ int k_work_queue_drain(struct k_work_q *queue, bool plug);
36063606
*/
36073607
int k_work_queue_unplug(struct k_work_q *queue);
36083608

3609+
/** @brief Stop a work queue.
3610+
*
3611+
* Stops the work queue thread and ensures that no further work will be processed.
3612+
* This call is blocking and guarantees that the work queue thread has terminated
3613+
* cleanly if successful, no work will be processed past this point.
3614+
*
3615+
* @param queue Pointer to the queue structure.
3616+
* @param timeout Maximum time to wait for the work queue to stop.
3617+
*
3618+
* @retval 0 if the work queue was stopped
3619+
* @retval -EALREADY if the work queue was not started (or already stopped)
3620+
* @retval -EBUSY if the work queue is actively processing work items
3621+
* @retval -ETIMEDOUT if the work queue did not stop within the stipulated timeout
3622+
*/
3623+
int k_work_queue_stop(struct k_work_q *queue, k_timeout_t timeout);
3624+
36093625
/** @brief Initialize a delayable work structure.
36103626
*
36113627
* This must be invoked before scheduling a delayable work structure for the
@@ -3915,6 +3931,8 @@ enum {
39153931
K_WORK_QUEUE_DRAIN = BIT(K_WORK_QUEUE_DRAIN_BIT),
39163932
K_WORK_QUEUE_PLUGGED_BIT = 3,
39173933
K_WORK_QUEUE_PLUGGED = BIT(K_WORK_QUEUE_PLUGGED_BIT),
3934+
K_WORK_QUEUE_STOP_BIT = 4,
3935+
K_WORK_QUEUE_STOP = BIT(K_WORK_QUEUE_STOP_BIT),
39183936

39193937
/* Static work queue flags */
39203938
K_WORK_QUEUE_NO_YIELD_BIT = 8,

kernel/work.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,12 @@ static void work_queue_main(void *workq_ptr, void *p2, void *p3)
653653
* submissions.
654654
*/
655655
(void)z_sched_wake_all(&queue->drainq, 1, NULL);
656+
} else if (flag_test(&queue->flags, K_WORK_QUEUE_STOP_BIT)) {
657+
/* User has requested that the queue stop. Clear the status flags and exit.
658+
*/
659+
flags_set(&queue->flags, 0);
660+
k_spin_unlock(&lock, key);
661+
return;
656662
} else {
657663
/* No work is available and no queue state requires
658664
* special handling.
@@ -812,6 +818,35 @@ int k_work_queue_unplug(struct k_work_q *queue)
812818
return ret;
813819
}
814820

821+
int k_work_queue_stop(struct k_work_q *queue, k_timeout_t timeout)
822+
{
823+
__ASSERT_NO_MSG(queue);
824+
825+
k_spinlock_key_t key = k_spin_lock(&lock);
826+
827+
if (!flag_test(&queue->flags, K_WORK_QUEUE_STARTED_BIT)) {
828+
k_spin_unlock(&lock, key);
829+
return -EALREADY;
830+
}
831+
832+
if (!flag_test(&queue->flags, K_WORK_QUEUE_PLUGGED_BIT)) {
833+
k_spin_unlock(&lock, key);
834+
return -EBUSY;
835+
}
836+
837+
flag_set(&queue->flags, K_WORK_QUEUE_STOP_BIT);
838+
notify_queue_locked(queue);
839+
k_spin_unlock(&lock, key);
840+
if (k_thread_join(&queue->thread, timeout)) {
841+
key = k_spin_lock(&lock);
842+
flag_clear(&queue->flags, K_WORK_QUEUE_STOP_BIT);
843+
k_spin_unlock(&lock, key);
844+
return -ETIMEDOUT;
845+
}
846+
847+
return 0;
848+
}
849+
815850
#ifdef CONFIG_SYS_CLOCK_EXISTS
816851

817852
/* Timeout handler for delayable work.

0 commit comments

Comments
 (0)