• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification,
5  * are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice, this list of
8  *    conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11  *    of conditions and the following disclaimer in the documentation and/or other materials
12  *    provided with the distribution.
13  *
14  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15  *    to endorse or promote products derived from this software without specific prior written
16  *    permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "los_signal.h"
32 #include "securec.h"
33 #include "los_config.h"
34 #include "los_interrupt.h"
35 #include "los_task.h"
36 #include "los_sched.h"
37 #include "los_debug.h"
38 #include "los_memory.h"
39 #include "los_context.h"
40 #include "los_arch_context.h"
41 
OsSignalTaskContextRestore(VOID)42 UINTPTR OsSignalTaskContextRestore(VOID)
43 {
44 #if (LOSCFG_KERNEL_SIGNAL == 1)
45     LosTaskCB *task = OsCurrTaskGet();
46     OsSigCB *sigCB = (OsSigCB *)task->sig;
47     UINTPTR sp;
48 
49     if ((sigCB == NULL) || (sigCB->sigRestoreSP == NULL)) {
50         return 0;
51     }
52 
53     sp = (UINTPTR)sigCB->sigRestoreSP;
54     sigCB->sigRestoreSP = NULL;
55 
56     return sp;
57 #else
58     return 0;
59 #endif
60 }
61 
62 #if (LOSCFG_KERNEL_SIGNAL == 1)
63 STATIC LOS_DL_LIST g_waitSignalList;
64 
SignalDefaultHandler(INT32 signo)65 STATIC VOID SignalDefaultHandler(INT32 signo)
66 {
67     PRINTK("signal default handler, signo = %d\n", signo);
68 }
69 
AddSigInfoToList(OsSigCB * sigCB,siginfo_t * info)70 STATIC UINT32 AddSigInfoToList(OsSigCB *sigCB, siginfo_t *info)
71 {
72     OsSigInfoNode *tmpInfo = NULL;
73     BOOL findFlag = FALSE;
74 
75     LOS_DL_LIST_FOR_EACH_ENTRY(tmpInfo, &sigCB->sigInfoList, OsSigInfoNode, node) {
76         if (tmpInfo->info.si_signo == info->si_signo) {
77             findFlag = TRUE;
78             break;
79         }
80     }
81 
82     if (findFlag == FALSE) {
83         tmpInfo = (OsSigInfoNode *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(OsSigInfoNode));
84         if (tmpInfo == NULL) {
85             return LOS_NOK;
86         }
87         LOS_ListAdd(&sigCB->sigInfoList, &tmpInfo->node);
88     }
89     (VOID)memcpy_s(&tmpInfo->info, sizeof(siginfo_t), info, sizeof(siginfo_t));
90     return LOS_OK;
91 }
92 
DeleteSigInfoFromList(OsSigCB * sigCB,INT32 sigNo)93 STATIC VOID DeleteSigInfoFromList(OsSigCB *sigCB, INT32 sigNo)
94 {
95     OsSigInfoNode *tmpInfo = NULL;
96     BOOL findFlag = FALSE;
97 
98     LOS_DL_LIST_FOR_EACH_ENTRY(tmpInfo, &sigCB->sigInfoList, OsSigInfoNode, node) {
99         if (tmpInfo->info.si_signo == sigNo) {
100             LOS_ListDelete(&tmpInfo->node);
101             findFlag = TRUE;
102             break;
103         }
104     }
105 
106     if (findFlag == TRUE) {
107         (VOID)memcpy_s(&sigCB->sigInfo, sizeof(siginfo_t), &tmpInfo->info, sizeof(siginfo_t));
108         (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, tmpInfo);
109     }
110 }
111 
SignalHandle(LosTaskCB * task,BOOL cleanStatus)112 STATIC VOID SignalHandle(LosTaskCB *task, BOOL cleanStatus)
113 {
114     UINT32 intSave;
115     OsSigCB *sigCB = NULL;
116 
117     intSave = LOS_IntLock();
118     sigCB = task->sig;
119     if (sigCB == NULL) {
120         LOS_IntRestore(intSave);
121         return;
122     }
123 
124     while (sigCB->sigPendFlag & sigCB->sigSetFlag) {
125         UINT32 sigFlag = sigCB->sigPendFlag & sigCB->sigSetFlag;
126         INT32 sigNo = LOS_SIGNAL_SUPPORT_MAX - CLZ(sigFlag) + 1;
127         DeleteSigInfoFromList(sigCB, sigNo);
128 
129         SIG_HANDLER handler = sigCB->sigHandlers[sigNo - 1];
130         sigCB->sigPendFlag &= ~LOS_SIGNAL_MASK(sigNo);
131         LOS_IntRestore(intSave);
132 
133         if (handler != NULL) {
134             handler(sigNo);
135         }
136         intSave = LOS_IntLock();
137 
138         if (cleanStatus == TRUE) {
139             task->taskStatus &= ~OS_TASK_FLAG_SIGNAL;
140         }
141     }
142     LOS_IntRestore(intSave);
143 }
144 
SignalEntry(INT32 sigNo)145 STATIC VOID SignalEntry(INT32 sigNo)
146 {
147     (void)sigNo;
148     LosTaskCB *task = OsCurrTaskGet();
149     OsSigCB *sigCB = (OsSigCB *)task->sig;
150 
151     SignalHandle(task, FALSE);
152 
153     task->stackPointer = sigCB->sigSaveSP;
154     sigCB->sigSaveSP = NULL;
155     sigCB->sigRestoreSP = task->stackPointer;
156     task->taskStatus &= ~OS_TASK_FLAG_SIGNAL;
157 
158     LOS_Schedule();
159 }
160 
SignalSend(LosTaskCB * task,INT32 sigNo)161 STATIC VOID SignalSend(LosTaskCB *task, INT32 sigNo)
162 {
163     UINT32 intSave;
164     OsSigCB *sigCB = NULL;
165     sigset_t mask = LOS_SIGNAL_MASK(sigNo);
166 
167     intSave = LOS_IntLock();
168     sigCB = task->sig;
169     if (sigCB == NULL) {
170         LOS_IntRestore(intSave);
171         return;
172     }
173 
174     if (!(sigCB->sigPendFlag & mask)) {
175         sigCB->sigPendFlag |= mask;
176     }
177 
178     if (task == OsCurrTaskGet()) {
179         task->taskStatus |= OS_TASK_FLAG_SIGNAL;
180         LOS_IntRestore(intSave);
181 
182         if (!OS_INT_ACTIVE) {
183             SignalHandle(task, TRUE);
184         }
185     } else {
186         if (sigCB->sigStatus & OS_SIGNAL_STATUS_WAIT) {
187             if (sigCB->sigWaitFlag & LOS_SIGNAL_MASK(sigNo)) {
188                 DeleteSigInfoFromList(sigCB, sigNo);
189                 OsSchedTaskWake(task);
190                 task->taskStatus |= OS_TASK_FLAG_SIGNAL;
191             }
192         } else if (!(task->taskStatus & OS_TASK_FLAG_SIGNAL)) {
193             task->taskStatus |= OS_TASK_FLAG_SIGNAL;
194             sigCB->sigSaveSP = task->stackPointer;
195             sigCB->sigRestoreSP = NULL;
196             task->stackPointer = ArchSignalContextInit(task->stackPointer, (VOID *)task->topOfStack,
197                                                        (UINTPTR)SignalEntry, sigNo);
198         }
199         LOS_IntRestore(intSave);
200         LOS_Schedule();
201     }
202 }
203 
SignalCBInit(LosTaskCB * task)204 STATIC OsSigCB *SignalCBInit(LosTaskCB *task)
205 {
206     OsSigCB *sigCB = NULL;
207     UINT32 i;
208 
209     if (task->sig == NULL) {
210         sigCB = (OsSigCB *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(OsSigCB));
211         if (sigCB == NULL) {
212             return NULL;
213         }
214         (VOID)memset_s(sigCB, sizeof(OsSigCB), 0, sizeof(OsSigCB));
215         LOS_ListInit(&sigCB->sigInfoList);
216 
217         for (i = 0; i <= LOS_SIGNAL_SUPPORT_MAX; i++) {
218             sigCB->sigHandlers[i] = SignalDefaultHandler;
219         }
220 
221         task->sig = (VOID *)sigCB;
222     } else {
223         sigCB = (OsSigCB *)task->sig;
224     }
225 
226     return sigCB;
227 }
228 
LOS_SignalSet(INT32 sigNo,SIG_HANDLER handler)229 SIG_HANDLER LOS_SignalSet(INT32 sigNo, SIG_HANDLER handler)
230 {
231     UINT32 intSave;
232     SIG_HANDLER old = NULL;
233     LosTaskCB *task = OsCurrTaskGet();
234     OsSigCB *sigCB = NULL;
235 
236     if (task == NULL) {
237         return SIG_ERR;
238     }
239 
240     if (!OS_SIGNAL_VALID(sigNo)) {
241         return SIG_ERR;
242     }
243 
244     intSave = LOS_IntLock();
245     sigCB = SignalCBInit(task);
246     if (sigCB == NULL) {
247         LOS_IntRestore(intSave);
248         return SIG_ERR;
249     }
250 
251     old = sigCB->sigHandlers[sigNo - 1]; /* signal number from 1, but index from 0 */
252     if (handler == SIG_IGN) {
253         sigCB->sigHandlers[sigNo - 1] = NULL;
254         sigCB->sigSetFlag &= ~LOS_SIGNAL_MASK(sigNo);
255     } else if (handler == SIG_DFL) {
256         sigCB->sigHandlers[sigNo - 1] = SignalDefaultHandler;
257         sigCB->sigSetFlag |= LOS_SIGNAL_MASK(sigNo);
258     } else {
259         sigCB->sigHandlers[sigNo - 1] = handler;
260         sigCB->sigSetFlag |= LOS_SIGNAL_MASK(sigNo);
261     }
262     LOS_IntRestore(intSave);
263 
264     return old;
265 }
266 
LOS_SignalMask(INT32 how,const sigset_t * set,sigset_t * oldSet)267 UINT32 LOS_SignalMask(INT32 how, const sigset_t *set, sigset_t *oldSet)
268 {
269     UINT32 intSave;
270     LosTaskCB *task = OsCurrTaskGet();
271     OsSigCB *sigCB = NULL;
272 
273     if (task == NULL) {
274         return LOS_ERRNO_SIGNAL_CAN_NOT_CALL;
275     }
276 
277     intSave = LOS_IntLock();
278     sigCB = SignalCBInit(task);
279     if (sigCB == NULL) {
280         LOS_IntRestore(intSave);
281         return LOS_ERRNO_SIGNAL_NO_MEMORY;
282     }
283 
284     if (oldSet != NULL) {
285         *oldSet = sigCB->sigSetFlag;
286     }
287 
288     if (set == NULL) {
289         LOS_IntRestore(intSave);
290         return LOS_ERRNO_SIGNAL_INVALID;
291     }
292 
293     switch (how) {
294         case SIG_BLOCK:
295             sigCB->sigSetFlag &= ~*set;
296             break;
297         case SIG_SETMASK:
298             sigCB->sigSetFlag = *set;
299             break;
300         case SIG_UNBLOCK:
301             sigCB->sigSetFlag |= *set;
302             break;
303         default:
304             PRINT_ERR("The error parameter how = %d\n", how);
305             break;
306     }
307     LOS_IntRestore(intSave);
308 
309     return LOS_OK;
310 }
311 
SignalTimedWait(LosTaskCB * task,const sigset_t * set,UINT32 timeout,UINT32 * intSave)312 STATIC INLINE UINT32 SignalTimedWait(LosTaskCB *task, const sigset_t *set, UINT32 timeout, UINT32 *intSave)
313 {
314     OsSigCB *sigCB = (OsSigCB *)task->sig;
315     INT32 sigNo;
316 
317     if (timeout == 0) {
318         LOS_IntRestore(*intSave);
319         return LOS_ERRNO_SIGNAL_INVALID;
320     }
321 
322     if (OS_INT_ACTIVE) {
323         LOS_IntRestore(*intSave);
324         return LOS_ERRNO_SIGNAL_PEND_INTERR;
325     }
326 
327     sigCB->sigWaitFlag |= *set;
328     sigCB->sigStatus |= OS_SIGNAL_STATUS_WAIT;
329 
330     OsSchedTaskWait(&g_waitSignalList, timeout);
331     LOS_IntRestore(*intSave);
332     LOS_Schedule();
333 
334     *intSave = LOS_IntLock();
335     task->taskStatus &= ~OS_TASK_FLAG_SIGNAL;
336     sigCB->sigStatus &= ~OS_SIGNAL_STATUS_WAIT;
337     sigCB->sigWaitFlag = 0;
338     if (task->taskStatus & OS_TASK_STATUS_TIMEOUT) {
339         task->taskStatus &= ~OS_TASK_STATUS_TIMEOUT;
340         LOS_IntRestore(*intSave);
341         return LOS_ERRNO_SIGNAL_TIMEOUT;
342     }
343     sigNo = sigCB->sigInfo.si_signo;
344     sigCB->sigPendFlag &= ~LOS_SIGNAL_MASK(sigNo);
345     return sigNo;
346 }
347 
LOS_SignalWait(const sigset_t * set,siginfo_t * info,UINT32 timeout)348 UINT32 LOS_SignalWait(const sigset_t *set, siginfo_t *info, UINT32 timeout)
349 {
350     UINT32 intSave;
351     LosTaskCB *task = OsCurrTaskGet();
352     OsSigCB *sigCB = NULL;
353     sigset_t sigFlag;
354     INT32 sigNo;
355 
356     if ((set == NULL) || (*set == 0)) {
357         return LOS_ERRNO_SIGNAL_INVALID;
358     }
359 
360     if (task == NULL) {
361         return LOS_ERRNO_SIGNAL_CAN_NOT_CALL;
362     }
363 
364     intSave = LOS_IntLock();
365     sigCB = SignalCBInit(task);
366     if (sigCB == NULL) {
367         LOS_IntRestore(intSave);
368         return LOS_ERRNO_SIGNAL_NO_MEMORY;
369     }
370 
371     sigFlag = sigCB->sigPendFlag & *set;
372     if (sigFlag) {
373         sigCB->sigPendFlag ^= sigFlag;
374         sigNo = LOS_SIGNAL_SUPPORT_MAX - CLZ(sigFlag) + 1;
375         DeleteSigInfoFromList(sigCB, sigNo);
376     } else {
377         sigNo = SignalTimedWait(task, set, timeout, &intSave);
378         if (sigNo > LOS_SIGNAL_SUPPORT_MAX) {
379             LOS_IntRestore(intSave);
380             return sigNo;
381         }
382     }
383 
384     if (info != NULL) {
385         (VOID)memcpy_s(info, sizeof(siginfo_t), &sigCB->sigInfo, sizeof(siginfo_t));
386     }
387     LOS_IntRestore(intSave);
388 
389     return sigNo;
390 }
391 
LOS_SignalSend(UINT32 taskID,INT32 sigNo)392 UINT32 LOS_SignalSend(UINT32 taskID, INT32 sigNo)
393 {
394     siginfo_t info;
395     UINT32 intSave;
396     OsSigCB *sigCB = NULL;
397     LosTaskCB *task = NULL;
398 
399     if (taskID > LOSCFG_BASE_CORE_TSK_LIMIT) {
400         return LOS_ERRNO_SIGNAL_INVALID;
401     }
402 
403     if (!OS_SIGNAL_VALID(sigNo)) {
404         return LOS_ERRNO_SIGNAL_INVALID;
405     }
406 
407     info.si_signo = sigNo;
408     info.si_code = SI_USER;
409     info.si_value.sival_ptr = NULL;
410 
411     intSave = LOS_IntLock();
412     task = OS_TCB_FROM_TID(taskID);
413     sigCB = SignalCBInit(task);
414     if (sigCB == NULL) {
415         LOS_IntRestore(intSave);
416         return LOS_ERRNO_SIGNAL_NO_MEMORY;
417     }
418 
419     if (!(sigCB->sigSetFlag & LOS_SIGNAL_MASK(sigNo))) { /* the signal has not been set */
420         LOS_IntRestore(intSave);
421         return LOS_ERRNO_SIGNAL_NO_SET;
422     }
423 
424     UINT32 ret = AddSigInfoToList(sigCB, &info);
425     if (ret != LOS_OK) {
426         LOS_IntRestore(intSave);
427         return LOS_ERRNO_SIGNAL_NO_MEMORY;
428     }
429     LOS_IntRestore(intSave);
430 
431     /* send signal to this thread */
432     SignalSend(task, sigNo);
433 
434     return LOS_OK;
435 }
436 
OsSignalInit(VOID)437 UINT32 OsSignalInit(VOID)
438 {
439     LOS_ListInit(&g_waitSignalList);
440     return LOS_OK;
441 }
442 #endif