inux内核中的信号机制--信号处理

【INT的内核笔记】Linux信号递达过程详解 1. 什么时候执行信号处理 一般在从中断或系统调用返回到用户态前,会执行一段逻辑检查TIF_SIGPENDING位, 如果被置位了的话则会经由:–> do_notify_resume --> do_signal,进入到do_signal执行信号处理。 中断/系统调用返回的大致情况,可以参考下图: 中断返回用户态的相关代码: /** *返回用户空间,只需要检查need_resched * *可能从中断返回,也可能从系统调用返回。 */ ENTRY(resume_userspace) # 阅读详情

https://blog.youkuaiyun.com/ce123_zhouwei/article/details/8570616

 

Kernel version:2.6.14

CPU architecture:ARM920T

Author:ce123(http://blog.youkuaiyun.com/ce123)

当进程被调度时,会调用do_notify_resume()来处理信号队列中的信号。信号处理主要就是调用sighand_struct结构中对应的信号处理函数。do_notify_resume()(arch/arm/kernel/signal.c)函数的定义如下:


asmlinkage void
do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall)
{
    if (thread_flags & _TIF_SIGPENDING)
        do_signal(&current->blocked, regs, syscall);
}
_TIF_SIGPENDING标志是在signal_wake_up()函数中设置的,检查该标志后,接下来就调用do_signal()函数,我们来看看do_signal()(arch/arm/kernel/signal.c)的具体定义:

/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 */
static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
{
    struct k_sigaction ka;
    siginfo_t info;
    int signr;

    /*
     * We want the common case to go fast, which
     * is why we may in certain cases get here from
     * kernel mode. Just return without doing anything
     * if so.
     */
    if (!user_mode(regs))//regs保存的是进入内核态之前的寄存器现场,必须为用户模式,否则直接返回
        return 0;

    if (try_to_freeze())
        goto no_signal;

    if (current->ptrace & PT_SINGLESTEP)
        ptrace_cancel_bpt(current);//和调试相关,我们在后面的文章中会具体分析

    signr = get_signal_to_deliver(&info, &ka, regs, NULL);//取出等待处理的信号
    if (signr > 0) {
        handle_signal(signr, &ka, &info, oldset, regs, syscall);//处理信号
        if (current->ptrace & PT_SINGLESTEP)
            ptrace_set_bpt(current);
        return 1;
    }

 no_signal:
    /*
     * No signal to deliver to the process - restart the syscall.
     */
    if (syscall) {
        if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) {
            if (thumb_mode(regs)) {
                regs->ARM_r7 = __NR_restart_syscall;
                regs->ARM_pc -= 2;
            } else {
                u32 __user *usp;

                regs->ARM_sp -= 12;
                usp = (u32 __user *)regs->ARM_sp;

                put_user(regs->ARM_pc, &usp[0]);
                /* swi __NR_restart_syscall */
                put_user(0xef000000 | __NR_restart_syscall, &usp[1]);
                /* ldr    pc, [sp], #12 */
                put_user(0xe49df00c, &usp[2]);

                flush_icache_range((unsigned long)usp,
                           (unsigned long)(usp + 3));

                regs->ARM_pc = regs->ARM_sp + 4;
            }
        }
        if (regs->ARM_r0 == -ERESTARTNOHAND ||
            regs->ARM_r0 == -ERESTARTSYS ||
            regs->ARM_r0 == -ERESTARTNOINTR) {
            restart_syscall(regs);
        }
    }
    if (current->ptrace & PT_SINGLESTEP)
        ptrace_set_bpt(current);
    return 0;
}
执行do_signal()函数时,进程一定处于内核空间,通常进程只有通过中断或者系统调用才能进入内核空间,regs保存着系统调用或者中断时的现场。user_mode()根据regs中的cpsr寄存器来判断是中断现场环境还是用户态环境。如果不是用户态环境,就不对信号进行任何处理,直接从do_signal()函数返回。

如果user_mode()函数发现regs的现场是内核态,那就意味着这不是一次系统调用的返回,也不是一次普通的中断返回,而是一次嵌套中断返回(或者在系统调用过程中发生了中断)。此时大概的执行路径应该是这样的:假设进场现在运行在用户态,此时发生一次中断,进场进入内核态(此时user_mode(regs)返回1,意味着中断现场是用户态。),此后在中断返回前,发生了一个更高优先级的中断,于是CPU开始执行高优先级的处理函数(此时user_mode(regs)返回0,意味着中断现场是在内核态)。当高优先级中断处理结束后,在它返回时,是不应该处理信号的,因为信号的优先级比中断的优先级低。在这种情况下,对信号的处理将会延迟到低优先级中断处理结束之后。相对于Windows内核来说,尽管linux内核中没有一组显式的操作函数来实现这一系列的优先级管理方案,但是linux内核和Windows内核都使用了同样的机制,优先级关系为:高优先级中断->低优先级中断->软中断(类似Windows内中的DPC)->信号(类似Windows内核中的APC)->进程运行。

如果user_mode(regs)返回1,接下来会执行(中间略去一下和本文关系不大的代码)get_signal_to_deliver(),这个函数从当前进程的信号队列(保存Private Signal Queue和Shared Signal Queue)取出等待处理的信号(调用dequeue_signal()函数),然后根据信号定位到对应的signal_struct结构,如果信号的处理函数sa_handler为SIG_IGN,就忽略该信号,继续取下一个信号;如果信号的处理函数sa_handler为SIG_DFL,意味着按照信号默认的处理方式对待就可以了(例如直接调用do_coredump()等)。

如果get_signal_to_deliver()函数返回值大于0,说明这个信号的处理函数是在用户态空间(通过signal()和sigaction()等函数设置的自定义信号处理函数。),将调用handle_signal()函数进行处理。handle_signal()函数的定义如下:


/*
 * OK, we're invoking a handler
 */    
static void
handle_signal(unsigned long sig, struct k_sigaction *ka,
          siginfo_t *info, sigset_t *oldset,
          struct pt_regs * regs, int syscall)
{
    struct thread_info *thread = current_thread_info();
    struct task_struct *tsk = current;
    int usig = sig;
    int ret;

    /*
     * If we were from a system call, check for system call restarting...
     */
    if (syscall) {
        switch (regs->ARM_r0) {
        case -ERESTART_RESTARTBLOCK:
        case -ERESTARTNOHAND:
            regs->ARM_r0 = -EINTR;
            break;
        case -ERESTARTSYS:
            if (!(ka->sa.sa_flags & SA_RESTART)) {
                regs->ARM_r0 = -EINTR;
                break;
            }
            /* fallthrough */
        case -ERESTARTNOINTR:
            restart_syscall(regs);
        }
    }

    /*
     * translate the signal
     */
    if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap)
        usig = thread->exec_domain->signal_invmap[usig];

    /*
     * Set up the stack frame//设置栈帧
     */
    if (ka->sa.sa_flags & SA_SIGINFO)
        ret = setup_rt_frame(usig, ka, info, oldset, regs);
    else
        ret = setup_frame(usig, ka, oldset, regs);

    /*
     * Check that the resulting registers are actually sane.
     */
    ret |= !valid_user_regs(regs);

    /*
     * Block the signal if we were unsuccessful.
     */
    if (ret != 0) {
        spin_lock_irq(&tsk->sighand->siglock);
        sigorsets(&tsk->blocked, &tsk->blocked,
              &ka->sa.sa_mask);
        if (!(ka->sa.sa_flags & SA_NODEFER))
            sigaddset(&tsk->blocked, sig);
        recalc_sigpending();
        spin_unlock_irq(&tsk->sighand->siglock);
    }

    if (ret == 0)
        return;

    force_sigsegv(sig, tsk);
}
在这样情况下,进程当前处于内核态,而信号处理函数却处于用户态,为此必须在进程的用户态构造一个临时的堆栈环境(因为进程的信号处理函数在进行函数调用以及使用局部变量时需要使用堆栈。),然后进入用户态执行信号处理函数,最后再返回内核态继续执行。在这个过程中,有以下几个问题需要解决:
1.临时的用户态堆栈在哪里呢?这个很好解决,因为可以直接使用进程现有的用户态堆栈,这里要保证的是:使用结束后这个堆栈必须和使用前是一模一样的。

2.临时堆栈解决后,需要确定的是通过什么方法来保证返回到用户态后,进程执行的是信号的处理函数。我们知道在进入内核态时,内核态堆栈中保存了一个中断现场,也就是一个pt_regs结构,中断返回地址就保存在pt_regts中的pc中,因此我们这里只要把当前进程的pt_regs中pc设置为sa_handler,然后返回到用户态就开始从sa_handler处开始执行了。


unsigned long handler = (unsigned long)ka->sa.sa_handler;
regs->ARM_pc = handler;
3.当信号的用户态处理函数执行结束时,需要再次进入内核态,还原用户态堆栈,并且修改pt_regs中的pc,保证将来能够按照正常的方式返回用户态。我们知道进程要主动进入内核态只有通过系统调用,出发异常等方法,为此内核专门提供了一个系统调用sys_sigreturn()(还有一个sys_rt_sigreturn()),但是如何调用sys_sigreturn()呢?强制安装信号处理函数最后必须调用一个sigreturn()不是一个好办法,因为不了解内核的程序员会对这个限制感到不解,为此程序员常常忘记在它们的信号处理函数的末尾调用sigreturn(),如果真是这样,arm-linux-gcc也检测不出这个错误。为此,内核修改regs的ARM_lr值,:


regs->ARM_lr = retcode;
当用户态信号处理函数运行结束时,会从lr取出返回地址,因此内核在构建临时regs时,会把上面这段代码的入口地址保存在lr,这样当信号处理完成后,就会顺利的通过系统调用sys_sigreturn()进入内核。

4.当通过构造的sys_sigreturn()返回到内核态之后,内核需要顺利的返回到用户态执行原来的代码(信号处理前应该返回的用户空间状态),但是此时进入内核空间的pt_regs上下文是通过sys_sigreturn()构造的,而最初的内核堆栈中的pt_regs上下文在第一次返回用户空间执行信号处理函数时,就已经被“销毁”了(内核态堆栈的pt_regs上下文在中断返回后就不复存在了)。而现在必须通过最初的pt_regs上下文返回用户态,为此,在构建临时堆栈环境时,内核会把最初的pt_regs上下文备份到临时堆栈中(位于用户态堆栈),当通过系统调用sys_sigreturn()再次进入内核时,内核从用户态空间还原出原始的pt_regs。最后正常返回。

通过上面的讨论,我们知道在这个迂回的处理过程中,关键在于用户态的临时堆栈环境的建立,这是一个sigframe结构:


/*
 * Do a signal return; undo the signal stack.  These are aligned to 64-bit.
 */
struct sigframe {
    struct sigcontext sc;//保存一组寄存器上下文
    unsigned long extramask[_NSIG_WORDS-1];
    unsigned long retcode;//保存返回地址
    struct aux_sigframe aux __attribute__((aligned(8)));
};

struct rt_sigframe {
    struct siginfo __user *pinfo;
    void __user *puc;
    struct siginfo info;
    struct ucontext uc;
    unsigned long retcode;
    struct aux_sigframe aux __attribute__((aligned(8)));
};
其中的sigcontext的作用类似于pt_regs用于保存相关寄存器上下文,原始的pt_regs的相关信息就备份在这里。而整个sigframe结构是通过get_sigframe()函数在进程用户态空间分配的,get_sigframe()定义如下:

static inline void __user *
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize)
{
    unsigned long sp = regs->ARM_sp;
    void __user *frame;

    /*
     * This is the X/Open sanctioned signal stack switching.
     */
    if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
        sp = current->sas_ss_sp + current->sas_ss_size;

    /*
     * ATPCS B01 mandates 8-byte alignment
     */
    frame = (void __user *)((sp - framesize) & ~7);

    /*
     * Check that we can actually write to the signal frame.
     */
    if (!access_ok(VERIFY_WRITE, frame, framesize))
        frame = NULL;

    return frame;
}
get_sigframe()通过用户态空间堆栈的sp-sizeof(struct sigframe)在用户态堆栈的顶部分配了一篇存储空间,将来使用完成后,再通过sp+sizeof(struct sigframe)还原。
通过上面的讨论,我们再回到do_signal()中来,如果有用户态的信号处理函数,do_signal()会调用handle_signal(),handle_signal()将调用setup_frame()或者setup_rt_frame()来完成实际的工作,这里我们以setup_frame()为例进行进一步讨论。

static int
setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs)
{
    //在用户态堆栈上分配一个sigframe结构
    struct sigframe __user *frame = get_sigframe(ka, regs, sizeof(*frame));
    int err = 0;

    if (!frame)
        return 1;

    //把相关信息从内核态备份到用户态堆栈的sigframe结构中
    err |= setup_sigcontext(&frame->sc, &frame->aux, regs, set->sig[0]);

    if (_NSIG_WORDS > 1) {
        err |= __copy_to_user(frame->extramask, &set->sig[1],
                      sizeof(frame->extramask));
    }

    if (err == 0)
        err = setup_return(regs, ka, &frame->retcode, frame, usig);

    return err;
}
setup_return()设置返回地址,其定义如下:
static int
setup_return(struct pt_regs *regs, struct k_sigaction *ka,
         unsigned long __user *rc, void __user *frame, int usig)
{
    unsigned long handler = (unsigned long)ka->sa.sa_handler;
    unsigned long retcode;
    int thumb = 0;
    unsigned long cpsr = regs->ARM_cpsr & ~PSR_f;

    /*
     * Maybe we need to deliver a 32-bit signal to a 26-bit task.
     */
    if (ka->sa.sa_flags & SA_THIRTYTWO)
        cpsr = (cpsr & ~MODE_MASK) | USR_MODE;

#ifdef CONFIG_ARM_THUMB
    if (elf_hwcap & HWCAP_THUMB) {
        /*
         * The LSB of the handler determines if we're going to
         * be using THUMB or ARM mode for this signal handler.
         */
        thumb = handler & 1;

        if (thumb)
            cpsr |= PSR_T_BIT;
        else
            cpsr &= ~PSR_T_BIT;
    }
#endif
<span>    </span>//这里的retcode就是保存手工构造的sigreturn()代码
    if (ka->sa.sa_flags & SA_RESTORER) {
        retcode = (unsigned long)ka->sa.sa_restorer;
    } else {
        unsigned int idx = thumb;

        if (ka->sa.sa_flags & SA_SIGINFO)
            idx += 2;

        if (__put_user(sigreturn_codes[idx], rc))
            return 1;

        if (cpsr & MODE32_BIT) {
            /*
             * 32-bit code can use the new high-page
             * signal return code support.
             */
            retcode = KERN_SIGRETURN_CODE + (idx << 2) + thumb;
        } else {
            /*
             * Ensure that the instruction cache sees
             * the return code written onto the stack.
             */
            flush_icache_range((unsigned long)rc,
                       (unsigned long)(rc + 1));

            retcode = ((unsigned long)rc) + thumb;
        }
    }

    regs->ARM_r0 = usig;
    regs->ARM_sp = (unsigned long)frame;//堆栈
    regs->ARM_lr = retcode;//返回地址,当用户态信号处理函数结束时,就会把这个地址作为返回地址
    regs->ARM_pc = handler;//信号处理函数
    regs->ARM_cpsr = cpsr;

    return 0;
}
当setup_frame()返回后,一切准备就绪,因此可以从内核态返回了,这样就顺利过渡到用户态的信号处理函数。当这个函数处理结束后,会通过retcode再次进入内核态,现在我们看看retcode是如何处理的,下面的代码选自glibc(2.3.2):


 #include <sysdep.h>

/* If no SA_RESTORER function was specified by the application we use
   one of these.  This avoids the need for the kernel to synthesise a return
   instruction on the stack, which would involve expensive cache flushes. */

ENTRY(__default_sa_restorer)
    swi    SYS_ify(sigreturn)

#ifdef __NR_rt_sigreturn

ENTRY(__default_rt_sa_restorer)
    swi    SYS_ify(rt_sigreturn)

#define SYS_ify(syscall_name)    (__NR_##syscall_name)
下面具体看看sys_sigreturn()的定义:

asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
    struct sigframe __user *frame;
    sigset_t set;

    /* Always make any pending restarted system calls return -EINTR */
    current_thread_info()->restart_block.fn = do_no_restart_syscall;

    /*
     * Since we stacked the signal on a 64-bit boundary,
     * then 'sp' should be word aligned here.  If it's
     * not, then the user is trying to mess with us.
     */
    if (regs->ARM_sp & 7)
        goto badframe;

    frame = (struct sigframe __user *)regs->ARM_sp;

    if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
        goto badframe;
    if (__get_user(set.sig[0], &frame->sc.oldmask)
        || (_NSIG_WORDS > 1
            && __copy_from_user(&set.sig[1], &frame->extramask,
                    sizeof(frame->extramask))))
        goto badframe;

    sigdelsetmask(&set, ~_BLOCKABLE);
    spin_lock_irq(&current->sighand->siglock);
    current->blocked = set;
    recalc_sigpending();
    spin_unlock_irq(&currentt->sighand->siglock);

    if (restore_sigcontext(regs, &frame->sc, &frame->aux))
        goto badframe;

    /* Send SIGTRAP if we're single-stepping */
    if (current->ptrace & PT_SINGLESTEP) {
        ptrace_cancel_bpt(current);
        send_sig(SIGTRAP, current, 1);
    }

    return regs->ARM_r0;

badframe:
    force_sig(SIGSEGV, current);
    return 0;
}
这个函数主要调用restore_sigcontext()根据用户态态堆栈上的sigframe备份还原pt_regs。
static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
           struct aux_sigframe __user *aux)
{
    int err = 0;

    __get_user_error(regs->ARM_r0, &sc->arm_r0, err);
    __get_user_error(regs->ARM_r1, &sc->arm_r1, err);
    __get_user_error(regs->ARM_r2, &sc->arm_r2, err);
    __get_user_error(regs->ARM_r3, &sc->arm_r3, err);
    __get_user_error(regs->ARM_r4, &sc->arm_r4, err);
    __get_user_error(regs->ARM_r5, &sc->arm_r5, err);
    __get_user_error(regs->ARM_r6, &sc->arm_r6, err);
    __get_user_error(regs->ARM_r7, &sc->arm_r7, err);
    __get_user_error(regs->ARM_r8, &sc->arm_r8, err);
    __get_user_error(regs->ARM_r9, &sc->arm_r9, err);
    __get_user_error(regs->ARM_r10, &sc->arm_r10, err);
    __get_user_error(regs->ARM_fp, &sc->arm_fp, err);
    __get_user_error(regs->ARM_ip, &sc->arm_ip, err);
    __get_user_error(regs->ARM_sp, &sc->arm_sp, err);
    __get_user_error(regs->ARM_lr, &sc->arm_lr, err);
    __get_user_error(regs->ARM_pc, &sc->arm_pc, err);
    __get_user_error(regs->ARM_cpsr, &sc->arm_cpsr, err);

    err |= !valid_user_regs(regs);

#ifdef CONFIG_IWMMXT
    if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
        err |= restore_iwmmxt_context(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
//    if (err == 0)
//        err |= vfp_restore_state(&aux->vfp);
#endif

    return err;
}
restore_sigcontext()很简单,当它返回后,通过sys_sigreturn()在内核态堆栈建立的pt_regs已经变为调用信号处理函数之前的pt_regs。这样,sys_sigreturn()返回用户态时,就顺利地过渡到处理之前的状态了。
--------------------- 
作者:ce123 
来源:优快云 
原文:https://blog.youkuaiyun.com/ce123_zhouwei/article/details/8570616 
版权声明:本文为博主原创文章,转载请附上博文链接!

Linux调度-调度时机和调度条件 struct thread_info { unsigned long flags; /* low level flags */ int preempt_count; /* 0 => preemptable, <0 => bug */ }; 作为一个正经的程序,它不可能从一开始运行就需要一直占用CPU直到地球毁灭,可能某些时候需要等待一些资源无... 阅读详情

相关推荐

inux驱动设计中,异步通知是一种高效的进程间通信机制

linux驱动设计中,异步通知是一种高效的进程间通信机制

a_zxswer的博客 245

linux内核中断返回调度标志是如何设置的

系统调用是常见一种类型的异常,也是应用代码从用户空间主动进入内核空间的唯一方式。 运行在用户空间的进程会被动陷入到内核空间,进行中断处理程序的处理。 中断处理程序处理完后返回到用户空间,在返回至用户空间之前,判断是否要进行进程调度。 如果需要则再进行一次进程调度。 futex_wake_op与fork一样最终执行check_preempt_curr函数。 该函数做的就是给当前线程设置一个需要调度的标志,在下一次中断返回时进行一次调度。 ...

focus on security 1439

Linux内核中的信号机制??信号处理

当进程被调度时,会调用do_notify_resume()来处理信号队列中的信号。信号处理主要是调用sighand_struct结构中对应的信号处理函数。do_notify_resume()(arch/arm/kernel/signal.c)函数的定义如下: asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) {  if (thread_flags & _TIF_SIGPENDING)   do_signal(&current->blocked,

Linux系统编程——进程间的通信(五)信号

对于 Linux来说,实际信号是软中断,许多重要的程序都需要处理信号。信号为 Linux 提供了一种处理异步事件的方法。比如,终端用户输入了 ctrl+c 来中断程序,会通过信号机制停止一个程序 。 信号概述 ...

学习记录,交流学习 956

Windows 10/11一键搞定HDF5文件查看:HDFView 3.4.1免配置安装指南(附中文路径避坑技巧)

本文详细介绍了HDFView 3.4.1在Windows 10/11上的免配置安装方法及中文路径优化技巧。作为HDF5文件查看的专业工具,HDFView 3.4.1简化了安装流程,提升了科研数据处理效率,特别适合遥感、气象等领域的研究人员使用。

qsc9012345的博客 1143

多视图学习 (Multi-View Learning)

多视角/多视图学习(Multi-view learning)是陶大成提出的一个研究方向。我们都知道,在机器学习中样本可以用不同的特征(如图片可以用LBP、SIFT等特征)来表示,或者从不同的角度进行观察(如从前后左右观察一个对象),甚至是采用不同的传感器来观测(如RGB摄像头,Depth摄像头),这些不同的观测手段、角度或特征在多视角学习中称为“视角”。多视角学习通过对不同的视角进行统一分析和研究,希望能够得到更好的分类或聚类等等的效果。

CarpeDiem 3万+

linux内核学习-信号-信号及信号处理

信号是一种软件终端,它提供一种处理异步事件的方法,也是进程同步的唯一方法。根据POSIX标准扩展的信号机制,不仅可以通知事件,还能传递数据。 信号来源: 1.硬件方式 用户按了某些键,如ctrl+c,产生一个SIGINT信号 硬件异常产生信号:除数为0,无效存储访问, 2.软件方式 kill命令 sigqueue函数 某些软件发送的,如定时器 查看信号种类 使用明星kill -l查看系统支...

zhu378287521的博客 307

SpringDoc 基本使用指南

SpringDoc 凭借零配置启动注解简洁和深度兼容 Spring 生态的优势,已成为 Spring Boot API 文档的首选工具。自动化- 减少手动维护文档的成本;标准化- 严格遵循 OpenAPI 3 规范;可扩展- 分组、安全控制灵活适配复杂项目。访问即可查看交互式文档(默认路径)

墨鸦的博客 1万+

Linux可替换信号栈,linux信号机制 - 用户堆栈和内核堆栈的变化【转】

1. 一个信号小例子hex@Gentoo~/signal $ cat sigint.c#include#include#includevoid sig_int(intsigno){printf("hello");}intmain(){if(signal(SIGINT, sig_int) ==SIG_ERR){printf("can't catch SIGINT");exit(-1);}for(;;...

weixin_31031155的博客 152

【近源攻击】badusb制作

BadUSB是利用伪造HID设备执行攻击载荷的一种攻击方式。HID(Human InterfaceDevice)设备通常指的就是键盘鼠标等与人交互的设备,用户插入BadUSB,就会自动执行预置在固件中的恶意代码。BadUsb插入后,会模拟键盘鼠标对电脑进行操作,通过这些操作打开电脑的命令终端,并执行一条命令,这条命令将从指定网址下载其他代码并于后台静默运行。这些代码功能包括:窃取信息、反弹shell、发送邮件等,从而实现控制目标机或者窃取信息的目的。

qinjilll的博客 2548

Kali Linux实战:Aircrack-ng破解Wi-Fi密码的完整流程与常见问题解决

本文详细介绍了在Kali Linux中使用Aircrack-ng套件进行Wi-Fi密码破解的完整流程,包括环境准备、无线网卡配置、网络扫描、握手包捕获与字典破解等关键步骤。同时针对无线网卡不支持监听模式、无法捕获握手包等常见问题提供了实用解决方案,帮助安全研究人员有效评估无线网络安全性。

weixin_29323049的博客 296

【Linux进程信号】

万字详解Linux进程信号

langk_的博客 412

【AI黑话日日新】什么是算力调度?

算力调度 = 在有限资源下,把任务智能分配到最合适的计算节点,实现效率、成本、稳定性最优。更完整的定义:算力调度是对 CPU、GPU、内存、网络、存储等异构资源进行统一抽象、感知、决策、分配、监控与自愈的全生命周期管理,是分布式系统的“智能管家”。算力调度不是玄学,它是资源管理 + 算法 + 工程实践的结合。先懂概念 → 再玩工具 → 再写策略 → 再优化算法从单机到集群,从CPU到GPU,从离线到在线,循序渐进未来AI与算力网络时代,算力调度是性价比最高、最稀缺、最长期吃香的技术方向之一。

专注:太空算力、AI infra、异构调度、大模型成本工程 266

inux内核之进程管理详解

转载:https://blog.youkuaiyun.com/heliangbin87/article/details/774419081、进程描述符(1)进程与线程         进程是处于执行期的程序以及相关资源的总称。线程在linux上称为轻量级进程,没有独立的地址空间,一个进程下的所有线程共享地址空间、文件系统资源、文件描述符、信号处理程序等。 (2)进程描述符task_struct        ...

wangyunqian6的专栏 561

Vue3 - Vite运行打包时Uncaught ReferenceError: process is not defined(解决vue3+vite报错process is not defined)

vue3,vite,vue3+vite报错,process,UncaughtReferenceError:processisnotdefined,浏览器控制台报错processisnotdefined解决方法,vue3如何解决报错,vite报错怎么办,前端打包UncaughtReferenceError:processisnotdefined,npmrunbuild打包报错,vite打包时出现错误,vue3打包运行找不到process,热更新会报错UncaughtRefer

🏆 前端领域优质创作者 7737

超临界二氧化碳发电技术深度解析

超临界二氧化碳发电技术正在突破传统热电转换的物理边界。作为新一代发

硬核科技 602

inux进程间通信的几种机制的比较及适用场合

# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。 # 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。 # 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共

julia_91的博客 314

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

linux下 signal信号机制的透彻分析与各种实例讲解 2

转载:http://blog.youkuaiyun.com/u012183924/article/details/53888972 第二部分: 信号的生命周期与处理过程分析   1. 信号的生命周期 信号产生->信号注册->信号在进程中注销->信号处理函数执行完毕 (1)信号的产生是指触发信号的事件的发生 (2)信号注册 指的是在目标进程中注册,该目标进程中有未决

yingge的专栏 617

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Linux信号透彻分析与理解

本文将从以下几个方面来阐述信号: (1)信号的基本知识 (2)信号生命周期与处理过程分析 (3) 基本的信号处理函数 (4) 保护临界区不被中断 (5) 信号的继承与执行 (6)实时信号中锁的研究 第一部分: 信号的基本知识 1.信号本质: 信号的本质是软件层次上对中断的一种模拟。它是一种异步通信的处理机制,事实上,进程并不知道信号何时到来。 2.信号来源 (1)...

jiangph1001的博客 582

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

*inux进程间通信总结(全)

IPC进程间通信(Inter-Process Communication)就是指多个进程之间相互通信,交换信息的方法。Linux IPC基本上都是从Unix平台上继承而来的。主要包括最初的Unix IPC,System V IPC以及基于Socket的IPC。另外,Linux也支持POSIX IPC。 System V,BSD,POSIX     System V是Unix操作系统最早的商业发

技术烂人 871

linux 信号详解

信号机制是进程之间相互传递消息的一种方法,信号全称为软中断信号,也有人称作软中断。从它的命名可以看出,它的实质和使用很象中断。所以,信号可以说是进程控制的一部分。  一、信号的基本概念  1、基本概念  软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个

程序猿老樊的博客 1240

Linux---进程信号的产生和处理

什么是信号 用户输入命令,在Shell下启动一个前台进程。 用户按下Ctrl-C,这个键盘输入产生一个硬件中断。 如果CPU当前正在执行这个进程的代码,则该进程的用户空间代码暂停执⾏行,CPU从用户态 切换到内 核态处理硬件中断。 终端驱动程序将Ctrl-C解释成一个SIGINT信号,记在该进程的PCB中(也可以说发送了一 个SIGINT 信号给该进程)。 当某个时刻要从内核返回到该进...

江城的博客 943

Linux_进程信号

1、信号基础 技术应用角度的信号 用户在Shell下输入命令启动一个前台进程 用户按下ctrl+c,此时键盘输入产生一个硬件中断,被操作系统获取并解释成信号,发送给目标前台进程 前台进程接收到信号后,进程执行退出 #include<iostream> #include<unistd.h> using namespace std; int main() { whil...

lhn的博客 283

Linux中的mysleep函数

第一个版本: 1、 main函数调用mysleep函数,后者调用sigaction注册了SIGALRM信号的处理函数handler。 2、调用alarm(timeout)设定闹钟。 3、调用pause等待,内核切换到别的进程运行。 4、timeout秒之后,闹钟超时,内核发SIGALRM给这个进程。 5、从内核态返回这个进程的用户态之前处理未决信号,发现有SIGALRM信号,其处理函数是h

scmuzi18的博客 1011

Linux-MySleep函数实现与竟态条件

(一) 函数实现的整体框架 1>需要用到的函数接口 2>实现的整体过程思路 3>程序运行遇到可能情况的分析 4>优化结果与解决方案 (二)三个主要的函数接口 根据系统内部的sleep函数为基础,通过了解其运行过程,可以使用alarm()函数,pause()函数以及sigaction()函数进行实现。 函数参数及返回值Markdown Extra 表格语法: 函数名称 参数 返回值

cvhbfgh的博客 501
上一篇: 一个无锁消息队列引发的血案(一)——地:起因
下一篇: workqueue --最清晰的讲解
往事已遥远
博客等级 码龄19年 50粉丝 14原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值