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