blob: 3ae6bfbab7a8462d0c4edc6b9622a6cb900cccbc [file] [log] [blame]
Benjamin Walsh456c6da2016-09-02 18:55:39 -04001/*
Benjamin Walsh8cf56bc2016-11-04 15:47:32 -04002 * Copyright (c) 2016 Intel Corporation
Benjamin Walsh456c6da2016-09-02 18:55:39 -04003 * Copyright (c) 2016 Wind River Systems, Inc.
4 *
David B. Kinderac74d8b2017-01-18 17:01:01 -08005 * SPDX-License-Identifier: Apache-2.0
Benjamin Walsh456c6da2016-09-02 18:55:39 -04006 */
7
8/**
9 * @file
10 *
11 * Workqueue support functions
12 */
13
Benjamin Walshf6ca7de2016-11-08 10:36:50 -050014#include <kernel_structs.h>
Benjamin Walsh456c6da2016-09-02 18:55:39 -040015#include <wait_q.h>
16#include <errno.h>
17
18static void work_q_main(void *work_q_ptr, void *p2, void *p3)
19{
20 struct k_work_q *work_q = work_q_ptr;
21
22 ARG_UNUSED(p2);
23 ARG_UNUSED(p3);
24
25 while (1) {
26 struct k_work *work;
27 k_work_handler_t handler;
28
Luiz Augusto von Dentzadb581b2017-07-03 19:09:44 +030029 work = k_queue_get(&work_q->queue, K_FOREVER);
Luiz Augusto von Dentzc1fa82b2017-07-03 19:24:10 +030030 if (!work) {
31 continue;
32 }
Benjamin Walsh456c6da2016-09-02 18:55:39 -040033
34 handler = work->handler;
35
Luiz Augusto von Dentzee1e99b2016-09-26 09:36:49 +030036 /* Reset pending state so it can be resubmitted by handler */
Iván Briano9c7b5ea2016-10-04 18:11:05 -030037 if (atomic_test_and_clear_bit(work->flags,
Luiz Augusto von Dentzadb581b2017-07-03 19:09:44 +030038 K_WORK_STATE_PENDING)) {
Benjamin Walsh456c6da2016-09-02 18:55:39 -040039 handler(work);
40 }
41
42 /* Make sure we don't hog up the CPU if the FIFO never (or
43 * very rarely) gets empty.
44 */
45 k_yield();
46 }
47}
48
Andrew Boie507852a2017-07-25 18:47:07 -070049void k_work_q_start(struct k_work_q *work_q, k_thread_stack_t stack,
Benjamin Walsh669360d2016-11-14 16:46:14 -050050 size_t stack_size, int prio)
Benjamin Walsh456c6da2016-09-02 18:55:39 -040051{
Luiz Augusto von Dentzadb581b2017-07-03 19:09:44 +030052 k_queue_init(&work_q->queue);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040053
Andrew Boied26cf2d2017-03-30 13:07:02 -070054 k_thread_create(&work_q->thread, stack, stack_size, work_q_main,
55 work_q, 0, 0, prio, 0, 0);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040056}
57
Benjamin Walsh179fd3a2016-10-04 16:58:46 -040058#ifdef CONFIG_SYS_CLOCK_EXISTS
Benjamin Walsh456c6da2016-09-02 18:55:39 -040059static void work_timeout(struct _timeout *t)
60{
61 struct k_delayed_work *w = CONTAINER_OF(t, struct k_delayed_work,
62 timeout);
63
64 /* submit work to workqueue */
65 k_work_submit_to_queue(w->work_q, &w->work);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040066}
67
68void k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler)
69{
70 k_work_init(&work->work, handler);
Benjamin Walsh055262c2016-10-05 17:16:01 -040071 _init_timeout(&work->timeout, work_timeout);
Benjamin Walsh456c6da2016-09-02 18:55:39 -040072 work->work_q = NULL;
73}
74
75int k_delayed_work_submit_to_queue(struct k_work_q *work_q,
76 struct k_delayed_work *work,
Kumar Galacc334c72017-04-21 10:55:34 -050077 s32_t delay)
Benjamin Walsh456c6da2016-09-02 18:55:39 -040078{
79 int key = irq_lock();
80 int err;
81
82 /* Work cannot be active in multiple queues */
83 if (work->work_q && work->work_q != work_q) {
84 err = -EADDRINUSE;
85 goto done;
86 }
87
88 /* Cancel if work has been submitted */
89 if (work->work_q == work_q) {
90 err = k_delayed_work_cancel(work);
91 if (err < 0) {
92 goto done;
93 }
94 }
95
96 /* Attach workqueue so the timeout callback can submit it */
97 work->work_q = work_q;
98
Allan Stephens6c98c4d2016-10-17 14:34:53 -050099 if (!delay) {
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400100 /* Submit work if no ticks is 0 */
101 k_work_submit_to_queue(work_q, &work->work);
102 } else {
103 /* Add timeout */
Allan Stephens6c98c4d2016-10-17 14:34:53 -0500104 _add_timeout(NULL, &work->timeout, NULL,
105 _TICK_ALIGN + _ms_to_ticks(delay));
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400106 }
107
108 err = 0;
109
110done:
111 irq_unlock(key);
112
113 return err;
114}
115
116int k_delayed_work_cancel(struct k_delayed_work *work)
117{
118 int key = irq_lock();
119
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400120 if (!work->work_q) {
121 irq_unlock(key);
122 return -EINVAL;
123 }
124
Luiz Augusto von Dentzc1fa82b2017-07-03 19:24:10 +0300125 if (k_work_pending(&work->work)) {
126 /* Remove from the queue if already submitted */
127 if (!k_queue_remove(&work->work_q->queue, &work->work)) {
128 irq_unlock(key);
129 return -EINVAL;
130 }
131 } else {
132 _abort_timeout(&work->timeout);
133 }
Benjamin Walsh456c6da2016-09-02 18:55:39 -0400134
135 /* Detach from workqueue */
136 work->work_q = NULL;
137
138 irq_unlock(key);
139
140 return 0;
141}
Benjamin Walsh179fd3a2016-10-04 16:58:46 -0400142#endif /* CONFIG_SYS_CLOCK_EXISTS */