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 <Mansgariusson@gmail.com>
This commit is contained in:
parent
2907a961f7
commit
82a9bc4589
2 changed files with 53 additions and 0 deletions
|
@ -3606,6 +3606,22 @@ 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.
|
||||
*
|
||||
* Stops the work queue thread and ensures that no further work will be processed.
|
||||
* This call is blocking and guarantees that the work queue thread has terminated
|
||||
* cleanly if successful, no work will be processed past this point.
|
||||
*
|
||||
* @param queue Pointer to the queue structure.
|
||||
* @param timeout Maximum time to wait for the work queue to stop.
|
||||
*
|
||||
* @retval 0 if the work queue was stopped
|
||||
* @retval -EALREADY if the work queue was not started (or already stopped)
|
||||
* @retval -EBUSY if the work queue is actively processing work items
|
||||
* @retval -ETIMEDOUT if the work queue did not stop within the stipulated timeout
|
||||
*/
|
||||
int k_work_queue_stop(struct k_work_q *queue, k_timeout_t timeout);
|
||||
|
||||
/** @brief Initialize a delayable work structure.
|
||||
*
|
||||
* This must be invoked before scheduling a delayable work structure for the
|
||||
|
@ -3915,6 +3931,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,
|
||||
|
|
|
@ -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.
|
||||
|
@ -812,6 +818,35 @@ int k_work_queue_unplug(struct k_work_q *queue)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int k_work_queue_stop(struct k_work_q *queue, k_timeout_t timeout)
|
||||
{
|
||||
__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 -EALREADY;
|
||||
}
|
||||
|
||||
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);
|
||||
if (k_thread_join(&queue->thread, timeout)) {
|
||||
key = k_spin_lock(&lock);
|
||||
flag_clear(&queue->flags, K_WORK_QUEUE_STOP_BIT);
|
||||
k_spin_unlock(&lock, key);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SYS_CLOCK_EXISTS
|
||||
|
||||
/* Timeout handler for delayable work.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue