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 "platform_log.h"
15
16 #define PLAT_QUEUE_THREAD_STAK 20000
17
PlatformQueueDoDestroy(struct PlatformQueue * queue)18 static void PlatformQueueDoDestroy(struct PlatformQueue *queue)
19 {
20 (void)OsalThreadDestroy(&queue->thread);
21 (void)OsalSemDestroy(&queue->sem);
22 (void)OsalSpinDestroy(&queue->spin);
23 OsalMemFree(queue);
24 }
25
PlatformQueueThreadWorker(void * data)26 static int32_t PlatformQueueThreadWorker(void *data)
27 {
28 int32_t ret;
29 struct PlatformQueue *queue = (struct PlatformQueue *)data;
30 struct PlatformMsg *msg = NULL;
31
32 while (true) {
33 /* wait envent */
34 ret = OsalSemWait(&queue->sem, HDF_WAIT_FOREVER);
35 if (ret != HDF_SUCCESS) {
36 continue;
37 }
38
39 if (!queue->start) {
40 PlatformQueueDoDestroy(queue);
41 break;
42 }
43
44 (void)OsalSpinLock(&queue->spin);
45 if (DListIsEmpty(&queue->msgs)) {
46 msg = NULL;
47 } else {
48 msg = DLIST_FIRST_ENTRY(&queue->msgs, struct PlatformMsg, node);
49 DListRemove(&msg->node);
50 }
51 (void)OsalSpinUnlock(&queue->spin);
52 /* message process */
53 if (msg != NULL) {
54 (void)(queue->handle(queue, msg));
55 }
56 }
57 return HDF_SUCCESS;
58 }
59
PlatformQueueCreate(PlatformMsgHandle handle,const char * name,void * data)60 struct PlatformQueue *PlatformQueueCreate(PlatformMsgHandle handle, const char *name, void *data)
61 {
62 int32_t ret;
63 struct PlatformQueue *queue = NULL;
64
65 if (handle == NULL) {
66 return NULL;
67 }
68
69 queue = (struct PlatformQueue *)OsalMemCalloc(sizeof(*queue));
70 if (queue == NULL) {
71 PLAT_LOGE("PlatformQueueCreate: alloc queue fail!");
72 return NULL;
73 }
74
75 ret = OsalThreadCreate(&queue->thread, (OsalThreadEntry)PlatformQueueThreadWorker, (void *)queue);
76 if (ret != HDF_SUCCESS) {
77 PLAT_LOGE("PlatformQueueCreate: create thread fail!");
78 OsalMemFree(queue);
79 return NULL;
80 }
81
82 (void)OsalSpinInit(&queue->spin);
83 (void)OsalSemInit(&queue->sem, 0);
84 DListHeadInit(&queue->msgs);
85 queue->name = (name == NULL) ? "PlatformWorkerThread" : name;
86 queue->handle = handle;
87 queue->data = data;
88 queue->start = false;
89 return queue;
90 }
91
PlatformQueueStart(struct PlatformQueue * queue)92 int32_t PlatformQueueStart(struct PlatformQueue *queue)
93 {
94 int32_t ret;
95 struct OsalThreadParam cfg;
96
97 if (queue == NULL) {
98 return HDF_ERR_INVALID_OBJECT;
99 }
100
101 cfg.name = (char *)queue->name;
102 cfg.priority = OSAL_THREAD_PRI_HIGHEST;
103 cfg.stackSize = PLAT_QUEUE_THREAD_STAK;
104 ret = OsalThreadStart(&queue->thread, &cfg);
105 if (ret != HDF_SUCCESS) {
106 PLAT_LOGE("PlatformQueueStart: start thread fail:%d", ret);
107 return ret;
108 }
109 queue->start = true;
110
111 return HDF_SUCCESS;
112 }
113
PlatformQueueDestroy(struct PlatformQueue * queue)114 void PlatformQueueDestroy(struct PlatformQueue *queue)
115 {
116 if (queue == NULL) {
117 return;
118 }
119
120 if (queue->start) {
121 queue->start = false;
122 (void)OsalSemPost(&queue->sem);
123 } else {
124 PlatformQueueDoDestroy(queue);
125 }
126 }
127
PlatformQueueAddMsg(struct PlatformQueue * queue,struct PlatformMsg * msg)128 int32_t PlatformQueueAddMsg(struct PlatformQueue *queue, struct PlatformMsg *msg)
129 {
130 if (queue == NULL || msg == NULL) {
131 return HDF_ERR_INVALID_OBJECT;
132 }
133
134 DListHeadInit(&msg->node);
135 msg->error = HDF_SUCCESS;
136 (void)OsalSpinLock(&queue->spin);
137 DListInsertTail(&msg->node, &queue->msgs);
138 (void)OsalSpinUnlock(&queue->spin);
139 /* notify the worker thread */
140 (void)OsalSemPost(&queue->sem);
141 return HDF_SUCCESS;
142 }
143