los_signal.c 29.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
/*
 * Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved.
 * Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "los_signal.h"
#include "pthread.h"
#include "los_process_pri.h"
#include "los_hw_pri.h"
#include "user_copy.h"
#ifdef LOSCFG_SECURITY_CAPABILITY
#include "capability_api.h"
#endif

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */

int raise(int sig)
{
    (VOID)sig;
    PRINT_ERR("%s NOT SUPPORT\n", __FUNCTION__);
    errno = ENOSYS;
    return -1;
}

#define GETUNMASKSET(procmask, pendFlag) ((~(procmask)) & (sigset_t)(pendFlag))
#define UINT64_BIT_SIZE 64
/****************************************************
58
判定信号signo是否存在信号集中。
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
如果信号集里已有该信号则返回1,否则返回0。如果有错误则返回-1
****************************************************/
int OsSigIsMember(const sigset_t *set, int signo)
{
    int ret = LOS_NOK;
    /* In musl, sig No bits 00000100 present sig No 3, but  1<< 3 = 00001000, so signo needs minus 1 */ 
	//在musl中,sig No bits 00000100表示sig No 3,但是在SIGNO2SET中 1<<3 = 00001000,因此signo需要减1
    signo -= 1;
    /* Verify the signal */
    if (GOOD_SIGNO(signo)) {//有效信号判断
        /* Check if the signal is in the set */
        ret = ((*set & SIGNO2SET((unsigned int)signo)) != 0);//检查信号是否还在集合中
    }

    return ret;
}
//给任务(线程)发送一个信号
int OsTcbDispatch(LosTaskCB *stcb, siginfo_t *info)
{
    bool masked = FALSE;
    sig_cb *sigcb = &stcb->sig;

    OS_RETURN_IF_NULL(sigcb);
    /* If signo is 0, not send signal, just check process or pthread exist */
    if (info->si_signo == 0) {
        return 0;
    }
    masked = (bool)OsSigIsMember(&sigcb->sigprocmask, info->si_signo);//@note_thinking 这里还有 masked= -1的情况要处理!!!
    if (masked) {//集合中已有该信号
        /* If signal is in wait list and mask list, need unblock it */ //如果信号在等待列表和掩码列表中,需要解除阻止
89 90 91
        if (!LOS_ListEmpty(&sigcb->waitList) && OsSigIsMember(&sigcb->sigwaitmask, info->si_signo)) {//waitList上挂的都是task,sigwaitmask表示是否在等si_signo
            OsTaskWake(stcb);//唤醒任务,从阻塞状态变成就绪态
            OsSigEmptySet(&sigcb->sigwaitmask);//将sigwaitmask清空,都已经变成就绪状态了,当然就没有要等待的信号了.
92
        } else {
93
            OsSigAddSet(&sigcb->sigPendFlag, info->si_signo);//
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
        }
    } else {//
        /* unmasked signal actions */
        OsSigAddSet(&sigcb->sigFlag, info->si_signo);
        if (!LOS_ListEmpty(&sigcb->waitList) && OsSigIsMember(&sigcb->sigwaitmask, info->si_signo)) {
            OsTaskWake(stcb);
            OsSigEmptySet(&sigcb->sigwaitmask);
        }
    }
    (void) memcpy_s(&sigcb->sigunbinfo, sizeof(siginfo_t), info, sizeof(siginfo_t));
    return 0;
}

void OsSigMaskSwitch(LosTaskCB * const rtcb, sigset_t set)
{
    sigset_t unmaskset;

    rtcb->sig.sigprocmask = set;
    unmaskset = GETUNMASKSET(rtcb->sig.sigprocmask, rtcb->sig.sigPendFlag);
    if (unmaskset != NULL_SIGNAL_SET) {
        /* pendlist do */
        rtcb->sig.sigFlag |= unmaskset;
        rtcb->sig.sigPendFlag ^= unmaskset;
    }
}
119
/******************************************************************
120
向信号集设置信号屏蔽的方法
121 122 123 124
	SIG_BLOCK:将set指向信号集中的信号,添加到进程阻塞信号集;
	SIG_UNBLOCK:将set指向信号集中的信号,从进程阻塞信号集删除;
	SIG_SETMASK:将set指向信号集中的信号,设置成进程阻塞信号集;
*******************************************************************/
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
int OsSigprocMask(int how, const sigset_t_l *setl, sigset_t_l *oldset)
{
    LosTaskCB *spcb = NULL;
    sigset_t oldSigprocmask;
    int ret = LOS_OK;
    unsigned int intSave;
    sigset_t set;
    int retVal;

    if (setl != NULL) {
        retVal = LOS_ArchCopyFromUser(&set, &(setl->sig[0]), sizeof(sigset_t));
        if (retVal != 0) {
            return -EFAULT;
        }
    }
    SCHEDULER_LOCK(intSave);
    spcb = OsCurrTaskGet();
    /* If requested, copy the old mask to user. */ //如果需要,请将旧掩码复制给用户
    oldSigprocmask = spcb->sig.sigprocmask;

    /* If requested, modify the current signal mask. */ //如有要求,修改当前信号屏蔽
    if (setl != NULL) {
        /* Okay, determine what we are supposed to do */
        switch (how) {
            /* Set the union of the current set and the signal
             * set pointed to by set as the new sigprocmask.
             */
            case SIG_BLOCK:
                spcb->sig.sigprocmask |= set;//增加信号屏蔽位
                break;
            /* Set the intersection of the current set and the
             * signal set pointed to by set as the new sigprocmask.
             */
            case SIG_UNBLOCK:
                spcb->sig.sigprocmask &= ~(set);//解除信号屏蔽位
                break;
            /* Set the signal set pointed to by set as the new sigprocmask. */
            case SIG_SETMASK:
                spcb->sig.sigprocmask = set;//设置一个新的屏蔽掩码
                break;
            default:
                ret = -EINVAL;
                break;
        }
        /* If pending mask not in sigmask, need set sigflag. */
        OsSigMaskSwitch(spcb, spcb->sig.sigprocmask);
    }
    SCHEDULER_UNLOCK(intSave);

    if (oldset != NULL) {
        retVal = LOS_ArchCopyToUser(&(oldset->sig[0]), &oldSigprocmask, sizeof(sigset_t));
        if (retVal != 0) {
            return -EFAULT;
        }
    }
    return ret;
}
//让进程的每一个task执行参数函数
int OsSigProcessForeachChild(LosProcessCB *spcb, ForEachTaskCB handler, void *arg)
{
    int ret;

187
    /* Visit the main thread last (if present) */
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
    LosTaskCB *taskCB = NULL;//遍历进程的 threadList 链表,里面存放的都是task节点
    LOS_DL_LIST_FOR_EACH_ENTRY(taskCB, &(spcb->threadSiblingList), LosTaskCB, threadList) {//遍历进程的任务列表
        ret = handler(taskCB, arg);//回调参数函数
        OS_RETURN_IF(ret != 0, ret);//这个宏的意思就是只有ret = 0时,啥也不处理.其余就返回 ret
    }
    return LOS_OK;
}
//信号处理函数,这里就是上面的 handler =  SigProcessSignalHandler,见于 OsSigProcessSend
static int SigProcessSignalHandler(LosTaskCB *tcb, void *arg)
{
    struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;//先把参数解出来
    int ret;
    int isMember;

    if (tcb == NULL) {
        return 0;
    }

    /* If the default tcb is not setted, then set this one as default. */
207
    if (!info->defaultTcb) {//如果没有默认发送方的任务,即默认参数任务.
208 209 210
        info->defaultTcb = tcb;
    }

211 212
    isMember = OsSigIsMember(&tcb->sig.sigwaitmask, info->sigInfo->si_signo);//任务是否在等待这个信号
    if (isMember && (!info->awakenedTcb)) {//是在等待,并尚未向该任务时发送信号时
213 214 215 216
        /* This means the task is waiting for this signal. Stop looking for it and use this tcb.
         * The requirement is: if more than one task in this task group is waiting for the signal,
         * then only one indeterminate task in the group will receive the signal.
         */
217
        ret = OsTcbDispatch(tcb, info->sigInfo);//发送信号,注意这是给其他任务发送信号,tcb不是当前任务
218 219 220 221 222 223 224
        OS_RETURN_IF(ret < 0, ret);//这种写法很有意思

        /* set this tcb as awakenedTcb */
        info->awakenedTcb = tcb;
        OS_RETURN_IF(info->receivedTcb != NULL, SIG_STOP_VISIT); /* Stop search */
    }
    /* Is this signal unblocked on this thread? */
225 226
    isMember = OsSigIsMember(&tcb->sig.sigprocmask, info->sigInfo->si_signo);//任务是否屏蔽了这个信号
    if ((!isMember) && (!info->receivedTcb) && (tcb != info->awakenedTcb)) {//没有屏蔽,有唤醒任务没有接收任务.
227 228 229 230 231
        /* if unblockedTcb of this signal is not setted, then set it. */
        if (!info->unblockedTcb) {
            info->unblockedTcb = tcb;
        }

232
        ret = OsTcbDispatch(tcb, info->sigInfo);//向任务发送信号
233 234
        OS_RETURN_IF(ret < 0, ret);
        /* set this tcb as receivedTcb */
235
        info->receivedTcb = tcb;//设置这个任务为接收任务
236 237 238 239
        OS_RETURN_IF(info->awakenedTcb != NULL, SIG_STOP_VISIT); /* Stop search */
    }
    return 0; /* Keep searching */
}
240
//进程收到 SIGKILL 信号后,通知任务tcb处理.
241 242 243 244 245 246
static int SigProcessKillSigHandler(LosTaskCB *tcb, void *arg)
{
    struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;//转参

    if ((tcb != NULL) && (info != NULL) && (info->sigInfo != NULL)) {//进程有信号
        sig_cb *sigcb = &tcb->sig;
247 248 249
        if (!LOS_ListEmpty(&sigcb->waitList) && OsSigIsMember(&sigcb->sigwaitmask, info->sigInfo->si_signo)) {//如果任务在等待这个信号
            OsTaskWake(tcb);//唤醒这个任务,加入进程的就绪队列,,并不申请调度
            OsSigEmptySet(&sigcb->sigwaitmask);//清空信号等待位,不等任何信号了.因为这是SIGKILL信号
250 251 252 253
        }
    }
    return 0;
}
254
//处理信号发送
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
static void SigProcessLoadTcb(struct ProcessSignalInfo *info, siginfo_t *sigInfo)
{
    LosTaskCB *tcb = NULL;

    if (info->awakenedTcb == NULL && info->receivedTcb == NULL) {//信号即没有指定接收task 也没有指定被唤醒task
        if (info->unblockedTcb) {//如果进程信号信息体中有阻塞task
            tcb = info->unblockedTcb;//
        } else if (info->defaultTcb) {//如果有默认的发送方task
            tcb = info->defaultTcb;
        } else {
            return;
        }
        /* Deliver the signal to the selected task */
        (void)OsTcbDispatch(tcb, sigInfo);//向所选任务发送信号
    }
}
//给参数进程发送参数信号
int OsSigProcessSend(LosProcessCB *spcb, siginfo_t *sigInfo)
{
    int ret;
    struct ProcessSignalInfo info = {
        .sigInfo = sigInfo, //信号内容
277
        .defaultTcb = NULL, //以下四个值将在OsSigProcessForeachChild中根据条件完善
278 279 280 281
        .unblockedTcb = NULL,
        .awakenedTcb = NULL,
        .receivedTcb = NULL
    };
282 283
	//总之是要从进程中找个至少一个任务来接受这个信号,优先级
	//awakenedTcb > receivedTcb > unblockedTcb > defaultTcb
284 285
    /* visit all taskcb and dispatch signal */ //访问所有任务和分发信号
    if ((info.sigInfo != NULL) && (info.sigInfo->si_signo == SIGKILL)) {//需要干掉进程时 SIGKILL = 9, #linux kill 9 14
286
        (void)OsSigProcessForeachChild(spcb, SigProcessKillSigHandler, &info);//进程要被干掉了,通知所有task做善后处理
287
        OsSigAddSet(&spcb->sigShare, info.sigInfo->si_signo);//信号集中增加信号
288 289 290
        OsWaitSignalToWakeProcess(spcb);//等待信号唤醒进程
        return 0;
    } else {
291
        ret = OsSigProcessForeachChild(spcb, SigProcessSignalHandler, &info);//进程通知所有task处理信号
292 293 294 295
    }
    if (ret < 0) {
        return ret;
    }
296
    SigProcessLoadTcb(&info, sigInfo);//确保能给一个任务发送信号
297 298
    return 0;
}
299
//信号集全部清0
300 301 302 303 304 305
int OsSigEmptySet(sigset_t *set)
{
    *set = NULL_SIGNAL_SET;
    return 0;
}

306
/* Privilege process can't send to kernel and privilege process */ //内核进程组和用户特权进程组无法发送
307 308 309 310 311 312 313 314 315 316 317 318
static int OsSignalPermissionToCheck(const LosProcessCB *spcb)
{
    UINT32 gid = spcb->group->groupID;

    if (gid == OS_KERNEL_PROCESS_GROUP) {//内核进程组
        return -EPERM;
    } else if (gid == OS_USER_PRIVILEGE_PROCESS_GROUP) {//用户特权进程组
        return -EPERM;
    }

    return 0;
}
319
//信号分发,发送信号权限/进程组过滤.
320 321 322
int OsDispatch(pid_t pid, siginfo_t *info, int permission)
{
    LosProcessCB *spcb = OS_PCB_FROM_PID(pid);//找到这个进程
323
    if (OsProcessIsUnused(spcb)) {//进程是否还在使用,不一定是当前进程但必须是个有效进程
324 325 326 327 328 329
        return -ESRCH;
    }
#ifdef LOSCFG_SECURITY_CAPABILITY	//启用能力安全模式
    LosProcessCB *current = OsCurrProcessGet();//获取当前进程

    /* If the process you want to kill had been inactive, but still exist. should return LOS_OK */
330
    if (OsProcessIsInactive(spcb)) {//不向非活动进程发送信息,但返回OK
331 332 333 334 335 336 337 338 339 340
        return LOS_OK;
    }

    /* Kernel process always has kill permission and user process should check permission *///内核进程总是有kill权限,用户进程需要检查权限
    if (OsProcessIsUserMode(current) && !(current->processStatus & OS_PROCESS_FLAG_EXIT)) {//用户进程检查能力范围
        if ((current != spcb) && (!IsCapPermit(CAP_KILL)) && (current->user->userID != spcb->user->userID)) {
            return -EPERM;
        }
    }
#endif
341
    if ((permission == OS_USER_KILL_PERMISSION) && (OsSignalPermissionToCheck(spcb) < 0)) {
342 343 344 345 346
        return -EPERM;
    }
    return OsSigProcessSend(spcb, info);//给参数进程发送信号
}
/************************************************
347
用于向进程或进程组发送信号
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
shell命令 kill 14 7(kill -14 7效果相同)
发送信号14(SIGALRM默认行为为进程终止)给7号进程
************************************************/
int OsKill(pid_t pid, int sig, int permission)
{
    siginfo_t info;
    int ret;

    /* Make sure that the para is valid */
    if (!GOOD_SIGNO(sig) || pid < 0) {//有效信号 [0,64]
        return -EINVAL;
    }
    if (OsProcessIDUserCheckInvalid(pid)) {//检查参数进程 
        return -ESRCH;
    }

    /* Create the siginfo structure */ //创建信号结构体
    info.si_signo = sig;	//信号编号
    info.si_code = SI_USER;	//来自用户进程信号
    info.si_value.sival_ptr = NULL;

    /* Send the signal */
    ret = OsDispatch(pid, &info, permission);//发送信号
    return ret;
}
373
//给发送信号过程加锁
374 375 376 377 378 379
int OsKillLock(pid_t pid, int sig)
{
    int ret;
    unsigned int intSave;

    SCHEDULER_LOCK(intSave);
380
    ret = OsKill(pid, sig, OS_USER_KILL_PERMISSION);//用户权限向进程发送信号
381 382 383
    SCHEDULER_UNLOCK(intSave);
    return ret;
}
384
//发送信号
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
int OsPthreadKill(UINT32 tid, int signo)
{
    LosTaskCB *stcb = NULL;
    siginfo_t info;

    int ret;
    UINT32 intSave;

    /* Make sure that the signal is valid */
    OS_RETURN_IF(!GOOD_SIGNO(signo), -EINVAL);
    if (OS_TID_CHECK_INVALID(tid)) {
        return -ESRCH;
    }

    /* Create the siginfo structure */
    info.si_signo = signo;	//信号编号 如 SIGKILL
    info.si_code = SI_USER;	//来自用户进程信号
    info.si_value.sival_ptr = NULL;
    /* Keep things stationary through the following */
    SCHEDULER_LOCK(intSave);
    /* Get the TCB associated with the thread */
    stcb = OsGetTaskCB(tid);
    OS_GOTO_EXIT_IF(stcb == NULL, -ESRCH);

    ret = OsUserTaskOperatePermissionsCheck(stcb);//用户态操作权限检查
    OS_GOTO_EXIT_IF(ret != LOS_OK, -ret);

    /* Dispatch the signal to thread, bypassing normal task group thread
     * dispatch rules. */
    ret = OsTcbDispatch(stcb, &info);//将信号发送到线程,将绕过正常的任务组线程调度规则
EXIT:
    SCHEDULER_UNLOCK(intSave);
    return ret;
}
419
//向信号集中加入signo信号
420 421 422 423 424 425 426 427 428
int OsSigAddSet(sigset_t *set, int signo)
{
    /* Verify the signal */
    if (!GOOD_SIGNO(signo)) {
        return -EINVAL;
    } else {
        /* In musl, sig No bits 00000100 present sig No 3, but  1<< 3 = 00001000, so signo needs minus 1 */
        signo -= 1;
        /* Add the signal to the set */
429
        *set |= SIGNO2SET((unsigned int)signo);//填充信号集
430 431 432
        return LOS_OK;
    }
}
433
//获取已发送到进程,却被阻塞的所有信号
434 435 436 437 438 439 440 441 442 443 444
int OsSigPending(sigset_t *set)
{
    LosTaskCB *tcb = NULL;
    unsigned int intSave;

    if (set == NULL) {
        return -EFAULT;
    }

    SCHEDULER_LOCK(intSave);
    tcb = OsCurrTaskGet();
445
    *set = tcb->sig.sigPendFlag;//被阻塞的信号集
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
    SCHEDULER_UNLOCK(intSave);
    return LOS_OK;
}

STATIC int FindFirstSetedBit(UINT64 n)
{
    int count;

    if (n == 0) {
        return -1;
    }
    for (count = 0; (count < UINT64_BIT_SIZE) && (n ^ 1ULL); n >>= 1, count++) {}
    return (count < UINT64_BIT_SIZE) ? count : (-1);
}

int OsSigTimedWaitNoLock(sigset_t *set, siginfo_t *info, unsigned int timeout)
{
    LosTaskCB *task = NULL;
    sig_cb *sigcb = NULL;
    int ret;

    task = OsCurrTaskGet();
    sigcb = &task->sig;

    if (sigcb->waitList.pstNext == NULL) {
        LOS_ListInit(&sigcb->waitList);//初始化信号等待链表
    }
    /* If pendingflag & set > 0, shound clear pending flag */
    sigset_t clear = sigcb->sigPendFlag & *set;
    if (clear) {
        sigcb->sigPendFlag ^= clear;
        ret = FindFirstSetedBit((UINT64)clear) + 1;
    } else {
        OsSigAddSet(set, SIGKILL);//kill 9 14 必须要处理
        OsSigAddSet(set, SIGSTOP);//终止进程的信号也必须处理

        sigcb->sigwaitmask |= *set;//按位加到等待集上,也就是说sigwaitmask的信号来了都是要处理的.
        ret = OsTaskWait(&sigcb->waitList, timeout, TRUE);//将当前任务挂到waitlist上
        if (ret == LOS_ERRNO_TSK_TIMEOUT) {
            ret = -EAGAIN;
        }
        sigcb->sigwaitmask = NULL_SIGNAL_SET;
    }
    if (info != NULL) {
        (void) memcpy_s(info, sizeof(siginfo_t), &sigcb->sigunbinfo, sizeof(siginfo_t));
    }
    return ret;
}
494
//让当前任务等待的信号
495 496 497 498 499 500 501
int OsSigTimedWait(sigset_t *set, siginfo_t *info, unsigned int timeout)
{
    int ret;
    unsigned int intSave;

    SCHEDULER_LOCK(intSave);

502
    ret = OsSigTimedWaitNoLock(set, info, timeout);//以不加锁的方式等待
503 504 505 506

    SCHEDULER_UNLOCK(intSave);
    return ret;
}
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
507
//通过信号挂起当前任务
508 509 510 511 512 513 514 515 516
int OsPause(void)
{
    LosTaskCB *spcb = NULL;
    sigset_t oldSigprocmask;

    spcb = OsCurrTaskGet();
    oldSigprocmask = spcb->sig.sigprocmask;
    return OsSigSuspend(&oldSigprocmask);
}
517
//用参数set代替进程的原有掩码,并暂停进程执行,直到收到信号再恢复原有掩码并继续执行进程。
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
int OsSigSuspend(const sigset_t *set)
{
    unsigned int intSave;
    LosTaskCB *rtcb = NULL;
    unsigned int sigTempProcMask;
    sigset_t setSuspend;
    int ret;

    if (set == NULL) {
        return -EINVAL;
    }
    SCHEDULER_LOCK(intSave);
    rtcb = OsCurrTaskGet();
    sigTempProcMask = rtcb->sig.sigprocmask;

    /* Wait signal calc */
    setSuspend = FULL_SIGNAL_SET & (~(*set));

    /* If pending mask not in sigmask, need set sigflag */
    OsSigMaskSwitch(rtcb, *set);
    ret = OsSigTimedWaitNoLock(&setSuspend, NULL, LOS_WAIT_FOREVER);
    if (ret < 0) {
        PRINT_ERR("FUNC %s LINE = %d, ret = %x\n", __FUNCTION__, __LINE__, ret);
    }
    /* Restore old sigprocmask */
    OsSigMaskSwitch(rtcb, sigTempProcMask);

    SCHEDULER_UNLOCK(intSave);
    return -EINTR;
}
/**************************************************
549
信号安装,函数用于改变进程接收到特定信号后的行为。
550
sig:信号的值,可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)。
551 552
act:设置对signal信号的新处理方式。
oldact:原来对信号的处理方式。
553
如果把第二、第三个参数都设为NULL,那么该函数可用于检查信号的有效性。
554
返回值:0 表示成功,-1 表示有错误发生。
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
**************************************************/
int OsSigAction(int sig, const sigaction_t *act, sigaction_t *oact)
{
    UINTPTR addr;
    sigaction_t action;

    if (!GOOD_SIGNO(sig) || sig < 1 || act == NULL) {
        return -EINVAL;
    }
    if (LOS_ArchCopyFromUser(&action, act, sizeof(sigaction_t)) != LOS_OK) {
        return -EFAULT;
    }

    if (sig == SIGSYS) {//系统调用中参数错,如系统调用号非法 
        addr = OsGetSigHandler();//获取进程信号处理函数
570
        if (addr == 0) {//进程没有信号处理函数时
571 572 573 574 575 576 577 578
            OsSetSigHandler((unsigned long)(UINTPTR)action.sa_handler);//设置进程信号处理函数
            return LOS_OK;
        }
        return -EINVAL;
    }

    return LOS_OK;
}
579 580
/**********************************************
产生系统调用时,也就是软中断时,保存用户栈寄存器现场信息
581
改写PC寄存器的值
582
**********************************************/
583 584 585 586 587 588 589 590 591 592
void OsSaveSignalContext(unsigned int *sp)
{
    UINTPTR sigHandler;
    UINT32 intSave;
    LosTaskCB *task = NULL;
    LosProcessCB *process = NULL;
    sig_cb *sigcb = NULL;
    unsigned long cpsr;

    OS_RETURN_IF_VOID(sp == NULL);
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
593
    cpsr = OS_SYSCALL_GET_CPSR(sp);//获取系统调用时的 CPSR值
594

595
    OS_RETURN_IF_VOID(((cpsr & CPSR_MASK_MODE) != CPSR_USER_MODE));//必须在用户模式下保存
596 597 598
    SCHEDULER_LOCK(intSave);
    task = OsCurrTaskGet();
    process = OsCurrProcessGet();
599
    sigcb = &task->sig;//获取任务的信号控制块
600 601 602
	//1.未保存任务上下文任务
	//2.任何的信号标签集不为空或者进程有信号要处理
    if ((sigcb->context.count == 0) && ((sigcb->sigFlag != 0) || (process->sigShare != 0))) {
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
603
        sigHandler = OsGetSigHandler();//获取信号处理函数
604
        if (sigHandler == 0) {//信号没有注册
605 606 607 608 609 610
            sigcb->sigFlag = 0;
            process->sigShare = 0;
            SCHEDULER_UNLOCK(intSave);
            PRINT_ERR("The signal processing function for the current process pid =%d is NULL!\n", task->processID);
            return;
        }
611
        /* One pthread do the share signal */ 
612
        sigcb->sigFlag |= process->sigShare;//扩展任务的信号标签集
613
        unsigned int signo = (unsigned int)FindFirstSetedBit(sigcb->sigFlag) + 1;
614
        OsProcessExitCodeSignalSet(process, signo);//设置进程退出信号
615
        sigcb->context.CPSR = cpsr;		//保存当前各寄存器的信息
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
616
        sigcb->context.PC = sp[REG_PC]; //获取被打断现场寄存器的值
617 618 619
        sigcb->context.USP = sp[REG_SP];//用户栈顶位置,以便能从内核栈切回用户栈
        sigcb->context.ULR = sp[REG_LR];//用户栈返回地址
        sigcb->context.R0 = sp[REG_R0];	//系统调用的返回值
620 621
        sigcb->context.R1 = sp[REG_R1];
        sigcb->context.R2 = sp[REG_R2];
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
622 623 624 625 626 627
        sigcb->context.R3 = sp[REG_R3]; 
        sigcb->context.R7 = sp[REG_R7];//为何参数不用传R7,是因为系统调用发生时 R7始终保存的是系统调用号.
        sigcb->context.R12 = sp[REG_R12];//详见 https://my.oschina.net/weharmony/blog/4967613
        sp[REG_PC] = sigHandler;//指定信号执行函数,注意此处改变保存任务上下文中PC寄存器的值,恢复上下文时将执行这个函数.
        sp[REG_R0] = signo;		//参数1,信号ID
        sp[REG_R1] = (unsigned int)(UINTPTR)(sigcb->sigunbinfo.si_value.sival_ptr); //参数2
628 629
        /* sig No bits 00000100 present sig No 3, but  1<< 3 = 00001000, so signo needs minus 1 */
        sigcb->sigFlag ^= 1ULL << (signo - 1);
630
        sigcb->context.count++;	//代表已保存
631 632 633 634
    }

    SCHEDULER_UNLOCK(intSave);
}
635
//发生硬中断时,需保存用户态的用户栈现场,多了一个参数 R7寄存器
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
636
//汇编调用 见于 los_dispatch.S |  BL        OsSaveSignalContextIrq
637 638 639 640 641 642 643 644
void OsSaveSignalContextIrq(unsigned int *sp, unsigned int r7)
{
    UINTPTR sigHandler;
    LosTaskCB *task = NULL;
    LosProcessCB *process = NULL;
    sig_cb *sigcb = NULL;
    unsigned long cpsr;
    UINT32 intSave;
645
    TaskIrqContext *context = (TaskIrqContext *)(sp);//汇编设置SP,从SP位置取出TaskIrqContext
646 647 648

    OS_RETURN_IF_VOID(sp == NULL);
    cpsr = context->CPSR;
649
    OS_RETURN_IF_VOID(((cpsr & CPSR_MASK_MODE) != CPSR_USER_MODE));//必须在用户模式下保存用户栈信息
650 651

    SCHEDULER_LOCK(intSave);
652
    task = OsCurrTaskGet();	//获取当前任务
653
    process = OsCurrProcessGet();//必须是需要当前任务
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
654
    sigcb = &task->sig;//获取任务的信号控制块
655 656
    //1.未保存任务上下文任务
	//2.任何的信号标签集不为空或者进程有信号要处理
657
    if ((sigcb->context.count == 0) && ((sigcb->sigFlag != 0) || (process->sigShare != 0))) {
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
658
        sigHandler = OsGetSigHandler();//获取进程的信号处理函数
659
        if (sigHandler == 0) {//没有设置信号处理函数
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
660 661
            sigcb->sigFlag = 0;//进程没有设置信号处理函数,所以任务的信号无意义,标签回0
            process->sigShare = 0;//进程的共享位也无意义,回0
662 663 664 665
            SCHEDULER_UNLOCK(intSave);
            PRINT_ERR("The current process pid =%d starts fail!\n", task->processID);
            return;
        }
666 667 668
        sigcb->sigFlag |= process->sigShare;//扩展任务的信号标签集
        unsigned int signo = (unsigned int)FindFirstSetedBit(sigcb->sigFlag) + 1;//找到第一个被设置的位置,+1是因为信号时从[1-64]的
        OsProcessExitCodeSignalSet(process, signo);//设置进程的退出码的信号为(0 ~ 7)位
鸿蒙内核源码分析's avatar
鸿蒙内核源码分析 已提交
669 670 671 672 673
        (VOID)memcpy_s(&sigcb->context.R0, sizeof(TaskIrqDataSize), &context->R0, sizeof(TaskIrqDataSize));//拷贝中断上下文到任务的信号上下文
        //这里其实类似于 OsSaveSignalContext 中的 sigcb->context.USP = sp[REG_SP] ...
        sigcb->context.R7 = r7;//因为是硬件触发,所以此处不同于 OsSaveSignalContext(unsigned int *sp),需要通过底层将 R7 带过来. MOV R1,R7, BL OsSaveSignalContextIrq
		//同样的改变了栈中PC,R0,R1的值,意味着恢复现场后将执行 sigHandler(R0,R1)
        context->PC = sigHandler;//信号入口函数
674
        context->R0 = signo;	//参数1.信号ID
675
        context->R1 = (UINT32)(UINTPTR)sigcb->sigunbinfo.si_value.sival_ptr;//参数2
676
        /* sig No bits 00000100 present sig No 3, but  1<< 3 = 00001000, so signo needs minus 1 */
677 678
        sigcb->sigFlag ^= 1ULL << (signo - 1);//减1跟上面 + 1 的道理一样. @note_thinking 但为啥要用 ^= 呢?
        sigcb->context.count++;//代表已经保存过信号的上下文了
679 680 681
    }
    SCHEDULER_UNLOCK(intSave);
}
682 683 684 685 686 687 688
/****************************************************
恢复信号上下文,由系统调用之__NR_sigreturn产生,这是一个内部产生的系统调用.
为什么要恢复呢?
因为系统调用的执行由任务内核态完成,使用的栈也是内核栈,CPU相关寄存器记录的都是内核栈的内容,
而系统调用完成后,需返回任务的用户栈执行,这时需将CPU各寄存器回到用户态现场
所以函数的功能就变成了还原寄存器的值
****************************************************/
689 690 691 692 693 694 695 696 697
void OsRestorSignalContext(unsigned int *sp)
{
    LosTaskCB *task = NULL; /* Do not adjust this statement */
    LosProcessCB *process = NULL;
    sig_cb *sigcb = NULL;
    UINT32 intSave;

    SCHEDULER_LOCK(intSave);
    task = OsCurrTaskGet();
698
    sigcb = &task->sig;//获取当前任务信号控制块
699

700
    if (sigcb->context.count != 1) {//必须之前保存过,才能被恢复
701 702 703 704 705
        SCHEDULER_UNLOCK(intSave);
        PRINT_ERR("sig error count : %d\n", sigcb->context.count);
        return;
    }

706 707 708 709 710
    process = OsCurrProcessGet();//获取当前进程
    sp[REG_PC] = sigcb->context.PC;//指令寄存器
    OS_SYSCALL_SET_CPSR(sp, sigcb->context.CPSR);//重置程序状态寄存器
    sp[REG_SP] = sigcb->context.USP;//堆栈指针, USP指的是 用户态的堆栈,即将回到用户栈继续运行
    sp[REG_LR] = sigcb->context.ULR;//连接寄存器
711 712 713 714 715 716
    sp[REG_R0] = sigcb->context.R0;
    sp[REG_R1] = sigcb->context.R1;
    sp[REG_R2] = sigcb->context.R2;
    sp[REG_R3] = sigcb->context.R3;
    sp[REG_R7] = sigcb->context.R7;
    sp[REG_R12] = sigcb->context.R12;
717 718 719
    sigcb->context.count--;	//信号上下文的数量回到减少
    process->sigShare = 0;	//回到用户态,信号共享清0
    OsProcessExitCodeSignalClear(process);//清空进程退出码
720 721 722 723 724 725 726 727
    SCHEDULER_UNLOCK(intSave);
}

#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */