1 /*
2  * Copyright (c) 2020-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 "comm_log.h"
17 #include "softbus_queue.h"
18 #include "softbus_adapter_mem.h"
19 #include "softbus_def.h"
20 
21 #ifdef __cplusplus
22 #if __cplusplus
23 extern "C" {
24 #endif
25 #endif
26 
27 #define IS_POWER_OF_2(x) ((((x) - 1) & (x)) == 0)
28 #define QUEUE_HEADER_MAGIC 0xccddddcc
29 #define QUEUE_SIZE_MAX 8192
30 #define CACHE_LINE_SIZE 64
31 
QueueInit(LockFreeQueue * queue,uint32_t unitNum)32 int32_t QueueInit(LockFreeQueue* queue, uint32_t unitNum)
33 {
34     if (queue == NULL) {
35         COMM_LOGE(COMM_UTILS, "queue is null");
36         return QUEUE_INVAL;
37     }
38     if (unitNum < 1 || !IS_POWER_OF_2(unitNum)) {
39         COMM_LOGE(COMM_UTILS, "invalid param");
40         return QUEUE_INVAL;
41     }
42 
43     (void)memset_s(queue, sizeof(LockFreeQueue), 0, sizeof(LockFreeQueue));
44 
45     queue->magic = QUEUE_HEADER_MAGIC;
46     queue->producer.size = unitNum;
47     queue->consumer.size = unitNum;
48     queue->producer.mask = unitNum - 1;
49     queue->consumer.mask = unitNum - 1;
50     queue->producer.head = 0;
51     queue->consumer.head = 0;
52     queue->producer.tail = 0;
53     queue->consumer.tail = 0;
54     queue->unitNum = unitNum;
55 
56     return 0;
57 }
58 
QueueSizeCalc(uint32_t unitNum,uint32_t * queueSize)59 int32_t QueueSizeCalc(uint32_t unitNum, uint32_t* queueSize)
60 {
61     uint32_t size;
62 
63     if (queueSize == NULL) {
64         COMM_LOGE(COMM_UTILS, "queueSize is null");
65         return QUEUE_INVAL;
66     }
67     if (unitNum > QUEUE_SIZE_MAX) {
68         COMM_LOGE(COMM_UTILS, "unitNum is invalid param unitNum=%{public}u", unitNum);
69         return QUEUE_INVAL;
70     }
71 
72     size = sizeof(uintptr_t) * unitNum + sizeof(LockFreeQueue);
73     *queueSize = ((size + CACHE_LINE_SIZE - 1) & (~(CACHE_LINE_SIZE - 1)));
74     return 0;
75 }
76 
QueueCountGet(const LockFreeQueue * queue,uint32_t * count)77 int32_t QueueCountGet(const LockFreeQueue* queue, uint32_t* count)
78 {
79     uint32_t producerTail;
80     uint32_t consumerTail;
81     uint32_t mask;
82 
83     if (queue == NULL || count == NULL) {
84         COMM_LOGE(COMM_UTILS, "invalid param");
85         return QUEUE_INVAL;
86     }
87     producerTail = queue->producer.tail;
88     consumerTail = queue->consumer.tail;
89     mask = queue->producer.mask;
90 
91     *count = ((producerTail - consumerTail) & mask);
92     return 0;
93 }
94 
CreateQueue(uint32_t unitNum)95 LockFreeQueue* CreateQueue(uint32_t unitNum)
96 {
97     if (unitNum < 1 || !IS_POWER_OF_2(unitNum)) {
98         return NULL;
99     }
100     uint32_t queueSize;
101     int ret = QueueSizeCalc(unitNum, &queueSize);
102     if (ret != 0) {
103         return NULL;
104     }
105     LockFreeQueue *queue = (LockFreeQueue *)SoftBusCalloc(queueSize);
106     if (queue == NULL) {
107         COMM_LOGE(COMM_UTILS, "SoftBusCalloc fail");
108         return NULL;
109     }
110     ret = QueueInit(queue, unitNum);
111     if (ret != 0) {
112         COMM_LOGE(COMM_UTILS, "QueueInit fail");
113         SoftBusFree(queue);
114         return NULL;
115     }
116     return queue;
117 }
118 
119 #ifdef __cplusplus
120 #if __cplusplus
121 }
122 #endif /* __cplusplus */
123 #endif /* __cplusplus */