• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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