1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdbool.h>
17 #include <stdint.h>
18 #include <string.h>
19
20 #include "common_list.h"
21 #include "securec.h"
22 #include "softbus_adapter_mem.h"
23 #include "softbus_ble_queue.h"
24 #include "softbus_conn_manager.h"
25 #include "softbus_def.h"
26 #include "softbus_errcode.h"
27 #include "softbus_log.h"
28 #include "softbus_queue.h"
29 #include "softbus_type_def.h"
30
31 #define QUEUE_NUM_PER_PID 3
32 #define HIGH_PRIORITY_DEFAULT_LIMIT 32
33 #define MIDDLE_PRIORITY_DEFAULT_LIMIT 32
34 #define LOW_PRIORITY_DEFAULT_LIMIT 16
35
36 typedef struct {
37 ListNode node;
38 int32_t pid;
39 LockFreeQueue *queue[QUEUE_NUM_PER_PID];
40 } BleQueue;
41
42 typedef enum {
43 HIGH_PRIORITY = 0,
44 MIDDLE_PRIORITY,
45 LOW_PRIORITY,
46 PRIORITY_BOUNDARY
47 } QueuePriority;
48
49 static const int32_t QUEUE_LIMIT[QUEUE_NUM_PER_PID] = {
50 HIGH_PRIORITY_DEFAULT_LIMIT,
51 MIDDLE_PRIORITY_DEFAULT_LIMIT,
52 LOW_PRIORITY_DEFAULT_LIMIT
53 };
54 static LIST_HEAD(g_bleQueueList);
55 static SoftBusMutex g_bleQueueLock;
56 static BleQueue *g_innerQueue = NULL;
57 static SoftBusCond g_sendCond;
58
CreateBleQueue(int32_t pid)59 static BleQueue *CreateBleQueue(int32_t pid)
60 {
61 BleQueue *queue = (BleQueue *)SoftBusCalloc(sizeof(BleQueue));
62 if (queue == NULL) {
63 return NULL;
64 }
65 queue->pid = pid;
66 int i;
67 for (i = 0; i < QUEUE_NUM_PER_PID; i++) {
68 queue->queue[i] = CreateQueue(QUEUE_LIMIT[i]);
69 if (queue->queue[i] == NULL) {
70 goto ERR_RETURN;
71 }
72 }
73 return queue;
74 ERR_RETURN:
75 for (i--; i >= 0; i--) {
76 SoftBusFree(queue->queue[i]);
77 }
78 SoftBusFree(queue);
79 return NULL;
80 }
81
DestroyBleQueue(BleQueue * queue)82 static void DestroyBleQueue(BleQueue *queue)
83 {
84 if (queue == NULL) {
85 return;
86 }
87 for (int i = 0; i < QUEUE_NUM_PER_PID; i++) {
88 SoftBusFree(queue->queue[i]);
89 }
90 SoftBusFree(queue);
91 }
92
GetPriority(int32_t flag)93 static int GetPriority(int32_t flag)
94 {
95 switch (flag) {
96 case CONN_HIGH:
97 return HIGH_PRIORITY;
98 case CONN_MIDDLE:
99 return MIDDLE_PRIORITY;
100 default:
101 return LOW_PRIORITY;
102 }
103 }
104
BleEnqueueNonBlock(const void * msg)105 int BleEnqueueNonBlock(const void *msg)
106 {
107 if (msg == NULL) {
108 return SOFTBUS_INVALID_PARAM;
109 }
110 SendQueueNode *queueNode = (SendQueueNode *)msg;
111 int32_t priority = GetPriority(queueNode->flag);
112 if (SoftBusMutexLock(&g_bleQueueLock) != EOK) {
113 return SOFTBUS_LOCK_ERR;
114 }
115 int32_t ret = SOFTBUS_ERR;
116 bool isListEmpty = true;
117 if (queueNode->pid == 0) {
118 ret = QueueMultiProducerEnqueue(g_innerQueue->queue[priority], msg);
119 goto END;
120 }
121
122 if (!IsListEmpty(&g_bleQueueList)) {
123 isListEmpty = false;
124 }
125 LockFreeQueue *lockFreeQueue = NULL;
126 BleQueue *item = NULL;
127 LIST_FOR_EACH_ENTRY(item, &g_bleQueueList, BleQueue, node) {
128 if (item->pid == queueNode->pid) {
129 lockFreeQueue = item->queue[priority];
130 break;
131 }
132 }
133 if (lockFreeQueue == NULL) {
134 BleQueue *newQueue = CreateBleQueue(queueNode->pid);
135 if (newQueue == NULL) {
136 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "BleEnqueueNonBlock CreateBleQueue failed");
137 goto END;
138 }
139 ListTailInsert(&g_bleQueueList, &(newQueue->node));
140 lockFreeQueue = newQueue->queue[priority];
141 }
142 ret = QueueMultiProducerEnqueue(lockFreeQueue, msg);
143 END:
144 if (isListEmpty) {
145 (void)SoftBusCondBroadcast(&g_sendCond);
146 }
147 (void)SoftBusMutexUnlock(&g_bleQueueLock);
148 return ret;
149 }
150
GetMsg(BleQueue * queue,void ** msg)151 static int GetMsg(BleQueue *queue, void **msg)
152 {
153 for (int i = 0; i < QUEUE_NUM_PER_PID; i++) {
154 if (QueueSingleConsumerDequeue(queue->queue[i], msg) == 0) {
155 return SOFTBUS_OK;
156 }
157 }
158 return SOFTBUS_ERR;
159 }
160
BleDequeueBlock(void ** msg)161 int BleDequeueBlock(void **msg)
162 {
163 int32_t status = SOFTBUS_ERR;
164 BleQueue *item = NULL;
165 BleQueue *next = NULL;
166
167 if (msg == NULL) {
168 return SOFTBUS_INVALID_PARAM;
169 }
170 if (SoftBusMutexLock(&g_bleQueueLock) != EOK) {
171 return SOFTBUS_LOCK_ERR;
172 }
173 do {
174 if (GetMsg(g_innerQueue, msg) == SOFTBUS_OK) {
175 status = SOFTBUS_OK;
176 break;
177 }
178 LIST_FOR_EACH_ENTRY_SAFE(item, next, &g_bleQueueList, BleQueue, node) {
179 ListDelete(&(item->node));
180 if (GetMsg(item, msg) == SOFTBUS_OK) {
181 ListTailInsert(&g_bleQueueList, &(item->node));
182 status = SOFTBUS_OK;
183 break;
184 }
185 DestroyBleQueue(item);
186 }
187 if (status == SOFTBUS_OK) {
188 break;
189 }
190 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_INFO, "ble queue is empty, dequeue start wait...");
191 if (SoftBusCondWait(&g_sendCond, &g_bleQueueLock, NULL) != SOFTBUS_OK) {
192 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "BleSendCondWait failed");
193 status = SOFTBUS_ERR;
194 break;
195 }
196 } while (true);
197 (void)SoftBusMutexUnlock(&g_bleQueueLock);
198 return status;
199 }
200
BleInnerQueueInit(void)201 int BleInnerQueueInit(void)
202 {
203 if (SoftBusMutexInit(&g_bleQueueLock, NULL) != 0) {
204 return SOFTBUS_ERR;
205 }
206 if (SoftBusCondInit(&g_sendCond) != SOFTBUS_OK) {
207 (void)SoftBusMutexDestroy(&g_bleQueueLock);
208 return SOFTBUS_ERR;
209 }
210 g_innerQueue = CreateBleQueue(0);
211 if (g_innerQueue == NULL) {
212 SoftBusLog(SOFTBUS_LOG_CONN, SOFTBUS_LOG_ERROR, "BleQueueInit CreateBleQueue(0) failed");
213 (void)SoftBusMutexDestroy(&g_bleQueueLock);
214 (void)SoftBusCondDestroy(&g_sendCond);
215 return SOFTBUS_ERR;
216 }
217 return SOFTBUS_OK;
218 }
219
BleInnerQueueDeinit(void)220 void BleInnerQueueDeinit(void)
221 {
222 (void)SoftBusMutexDestroy(&g_bleQueueLock);
223 (void)SoftBusCondDestroy(&g_sendCond);
224 DestroyBleQueue(g_innerQueue);
225 g_innerQueue = NULL;
226 }