signal.c

770阅读 0评论2009-08-04 jhluroom
分类:LINUX

/*
 * linux/kernel/signal.c
 *
 * (C) 1991 Linus Torvalds
 */


#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/segment.h>

#include <signal.h>

volatile void do_exit(int error_code);//volatile,告诉GCC编译器本函数不会返回


int sys_sgetmask()//取本进程任务信号屏蔽位

{
    return current->blocked;
}

int sys_ssetmask(int newmask)//设置本进程任务信号屏蔽位

{
    int old=current->blocked;

    current->blocked = newmask & ~(1<<(SIGKILL-1));//SIGKILL信号不可屏蔽

    return old;
}

static inline void save_old(char * from,char * to)//COPY sigaction 数据到FS段的TO处,从内核空间COPY到用户空间

{
    int i;

    verify_area(to, sizeof(struct sigaction));//验证目的地址的空间是否足够大

    for (i=0 ; i< sizeof(struct sigaction) ; i++) {
        put_fs_byte(*from,to);//COPY

        from++;
        to++;
    }
}

static inline void get_new(char * from,char * to)//COPY sigaction 数据从FS段FROM地址到TO处,从用户空间到内核空间

{
    int i;

    for (i=0 ; i< sizeof(struct sigaction) ; i++)
        *(to++) = get_fs_byte(from++);//COPY

}

int sys_signal(int signum, long handler, long restorer)//为指定信号安装处理函数,signum为信号,handler为处理函数,restorer为恢复指针由LIBC库提供

{
    struct sigaction tmp;

    if (signum<1 || signum>32 || signum==SIGKILL)//最大为32个信号 ,不可为SIGKILL SIGSTOP这两个信号 不可为进程捕获

        return -1;
    tmp.sa_handler = (void (*)(int)) handler;
    tmp.sa_mask = 0;
    tmp.sa_flags = SA_ONESHOT | SA_NOMASK;////SA_NOCLDSTOP,SA_NOMASK,SA_ONESHOT

    tmp.sa_restorer = (void (*)(void)) restorer;
    handler = (long) current->sigaction[signum-1].sa_handler;//保存当前任务以前此信号处理函数

    current->sigaction[signum-1] = tmp;//定义当前任务此信号 的处理函数

    return handler;
}

int sys_sigaction(int signum, const struct sigaction * action,
    struct sigaction * oldaction)//修改进程在收到一个信号 时的操作,相关操作同前

{
    struct sigaction tmp;

    if (signum<1 || signum>32 || signum==SIGKILL)
        return -1;
    tmp = current->sigaction[signum-1];
    get_new((char *) action,
        (char *) (signum-1+current->sigaction));//COPY sigaction 数据从FS段FROM地址到TO处,从用户空间到内核空间

    if (oldaction)
        save_old((char *) &tmp,(char *) oldaction);//COPY sigaction 数据从FS段FROM地址到TO处,从用户空间到内核空间

    if (current->sigaction[signum-1].sa_flags & SA_NOMASK)//允许信号在自己的信号句柄中收到

        current->sigaction[signum-1].sa_mask = 0;
    else
        current->sigaction[signum-1].sa_mask |= (1<<(signum-1));
    return 0;
}

void do_signal(long signr,long eax, long ebx, long ecx, long edx,
    long fs, long es, long ds,
    long eip, long cs, long eflags,
    unsigned long * esp, long ss)//内核系统调用 (int 0X80)中断处理程序中对信号的预处理程序,由/kernel/system_call.s line 119行调用,本函数主要作用为:将信号处理函数放入用户椎栈,本函数调用返回时可保证立即执行信号处理函数,然后继续执行用用户的程序

{
    unsigned long sa_handler;
    long old_eip=eip;
    struct sigaction * sa = current->sigaction + signr - 1;//current->sigaction[signr-1]

    int longs;
    unsigned long * tmp_esp;

    sa_handler = (unsigned long) sa->sa_handler;//取得句柄,0为SIG_DFL, 1为SIG_IGN, 其他为用户定义的信号处理函数

    if (sa_handler==1)//如果为SIG_IGN,则忽落返回

        return;
    if (!sa_handler) {
        if (signr==SIGCHLD)//如果为SIGCHLD则也返回

            return;
        else//其他的则退出返回

            do_exit(1<<(signr-1));//可作为wait() waitpid() 函数的 状态信息,/include/sys/wait.h

    }
    if (sa->sa_flags & SA_ONESHOT)
        sa->sa_handler = NULL;
    *(&eip) = sa_handler;
    longs = (sa->sa_flags & SA_NOMASK)?7:8;
    *(&esp) -= longs;
    verify_area(esp,longs*4);
    tmp_esp=esp;
    put_fs_long((long) sa->sa_restorer,tmp_esp++);
    put_fs_long(signr,tmp_esp++);
    if (!(sa->sa_flags & SA_NOMASK))
        put_fs_long(current->blocked,tmp_esp++);
    put_fs_long(eax,tmp_esp++);
    put_fs_long(ecx,tmp_esp++);
    put_fs_long(edx,tmp_esp++);
    put_fs_long(eflags,tmp_esp++);
    put_fs_long(old_eip,tmp_esp++);
    current->blocked |= sa->sa_mask;//进程信号屏蔽码

}

上一篇:sched.c
下一篇:exit.c