1 /*
2 * Copyright (c) 2022 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 return;
56 }
57 OsalAtomicInc(&holder->available);
58 }
59
CanMsgGet(const struct CanMsg * msg)60 void CanMsgGet(const struct CanMsg *msg)
61 {
62 struct CanMsgHolder *holder = NULL;
63
64 if (msg == NULL) {
65 return;
66 }
67 holder = CONTAINER_OF(msg, struct CanMsgHolder, cmsg);
68 HdfSRefAcquire(&holder->ref);
69 }
70
CanMsgPut(const struct CanMsg * msg)71 void CanMsgPut(const struct CanMsg *msg)
72 {
73 struct CanMsgHolder *holder = NULL;
74
75 if (msg == NULL) {
76 return;
77 }
78 holder = CONTAINER_OF(msg, struct CanMsgHolder, cmsg);
79 HdfSRefRelease(&holder->ref);
80 }
81
CanMsgHolderOnFirstGet(struct HdfSRef * sref)82 static void CanMsgHolderOnFirstGet(struct HdfSRef *sref)
83 {
84 (void)sref;
85 }
86
CanMsgHolderOnLastPut(struct HdfSRef * sref)87 static void CanMsgHolderOnLastPut(struct HdfSRef *sref)
88 {
89 struct CanMsgHolder *holder = NULL;
90
91 if (sref == NULL) {
92 return;
93 }
94 holder = CONTAINER_OF(sref, struct CanMsgHolder, ref);
95 CanMsgPoolRecycleHolder(holder);
96 }
97
98 struct IHdfSRefListener g_canMsgExtListener = {
99 .OnFirstAcquire = CanMsgHolderOnFirstGet,
100 .OnLastRelease = CanMsgHolderOnLastPut,
101 };
102
CanMsgPoolObtainMsg(struct CanMsgPool * pool)103 struct CanMsg *CanMsgPoolObtainMsg(struct CanMsgPool *pool)
104 {
105 struct CanMsgHolder *holder = NULL;
106
107 if (pool == NULL) {
108 return NULL;
109 }
110
111 holder = CanMsgPoolAcquireHolder(pool);
112 if (holder == NULL) {
113 return NULL;
114 }
115
116 HdfSRefConstruct(&holder->ref, &g_canMsgExtListener);
117 CanMsgGet(&holder->cmsg);
118 return &holder->cmsg;
119 }
120
CanMsgPoolCreate(size_t size)121 struct CanMsgPool *CanMsgPoolCreate(size_t size)
122 {
123 size_t i;
124 struct CanMsgPool *pool = NULL;
125
126 if (size > CAN_MSG_POOL_SIZE_MAX) {
127 HDF_LOGE("CanMsgPoolCreate: invalid pool size %zu", size);
128 return NULL;
129 }
130 pool = OsalMemCalloc(sizeof(*pool) + sizeof(struct CanMsgHolder) * size);
131 if (pool == NULL) {
132 HDF_LOGE("CanMsgPoolCreate: alloc pool mem failed");
133 return NULL;
134 }
135
136 pool->size = size;
137 pool->holders = (struct CanMsgHolder *)((uint8_t *)pool + sizeof(*pool));
138 for (i = 0; i < size; i++) {
139 OsalAtomicSet(&pool->holders[i].available, 1);
140 }
141
142 HDF_LOGI("CanMsgPoolCreate: pool = %p", pool);
143 return pool;
144 }
145
CanMsgPoolDestroy(struct CanMsgPool * pool)146 void CanMsgPoolDestroy(struct CanMsgPool *pool)
147 {
148 size_t drain;
149 struct CanMsgHolder *holder = NULL;
150
151 if (pool == NULL) {
152 return;
153 }
154 drain = pool->size;
155 while (drain > 0) {
156 holder = CanMsgPoolAcquireHolder(pool);
157 if (holder == NULL) {
158 HDF_LOGI("CanMsgPoolDestroy: wait pool, drain = %zu", drain);
159 OsalMSleep(200); //wait for 200 ms
160 continue;
161 }
162 drain--;
163 };
164 HDF_LOGI("CanMsgPoolDestroy: pool = %p", pool);
165 OsalMemFree(pool);
166 }
167