1 /*
2 * Copyright (c) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved.
3 *
4 * UniProton is licensed under Mulan PSL v2.
5 * You can use this software according to the terms and conditions of the Mulan PSL v2.
6 * You may obtain a copy of Mulan PSL v2 at:
7 * http://license.coscl.org.cn/MulanPSL2
8 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11 * See the Mulan PSL v2 for more details.
12 * Create: 2022-11-15
13 * Description: pthread rwlock功能实现
14 */
15 #include "prt_rwlock_internal.h"
16 #include "prt_task_external.h"
17
OsRwlockPriCompare(struct TagTskCb * runTask,struct TagListObject * rwList)18 OS_SEC_ALW_INLINE INLINE bool OsRwlockPriCompare(struct TagTskCb *runTask, struct TagListObject *rwList)
19 {
20 struct TagTskCb *task;
21
22 if (!ListEmpty(rwList)) {
23 task = GET_TCB_PEND(LIST_FIRST(rwList));
24 if (runTask->priority < task->priority) {
25 return TRUE;
26 }
27 return FALSE;
28 }
29 return TRUE;
30 }
31
OsRwLockPendFindPosSub(const struct TagTskCb * runTask,const struct TagListObject * lockList)32 struct TagListObject *OsRwLockPendFindPosSub(const struct TagTskCb *runTask, const struct TagListObject *lockList)
33 {
34 struct TagTskCb *pendedTask;
35 struct TagListObject *node = NULL;
36
37 LIST_FOR_EACH_SAFE(pendedTask, lockList, struct TagTskCb, pendList) {
38 if (pendedTask->priority < runTask->priority) {
39 continue;
40 } else if (pendedTask->priority > runTask->priority) {
41 node = &pendedTask->pendList;
42 break;
43 } else {
44 node = pendedTask->pendList.next;
45 break;
46 }
47 }
48
49 return node;
50 }
51
OsRwLockPendFindPos(struct TagTskCb * runTask,struct TagListObject * lockList)52 struct TagListObject *OsRwLockPendFindPos(struct TagTskCb *runTask, struct TagListObject *lockList)
53 {
54 struct TagListObject *node = NULL;
55 struct TagTskCb *taskFirst;
56 struct TagTskCb *taskLast;
57
58 if (ListEmpty(lockList)) {
59 node = lockList;
60 } else {
61 taskFirst = GET_TCB_PEND(LIST_FIRST(lockList));
62 taskLast = GET_TCB_PEND(LIST_LAST(lockList));
63 if (taskFirst->priority > runTask->priority) {
64 node = lockList->next;
65 } else if (taskLast->priority <= runTask->priority) {
66 node = lockList;
67 } else {
68 node = OsRwLockPendFindPosSub(runTask, lockList);
69 }
70 }
71
72 return node;
73 }
74
OsRwLockPendPre(struct TagTskCb * runTask,struct TagListObject * list,U32 timeout)75 void OsRwLockPendPre(struct TagTskCb *runTask, struct TagListObject *list, U32 timeout)
76 {
77 OsTskReadyDel(runTask);
78
79 TSK_STATUS_SET(runTask, OS_TSK_PEND);
80
81 if (timeout != OS_WAIT_FOREVER) {
82 TSK_STATUS_SET(runTask, OS_TSK_TIMEOUT);
83 OsTskTimerAdd(runTask, timeout);
84 }
85
86 ListTailAdd(&(runTask->pendList), list);
87 }
88
OsRwLockTaskWake(struct TagTskCb * resumedTask)89 void OsRwLockTaskWake(struct TagTskCb *resumedTask)
90 {
91 ListDelete(&resumedTask->pendList);
92
93 if (TSK_STATUS_TST(resumedTask, OS_TSK_TIMEOUT)) {
94 OS_TSK_DELAY_LOCKED_DETACH(resumedTask);
95 }
96
97 TSK_STATUS_CLEAR(resumedTask, OS_TSK_TIMEOUT | OS_TSK_PEND);
98
99 if (!TSK_STATUS_TST(resumedTask, OS_TSK_SUSPEND_READY_BLOCK)) {
100 OsTskReadyAddBgd(resumedTask);
101 }
102 }
103
OsRwLockTryRdCheck(struct TagTskCb * runTask,prt_pthread_rwlock_t * rwl)104 U32 OsRwLockTryRdCheck(struct TagTskCb *runTask, prt_pthread_rwlock_t *rwl)
105 {
106 if ((struct TagTskCb *)(rwl->rw_owner) == runTask) {
107 return EINVAL;
108 }
109
110 /* 读写锁为读模式或者初始化模式,并且当前读锁任务的优先级比第一个写锁pend任务的优先级低,
111 * 当前读锁任务不能获取锁
112 */
113 if ((rwl->rw_count >= 0) && !OsRwlockPriCompare(runTask, &(rwl->rw_write))) {
114 return EBUSY;
115 }
116
117 /* 读写锁被写锁获得,当前读锁任务不能获取锁 */
118 if (rwl->rw_count < 0) {
119 return EBUSY;
120 }
121
122 return OS_OK;
123 }
124
OsRwlockTryWrCheck(struct TagTskCb * runTask,prt_pthread_rwlock_t * rwl)125 U32 OsRwlockTryWrCheck(struct TagTskCb *runTask, prt_pthread_rwlock_t *rwl)
126 {
127 /* 读写锁被读锁获得,当前写锁任务不能获取锁 */
128 if (rwl->rw_count > 0) {
129 return EBUSY;
130 }
131
132 /* 读写锁被写锁获得,当前写锁任务不能获取锁. */
133 if ((rwl->rw_count < 0) && ((struct TagTskCb *)(rwl->rw_owner) != runTask)) {
134 return EBUSY;
135 }
136
137 return OS_OK;
138 }
139
OsRwLockCheck(prt_pthread_rwlock_t * rwl)140 OS_SEC_ALW_INLINE INLINE U32 OsRwLockCheck(prt_pthread_rwlock_t *rwl)
141 {
142 if (rwl == NULL) {
143 return EINVAL;
144 }
145
146 if ((rwl->rw_magic & RWLOCK_COUNT_MASK) != RWLOCK_MAGIC_NUM) {
147 return EINVAL;
148 }
149
150 if (OS_INT_ACTIVE) {
151 return EINVAL;
152 }
153
154 if (OS_TASK_LOCK_DATA != 0) {
155 return EDEADLK;
156 }
157
158 return OS_OK;
159 }
160
OsRwLockPendSchedule(struct TagTskCb * runTask,struct TagListObject * lockList,U32 timeout,U32 intSave)161 U32 OsRwLockPendSchedule(struct TagTskCb *runTask, struct TagListObject *lockList, U32 timeout, U32 intSave)
162 {
163 struct TagListObject *node;
164
165 if (timeout == 0) {
166 PRT_HwiRestore(intSave);
167 return EINVAL;
168 }
169
170 node = OsRwLockPendFindPos(runTask, lockList);
171 OsRwLockPendPre(runTask, node, timeout);
172 if (timeout != OS_WAIT_FOREVER) {
173 PRT_HwiRestore(intSave);
174 OsTskSchedule();
175 intSave = PRT_HwiLock();
176 /* 判断是否是等待信号量超时 */
177 if (TSK_STATUS_TST(runTask, OS_TSK_TIMEOUT)) {
178 TSK_STATUS_CLEAR(runTask, OS_TSK_TIMEOUT);
179 PRT_HwiRestore(intSave);
180 return ETIMEDOUT;
181 }
182 PRT_HwiRestore(intSave);
183 } else {
184 PRT_HwiRestore(intSave);
185 OsTskSchedule();
186 }
187
188 return OS_OK;
189 }
190
OsRwLockRdPend(prt_pthread_rwlock_t * rwl,U32 timeout,U32 rwType)191 U32 OsRwLockRdPend(prt_pthread_rwlock_t *rwl, U32 timeout, U32 rwType)
192 {
193 U32 ret;
194 U32 intSave;
195 struct TagTskCb *runTask = NULL;
196
197 intSave = PRT_HwiLock();
198
199 ret = OsRwLockCheck(rwl);
200 if (ret != OS_OK) {
201 PRT_HwiRestore(intSave);
202 return ret;
203 }
204
205 runTask = (struct TagTskCb *)RUNNING_TASK;
206
207 if (rwType == RWLOCK_TRYRD) {
208 ret = OsRwLockTryRdCheck(runTask, rwl);
209 if (ret != OS_OK) {
210 PRT_HwiRestore(intSave);
211 return ret;
212 }
213 }
214
215 /*
216 * 读写锁为读模式或者初始化模式,并且当前读锁任务的优先级比第一个写锁pend任务的优先级高,
217 * 当前读锁任务能获取锁
218 */
219 if (rwl->rw_count >= 0) {
220 if (OsRwlockPriCompare(runTask, &(rwl->rw_write))) {
221 if (rwl->rw_count == S32_MAX) {
222 PRT_HwiRestore(intSave);
223 return EINVAL;
224 }
225 rwl->rw_count++;
226 PRT_HwiRestore(intSave);
227 return OS_OK;
228 }
229 }
230
231 if ((struct TagTskCb *)(rwl->rw_owner) == runTask) {
232 PRT_HwiRestore(intSave);
233 return EINVAL;
234 }
235
236 return OsRwLockPendSchedule(runTask, &(rwl->rw_read), timeout, intSave);
237 }
238
OsRwLockWrPend(prt_pthread_rwlock_t * rwl,U32 timeout,U32 rwType)239 U32 OsRwLockWrPend(prt_pthread_rwlock_t *rwl, U32 timeout, U32 rwType)
240 {
241 U32 ret;
242 U32 intSave;
243 struct TagTskCb *runTask;
244
245 intSave = PRT_HwiLock();
246
247 ret = OsRwLockCheck(rwl);
248 if (ret != OS_OK) {
249 PRT_HwiRestore(intSave);
250 return ret;
251 }
252
253 runTask = (struct TagTskCb *)RUNNING_TASK;
254 if (rwType == RWLOCK_TRYWR) {
255 ret = OsRwlockTryWrCheck(runTask, rwl);
256 if (ret != OS_OK) {
257 PRT_HwiRestore(intSave);
258 return ret;
259 }
260 }
261
262 if (rwl->rw_count == 0) {
263 rwl->rw_count = -1;
264 rwl->rw_owner = (void *)runTask;
265 PRT_HwiRestore(intSave);
266 return OS_OK;
267 }
268
269 /* 如果读写锁被自身获取,只能获取一次. */
270 if ((rwl->rw_count < 0) && ((struct TagTskCb *)(rwl->rw_owner) == runTask)) {
271 if (rwl->rw_count == S32_MIN) {
272 PRT_HwiRestore(intSave);
273 return EINVAL;
274 }
275 PRT_HwiRestore(intSave);
276 return OS_OK;
277 }
278
279 return OsRwLockPendSchedule(runTask, &(rwl->rw_write), timeout, intSave);
280 }
281
OsRwLockGetMode(struct TagListObject * readList,struct TagListObject * writeList)282 U32 OsRwLockGetMode(struct TagListObject *readList, struct TagListObject *writeList)
283 {
284 bool isReadEmpty = ListEmpty(readList);
285 bool isWriteEmpty = ListEmpty(writeList);
286 if (isReadEmpty && isWriteEmpty) {
287 return RWLOCK_NONE_MODE;
288 }
289 if (!isReadEmpty && isWriteEmpty) {
290 return RWLOCK_READ_MODE;
291 }
292 if (isReadEmpty && !isWriteEmpty) {
293 return RWLOCK_WRITE_MODE;
294 }
295
296 struct TagTskCb *pendedReadTask = GET_TCB_PEND(LIST_FIRST(readList));
297 struct TagTskCb *pendedWriteTask = GET_TCB_PEND(LIST_FIRST(writeList));
298 if (pendedWriteTask->priority <= pendedReadTask->priority) {
299 return RWLOCK_WRITEFIRST_MODE;
300 }
301 return RWLOCK_READFIRST_MODE;
302 }
303
OsRwLockPost(prt_pthread_rwlock_t * rwl,bool * needSched)304 U32 OsRwLockPost(prt_pthread_rwlock_t *rwl, bool *needSched)
305 {
306 U32 rwlockMode;
307 struct TagTskCb *resumedTask = NULL;
308 U32 pendedWriteTaskPri = 0;
309
310 rwl->rw_count = 0;
311 rwl->rw_owner = NULL;
312 rwlockMode = OsRwLockGetMode(&(rwl->rw_read), &(rwl->rw_write));
313 if (rwlockMode == RWLOCK_NONE_MODE) {
314 return OS_OK;
315 }
316
317 /* 唤醒第一个被pend的写锁任务 */
318 if ((rwlockMode == RWLOCK_WRITE_MODE) || (rwlockMode == RWLOCK_WRITEFIRST_MODE)) {
319 resumedTask = GET_TCB_PEND(LIST_FIRST(&(rwl->rw_write)));
320 rwl->rw_count = -1;
321 rwl->rw_owner = (void *)resumedTask;
322 OsRwLockTaskWake(resumedTask);
323 if (needSched != NULL) {
324 *needSched = TRUE;
325 }
326 return OS_OK;
327 }
328
329 /* 唤醒被pend的读锁任务 */
330 if (rwlockMode == RWLOCK_READFIRST_MODE) {
331 pendedWriteTaskPri = GET_TCB_PEND(LIST_FIRST(&(rwl->rw_write)))->priority;
332 }
333
334 resumedTask = GET_TCB_PEND(LIST_FIRST(&(rwl->rw_read)));
335 rwl->rw_count = 1;
336 OsRwLockTaskWake(resumedTask);
337 while (!ListEmpty(&(rwl->rw_read))) {
338 resumedTask = GET_TCB_PEND(LIST_FIRST(&(rwl->rw_read)));
339 if ((rwlockMode == RWLOCK_READFIRST_MODE) && (resumedTask->priority >= pendedWriteTaskPri)) {
340 break;
341 }
342
343 if (rwl->rw_count == S32_MAX) {
344 return EINVAL;
345 }
346
347 rwl->rw_count++;
348 OsRwLockTaskWake(resumedTask);
349 }
350
351 if (needSched != NULL) {
352 *needSched = TRUE;
353 }
354 return OS_OK;
355 }
356
OsRwLockUnlock(prt_pthread_rwlock_t * rwl,bool * needSched)357 U32 OsRwLockUnlock(prt_pthread_rwlock_t *rwl, bool *needSched)
358 {
359 struct TagTskCb *runTask;
360
361 if (rwl == NULL) {
362 return EINVAL;
363 }
364 if ((rwl->rw_magic & RWLOCK_COUNT_MASK) != RWLOCK_MAGIC_NUM) {
365 return EINVAL;
366 }
367
368 if (rwl->rw_count == 0) {
369 return EPERM;
370 }
371
372 runTask = RUNNING_TASK;
373 if ((rwl->rw_count < 0) && ((struct TagTskCb *)(rwl->rw_owner) != runTask)) {
374 return EPERM;
375 }
376
377 if (rwl->rw_count > 1) {
378 rwl->rw_count--;
379 return OS_OK;
380 }
381
382 if (rwl->rw_count < -1) {
383 rwl->rw_count++;
384 return OS_OK;
385 }
386
387 return OsRwLockPost(rwl, needSched);
388 }
389