1 /*
2 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "platform_queue.h"
10 #include "hdf_log.h"
11 #include "osal_mem.h"
12 #include "osal_mutex.h"
13 #include "osal_thread.h"
14 #include "osal_time.h"
15 #include "platform_errno.h"
16 #include "platform_log.h"
17
18 #define PLAT_QUEUE_THREAD_STAK 20000
19 #define PLAT_QUEUE_DEPTH_MAX 32
20
PlatformQueueDoDestroy(struct PlatformQueue * queue)21 static void PlatformQueueDoDestroy(struct PlatformQueue *queue)
22 {
23 (void)OsalThreadDestroy(&queue->thread);
24 (void)OsalSemDestroy(&queue->sem);
25 (void)OsalSpinDestroy(&queue->spin);
26 OsalMemFree(queue);
27 }
28
PlatformQueueNextMsg(struct PlatformQueue * queue,struct PlatformMsg ** msg)29 static int32_t PlatformQueueNextMsg(struct PlatformQueue *queue, struct PlatformMsg **msg)
30 {
31 int32_t ret;
32
33 (void)OsalSpinLock(&queue->spin);
34 if (DListIsEmpty(&queue->msgs)) {
35 PLAT_LOGE("PlatformQueueNextMsg: queue msgs is empty!");
36 ret = HDF_PLT_ERR_NO_DATA;
37 } else {
38 *msg = DLIST_FIRST_ENTRY(&queue->msgs, struct PlatformMsg, node);
39 DListRemove(&((*msg)->node));
40 queue->depth--;
41 ret = HDF_SUCCESS;
42 }
43 (void)OsalSpinUnlock(&queue->spin);
44
45 return ret;
46 }
47
PlatformQueueWorker(void * data)48 static int32_t PlatformQueueWorker(void *data)
49 {
50 int32_t ret;
51 struct PlatformQueue *queue = (struct PlatformQueue *)data;
52 struct PlatformMsg *msg = NULL;
53
54 while (true) {
55 /* wait envent */
56 ret = OsalSemWait(&queue->sem, HDF_WAIT_FOREVER);
57 if (ret != HDF_SUCCESS) {
58 continue;
59 }
60
61 if (!queue->start) {
62 queue->exited = true;
63 break;
64 }
65
66 (void)PlatformQueueNextMsg(queue, &msg);
67 /* message process */
68 if (msg != NULL && queue->handle != NULL) {
69 (void)(queue->handle(queue, msg));
70 msg = NULL;
71 }
72 }
73 return HDF_SUCCESS;
74 }
75
PlatformQueueCreate(PlatformMsgHandle handle,const char * name,void * data)76 struct PlatformQueue *PlatformQueueCreate(PlatformMsgHandle handle, const char *name, void *data)
77 {
78 struct PlatformQueue *queue = NULL;
79
80 queue = (struct PlatformQueue *)OsalMemCalloc(sizeof(*queue));
81 if (queue == NULL) {
82 PLAT_LOGE("PlatformQueueCreate: alloc queue fail!");
83 return NULL;
84 }
85
86 (void)OsalSpinInit(&queue->spin);
87 (void)OsalSemInit(&queue->sem, 0);
88 DListHeadInit(&queue->msgs);
89 queue->name = (name == NULL) ? "PlatformQueue" : name;
90 queue->handle = handle;
91 queue->depth = 0;
92 queue->depthMax = PLAT_QUEUE_DEPTH_MAX;
93 queue->data = data;
94 queue->start = false;
95 queue->exited = false;
96 return queue;
97 }
98
PlatformQueueStart(struct PlatformQueue * queue)99 int32_t PlatformQueueStart(struct PlatformQueue *queue)
100 {
101 int32_t ret;
102 struct OsalThreadParam cfg;
103
104 if (queue == NULL) {
105 PLAT_LOGE("PlatformQueueStart: queue is null!");
106 return HDF_ERR_INVALID_OBJECT;
107 }
108
109 ret = OsalThreadCreate(&queue->thread, (OsalThreadEntry)PlatformQueueWorker, (void *)queue);
110 (void)PlatformQueueWorker;
111 if (ret != HDF_SUCCESS) {
112 PLAT_LOGE("PlatformQueueStart: create thread fail!");
113 return ret;
114 }
115
116 cfg.name = (char *)queue->name;
117 cfg.priority = OSAL_THREAD_PRI_HIGHEST;
118 cfg.stackSize = PLAT_QUEUE_THREAD_STAK;
119 ret = OsalThreadStart(&queue->thread, &cfg);
120 (void)cfg;
121 if (ret != HDF_SUCCESS) {
122 OsalThreadDestroy(&queue->thread);
123 PLAT_LOGE("PlatformQueueStart: start thread fail, ret: %d!", ret);
124 return ret;
125 }
126 queue->start = true;
127
128 return HDF_SUCCESS;
129 }
130
PlatformQueueDestroy(struct PlatformQueue * queue)131 void PlatformQueueDestroy(struct PlatformQueue *queue)
132 {
133 if (queue == NULL) {
134 PLAT_LOGE("PlatformQueueDestroy: queue is null!");
135 return;
136 }
137
138 if (queue->start) {
139 queue->start = false;
140 (void)OsalSemPost(&queue->sem);
141 while (!queue->exited) {
142 OsalMSleep(1);
143 }
144 PlatformQueueDoDestroy(queue);
145 } else {
146 PlatformQueueDoDestroy(queue);
147 }
148 }
149
PlatformQueueAddMsg(struct PlatformQueue * queue,struct PlatformMsg * msg)150 int32_t PlatformQueueAddMsg(struct PlatformQueue *queue, struct PlatformMsg *msg)
151 {
152 if (queue == NULL || msg == NULL) {
153 PLAT_LOGE("PlatformQueueAddMsg: queue or msg is null!");
154 return HDF_ERR_INVALID_OBJECT;
155 }
156
157 DListHeadInit(&msg->node);
158 msg->error = HDF_SUCCESS;
159 (void)OsalSpinLock(&queue->spin);
160 if (queue->depth >= queue->depthMax) {
161 (void)OsalSpinUnlock(&queue->spin);
162 HDF_LOGE("PlatformQueueAddMsg: queue(%s) full!", queue->name);
163 return HDF_PLT_OUT_OF_RSC;
164 }
165 DListInsertTail(&msg->node, &queue->msgs);
166 queue->depth++;
167 (void)OsalSpinUnlock(&queue->spin);
168 /* notify the worker thread */
169 (void)OsalSemPost(&queue->sem);
170 return HDF_SUCCESS;
171 }
172
PlatformQueueGetMsg(struct PlatformQueue * queue,struct PlatformMsg ** msg,uint32_t tms)173 int32_t PlatformQueueGetMsg(struct PlatformQueue *queue, struct PlatformMsg **msg, uint32_t tms)
174 {
175 int32_t ret;
176
177 if (queue == NULL) {
178 PLAT_LOGE("PlatformQueueGetMsg: queue is null!");
179 return HDF_ERR_INVALID_OBJECT;
180 }
181 if (msg == NULL) {
182 PLAT_LOGE("PlatformQueueGetMsg: msg is null!");
183 return HDF_ERR_INVALID_PARAM;
184 }
185
186 ret = PlatformQueueNextMsg(queue, msg);
187 if (ret == HDF_SUCCESS) {
188 (void)OsalSemWait(&queue->sem, HDF_WAIT_FOREVER); // consume the semaphore after get
189 return ret;
190 }
191
192 if (tms == 0) {
193 PLAT_LOGE("PlatformQueueGetMsg: no data get!");
194 return HDF_PLT_ERR_NO_DATA;
195 }
196
197 ret = OsalSemWait(&queue->sem, tms);
198 if (ret != HDF_SUCCESS) {
199 PLAT_LOGE("PlatformQueueGetMsg: sem wait fail!");
200 return ret;
201 }
202 return PlatformQueueNextMsg(queue, msg);
203 }
204
205