1 /*
2 * Copyright (c) 2022-2023 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 "can/can_msg.h"
10 #include "hdf_dlist.h"
11 #include "hdf_log.h"
12 #include "osal_atomic.h"
13 #include "osal_mem.h"
14 #include "osal_time.h"
15 #include "securec.h"
16
17 #define HDF_LOG_TAG can_msg
18
19 #define CAN_MSG_POOL_SIZE_MAX 32
20
21 struct CanMsgHolder {
22 struct CanMsg cmsg;
23 struct HdfSRef ref;
24 OsalAtomic available;
25 };
26
27 struct CanMsgPool {
28 size_t size;
29 struct CanMsgHolder *holders;
30 };
31
CanMsgPoolAcquireHolder(struct CanMsgPool * pool)32 static struct CanMsgHolder *CanMsgPoolAcquireHolder(struct CanMsgPool *pool)
33 {
34 size_t i;
35 struct CanMsgHolder *holder = NULL;
36
37 for (i = 0; i < pool->size; i++) {
38 holder = &pool->holders[i];
39 if (OsalAtomicRead(&holder->available) < 1) {
40 continue;
41 }
42 if (OsalAtomicDecReturn(&holder->available) != 0) {
43 OsalAtomicInc(&holder->available);
44 continue;
45 }
46 (void)memset_s(holder, sizeof(*holder), 0, sizeof(*holder));
47 return holder;
48 }
49 return NULL;
50 }
51
CanMsgPoolRecycleHolder(struct CanMsgHolder * holder)52 static void CanMsgPoolRecycleHolder(struct CanMsgHolder *holder)
53 {
54 if (holder == NULL) {
55 HDF_LOGE("CanMsgPoolRecycleHolder: holder is null!");
56 return;
57 }
58 OsalAtomicInc(&holder->available);
59 }
60
CanMsgGet(const struct CanMsg * msg)61 void CanMsgGet(const struct CanMsg *msg)
62 {
63 struct CanMsgHolder *holder = NULL;
64
65 if (msg == NULL) {
66 HDF_LOGE("CanMsgGet: msg is null!");
67 return;
68 }
69 holder = CONTAINER_OF(msg, struct CanMsgHolder, cmsg);
70 HdfSRefAcquire(&holder->ref);
71 }
72
CanMsgPut(const struct CanMsg * msg)73 void CanMsgPut(const struct CanMsg *msg)
74 {
75 struct CanMsgHolder *holder = NULL;
76
77 if (msg == NULL) {
78 HDF_LOGE("CanMsgPut: msg is null!");
79 return;
80 }
81 holder = CONTAINER_OF(msg, struct CanMsgHolder, cmsg);
82 HdfSRefRelease(&holder->ref);
83 }
84
CanMsgHolderOnFirstGet(struct HdfSRef * sref)85 static void CanMsgHolderOnFirstGet(struct HdfSRef *sref)
86 {
87 (void)sref;
88 }
89
CanMsgHolderOnLastPut(struct HdfSRef * sref)90 static void CanMsgHolderOnLastPut(struct HdfSRef *sref)
91 {
92 struct CanMsgHolder *holder = NULL;
93
94 if (sref == NULL) {
95 HDF_LOGE("CanMsgHolderOnLastPut: sref is null!");
96 return;
97 }
98 holder = CONTAINER_OF(sref, struct CanMsgHolder, ref);
99 CanMsgPoolRecycleHolder(holder);
100 }
101
102 struct IHdfSRefListener g_canMsgExtListener = {
103 .OnFirstAcquire = CanMsgHolderOnFirstGet,
104 .OnLastRelease = CanMsgHolderOnLastPut,
105 };
106
CanMsgPoolObtainMsg(struct CanMsgPool * pool)107 struct CanMsg *CanMsgPoolObtainMsg(struct CanMsgPool *pool)
108 {
109 struct CanMsgHolder *holder = NULL;
110
111 if (pool == NULL) {
112 HDF_LOGE("CanMsgPoolObtainMsg: pool is null!");
113 return NULL;
114 }
115
116 holder = CanMsgPoolAcquireHolder(pool);
117 if (holder == NULL) {
118 HDF_LOGE("CanMsgPoolObtainMsg: holder is null!");
119 return NULL;
120 }
121
122 HdfSRefConstruct(&holder->ref, &g_canMsgExtListener);
123 CanMsgGet(&holder->cmsg);
124 return &holder->cmsg;
125 }
126
CanMsgPoolCreate(size_t size)127 struct CanMsgPool *CanMsgPoolCreate(size_t size)
128 {
129 size_t i;
130 struct CanMsgPool *pool = NULL;
131
132 if (size > CAN_MSG_POOL_SIZE_MAX) {
133 HDF_LOGE("CanMsgPoolCreate: invalid pool size %zu", size);
134 return NULL;
135 }
136 pool = OsalMemCalloc(sizeof(*pool) + sizeof(struct CanMsgHolder) * size);
137 if (pool == NULL) {
138 HDF_LOGE("CanMsgPoolCreate: alloc pool mem fail!");
139 return NULL;
140 }
141
142 pool->size = size;
143 pool->holders = (struct CanMsgHolder *)((uint8_t *)pool + sizeof(*pool));
144 for (i = 0; i < size; i++) {
145 OsalAtomicSet(&pool->holders[i].available, 1);
146 }
147
148 HDF_LOGI("CanMsgPoolCreate: end!");
149 return pool;
150 }
151
CanMsgPoolDestroy(struct CanMsgPool * pool)152 void CanMsgPoolDestroy(struct CanMsgPool *pool)
153 {
154 size_t drain;
155 struct CanMsgHolder *holder = NULL;
156
157 if (pool == NULL) {
158 HDF_LOGE("CanMsgPoolDestroy: pool is null!");
159 return;
160 }
161 drain = pool->size;
162 while (drain > 0) {
163 holder = CanMsgPoolAcquireHolder(pool);
164 if (holder == NULL) {
165 HDF_LOGI("CanMsgPoolDestroy: wait pool, drain = %zu", drain);
166 OsalMSleep(200); //wait for 200 ms
167 continue;
168 }
169 drain--;
170 };
171 HDF_LOGI("CanMsgPoolDestroy: end!");
172 OsalMemFree(pool);
173 }
174