• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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