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 
18 #include "common_list.h"
19 #include "securec.h"
20 #include "conn_log.h"
21 #include "softbus_adapter_mem.h"
22 #include "softbus_conn_ble_send_queue.h"
23 #include "softbus_conn_common.h"
24 #include "softbus_conn_manager.h"
25 #include "softbus_def.h"
26 #include "softbus_queue.h"
27 #define BLE_WAIT_TIME_SEC (600)
28 
29 static LIST_HEAD(g_bleQueueList);
30 static SoftBusMutex g_bleQueueLock;
31 static ConnectionQueue *g_innerQueue = NULL;
32 static SoftBusCond g_sendCond;
33 static SoftBusCond g_sendWaitCond;
34 
CreateBleQueue(int32_t pid)35 static ConnectionQueue *CreateBleQueue(int32_t pid)
36 {
37     ConnectionQueue *queue = (ConnectionQueue *)SoftBusCalloc(sizeof(ConnectionQueue));
38     if (queue == NULL) {
39         return NULL;
40     }
41     queue->pid = pid;
42     int32_t i;
43     for (i = 0; i < QUEUE_NUM_PER_PID; i++) {
44         queue->queue[i] = CreateQueue(GetQueueLimit(i));
45         if (queue->queue[i] == NULL) {
46             goto ERR_RETURN;
47         }
48     }
49     return queue;
50 ERR_RETURN:
51     for (i--; i >= 0; i--) {
52         SoftBusFree(queue->queue[i]);
53     }
54     SoftBusFree(queue);
55     return NULL;
56 }
57 
DestroyBleQueue(ConnectionQueue * queue)58 static void DestroyBleQueue(ConnectionQueue *queue)
59 {
60     if (queue == NULL) {
61         return;
62     }
63     for (int32_t i = 0; i < QUEUE_NUM_PER_PID; i++) {
64         SoftBusFree(queue->queue[i]);
65     }
66     SoftBusFree(queue);
67 }
68 
GetPriority(int32_t flag)69 static int32_t GetPriority(int32_t flag)
70 {
71     switch (flag) {
72         case CONN_HIGH:
73             return HIGH_PRIORITY;
74         case CONN_MIDDLE:
75             return MIDDLE_PRIORITY;
76         default:
77             return LOW_PRIORITY;
78     }
79 }
80 
ConnBleEnqueueNonBlock(const void * msg)81 int32_t ConnBleEnqueueNonBlock(const void *msg)
82 {
83     CONN_CHECK_AND_RETURN_RET_LOGW(msg != NULL, SOFTBUS_INVALID_PARAM, CONN_BLE, "msg is null");
84     SendQueueNode *queueNode = (SendQueueNode *)msg;
85     int32_t priority = GetPriority(queueNode->flag);
86     if (SoftBusMutexLock(&g_bleQueueLock) != EOK) {
87         CONN_LOGE(CONN_BLE, "Lock failed");
88         return SOFTBUS_LOCK_ERR;
89     }
90     bool isListEmpty = true;
91     int32_t ret = SOFTBUS_CONN_BLE_INTERNAL_ERR;
92     if (queueNode->pid == 0) {
93         ret = WaitQueueLength(g_innerQueue->queue[priority], GetQueueLimit(priority), WAIT_QUEUE_BUFFER_PERIOD_LEN,
94             &g_sendWaitCond, &g_bleQueueLock);
95         if (ret == SOFTBUS_OK) {
96             ret = QueueMultiProducerEnqueue(g_innerQueue->queue[priority], msg);
97         }
98         goto END;
99     }
100     isListEmpty = IsListEmpty(&g_bleQueueList);
101     LockFreeQueue *lockFreeQueue = NULL;
102     ConnectionQueue *item = NULL;
103     LIST_FOR_EACH_ENTRY(item, &g_bleQueueList, ConnectionQueue, node) {
104         if (item->pid == queueNode->pid) {
105             lockFreeQueue = item->queue[priority];
106             break;
107         }
108     }
109     if (lockFreeQueue == NULL) {
110         ConnectionQueue *newQueue = CreateBleQueue(queueNode->pid);
111         if (newQueue == NULL) {
112             CONN_LOGE(CONN_BLE, "ConnBleEnqueueNonBlock CreateBleQueue failed");
113             goto END;
114         }
115         ListTailInsert(&g_bleQueueList, &(newQueue->node));
116         lockFreeQueue = newQueue->queue[priority];
117     } else {
118         ret = WaitQueueLength(
119             lockFreeQueue, GetQueueLimit(priority), WAIT_QUEUE_BUFFER_PERIOD_LEN, &g_sendWaitCond, &g_bleQueueLock);
120         if (ret != SOFTBUS_OK) {
121             goto END;
122         }
123     }
124     ret = QueueMultiProducerEnqueue(lockFreeQueue, msg);
125 END:
126     if (isListEmpty) {
127         (void)SoftBusCondBroadcast(&g_sendCond);
128     }
129     (void)SoftBusMutexUnlock(&g_bleQueueLock);
130     return ret;
131 }
132 
ConnBleDequeueBlock(void ** msg)133 int32_t ConnBleDequeueBlock(void **msg)
134 {
135     bool isFull = false;
136     int32_t status = SOFTBUS_CONN_BLE_INTERNAL_ERR;
137     ConnectionQueue *item = NULL;
138     ConnectionQueue *next = NULL;
139     SoftBusSysTime waitTime = {0};
140     int32_t ret = SoftBusGetTime(&waitTime);
141     CONN_CHECK_AND_RETURN_RET_LOGE(ret == SOFTBUS_OK, SOFTBUS_INVALID_PARAM, CONN_BLE, "softbus get time failed");
142     waitTime.sec += BLE_WAIT_TIME_SEC;
143 
144     CONN_CHECK_AND_RETURN_RET_LOGE(msg != NULL, SOFTBUS_INVALID_PARAM, CONN_BLE, "msg is null");
145     CONN_CHECK_AND_RETURN_RET_LOGE(
146         SoftBusMutexLock(&g_bleQueueLock) == SOFTBUS_OK, SOFTBUS_LOCK_ERR, CONN_BLE, "lock fail!");
147     do {
148         if (GetMsg(g_innerQueue, msg, &isFull, MIDDLE_PRIORITY) == SOFTBUS_OK) {
149             status = SOFTBUS_OK;
150             break;
151         }
152         LIST_FOR_EACH_ENTRY_SAFE(item, next, &g_bleQueueList, ConnectionQueue, node) {
153             ListDelete(&(item->node));
154             if (GetMsg(item, msg, &isFull, LOW_PRIORITY) == SOFTBUS_OK) {
155                 ListTailInsert(&g_bleQueueList, &(item->node));
156                 status = SOFTBUS_OK;
157                 break;
158             }
159             DestroyBleQueue(item);
160         }
161         if (status == SOFTBUS_OK) {
162             break;
163         }
164         if (GetMsg(g_innerQueue, msg, &isFull, LOW_PRIORITY) == SOFTBUS_OK) {
165             status = SOFTBUS_OK;
166             break;
167         }
168         int32_t ret = SoftBusCondWait(&g_sendCond, &g_bleQueueLock, &waitTime);
169         if (ret != SOFTBUS_OK) {
170             if (ret == SOFTBUS_TIMOUT) {
171                 CONN_LOGD(CONN_BLE, "BleSendCondWait 600s time out");
172                 status = SOFTBUS_TIMOUT;
173                 break;
174             }
175             CONN_LOGD(CONN_BLE, "BleSendCondWait fail");
176             status = SOFTBUS_CONN_COND_WAIT_FAIL;
177             break;
178         }
179         CONN_LOGD(CONN_BLE, "ble queue wakeup.");
180     } while (true);
181 
182     if (isFull) {
183         (void)SoftBusCondBroadcast(&g_sendWaitCond);
184     }
185     (void)SoftBusMutexUnlock(&g_bleQueueLock);
186     return status;
187 }
188 
ConnBleInitSendQueue(void)189 int32_t ConnBleInitSendQueue(void)
190 {
191     if (SoftBusMutexInit(&g_bleQueueLock, NULL) != 0) {
192         CONN_LOGE(CONN_INIT, "Mutex Init failed");
193         return SOFTBUS_NO_INIT;
194     }
195     if (SoftBusCondInit(&g_sendWaitCond) != SOFTBUS_OK) {
196         CONN_LOGE(CONN_INIT, "cond Init failed");
197         (void)SoftBusMutexDestroy(&g_bleQueueLock);
198         return SOFTBUS_NO_INIT;
199     }
200     if (SoftBusCondInit(&g_sendCond) != SOFTBUS_OK) {
201         (void)SoftBusMutexDestroy(&g_bleQueueLock);
202         (void)SoftBusCondDestroy(&g_sendWaitCond);
203         return SOFTBUS_NO_INIT;
204     }
205     g_innerQueue = CreateBleQueue(0);
206     if (g_innerQueue == NULL) {
207         CONN_LOGE(CONN_INIT, "BleQueueInit CreateBleQueue(0) failed");
208         (void)SoftBusMutexDestroy(&g_bleQueueLock);
209         (void)SoftBusCondDestroy(&g_sendWaitCond);
210         (void)SoftBusCondDestroy(&g_sendCond);
211         return SOFTBUS_NO_INIT;
212     }
213     return SOFTBUS_OK;
214 }
215 
ConnBleDeinitSendQueue(void)216 void ConnBleDeinitSendQueue(void)
217 {
218     (void)SoftBusMutexDestroy(&g_bleQueueLock);
219     (void)SoftBusCondDestroy(&g_sendWaitCond);
220     (void)SoftBusCondDestroy(&g_sendCond);
221     DestroyBleQueue(g_innerQueue);
222     g_innerQueue = NULL;
223 }