深入理解Linux内核--信号

2023-05-16

信号用于在用户态进程间通信。内核也用信号通知进程系统所发生的事情。

1、信号的作用

信号(signal)是很短的消息,可以被发送到一个进程或一组进程。发送给进程的唯一信息通常是一个数,以此来标识信号。

使用信号的两个主要目的:

让进程知道已经发生了一个特定的事件。

强迫进程执行它自己 代码 中的信号处理 程序

当然,这两个目的不是互斥的,因为进程经常通过执行一个特定的例程来对某一事件作出反应。

常规信号:前31个

实时信号:32-64

实时信号与常规信号有很大的不同,因为它们必须排队以便发送的多个信号能被接收到。另一方面,同种类型的常规信号并不排队;如果一个常规信号被连续发送多次,那么,只有其中的一个发送到接收进程。尽管Linux内核并不使用实时信号,它还是通过几个特定的系统调用完全实现了POSIX标准。

许多系统调用允许程序员发送信号,并决定他们的进程如何响应所接收的信号。

信号的一个重要特点是它们可以随时被发送给状态经常不可预知的进程。发送给非运行进程的信号必须由内核保存,直到进程恢复执行。

阻塞一个信号要求信号的传递拖延,直到随后解除阻塞,这使得信号产生一段时间之后才能对其传递这一问题变得更加严重。

内核区分信号传递的两个不同阶段:

信号产生:

内核更新目标进程的数据结构以表示一个新信号已被发送。

信号传递:

内核强迫目标进程通过以下方式对信号做出反应:或改变目标进程的执行状态,或开始执行一个特定的信号处理程序,或两者都是。

每个所产生的信号至多被传递一次。信号是可消费资源:一旦它们已传递出去,进程描述符中有关这个信号的所有信息都被取消。

已经产生但还没有传递的信号称为挂起信号(pendingsignal)。任何时候,一个进程仅存在给定类型的一个挂起信号,同一进程同种类型的其他信号不被排队,只被简单地丢弃。但是,实时信号是不同的:同种类型的挂起信号可以有好几个。

信号可以保留不可预知的挂起时间,必须考虑的因素:

信号通常只被当前正运行的进程传递

给定类型的信号可以由进程选择性地阻塞

当进程执行一个信号处理程序的函数时,通常“屏蔽”相应的信号,即自动阻塞这个信号到处理程序结束。因此,所处理的信号的另一次出现不能中断信号处理程序,所以,信号处理函数不必是可重入的。

内核实现:

记住每个进程阻塞哪些信号

当从内核态切换到用户态时,对任何一个进程都要检查是否有一个信号已到达。这几乎在每个定时中断时都发生

确定是否可以忽略信号。这个发生在下列所有的条件都满足时:

目标进程没有被另一个进程跟踪

信号没有被目标进程阻塞

信号被目标进程忽略

处理这样的信号,即信号可能在进程运行期间的任一时刻请求把进程切换到一个信号处理函数,并在这个函数返回以后恢复原来执行的上下文。 

[1]传递信号之前所执行的操作

进程以三种方式对一个信号做出应答:

(1)显示地忽略信号

(2)执行与信号相关的缺省操作。由内核预定义的缺省操作取决于信号的类型,下列类型:

Terminate:进程被终止(杀死)

Dump:进程被终止(杀死)

Ignore:信号被忽略

Stop:进程被停止,即把进程置为TASK_STOPPED状态

Continue:如果进程被停止,就把它置为TASK_RUNNING状态

(3)通过调用相应的信号处理函数捕获信号

注意,被对一个信号的阻塞和忽略是不同的:只要信号被阻塞,它就不被传递;只有在信号解除阻塞后才传递它。而一个被忽略的信号总是被传递,只是没有进一步的操作。

SIGKILL和SIGSTOP信号不可以被显示地忽略、捕获或阻塞,因此,通常必须执行它们的缺省操作。因此,SIGKILL和SIGSTOP允许具有适当特权的用户分别终止并停止任何进程,不管进程执行时采取怎样的防御措施。

如果信号的传递会引起内核杀死一个进程,难么这个信号对该进程就是致命的。SIGKILL信号总是致命的;而且,缺省操作为Terminate的每个信号,以及不被进程捕获的信号对该进程也是致命的。注意,如果一个被进程所捕获的信号,其对应的信号处理函数终止了这个进程,那么这个信号就不是致命的,因为进程自己选择了终止,而不是被内核杀死。

[2]POSIX信号和多线程应用


POSIX1003.1标准对多线程应用的信号处理有一些严格的要求:

信号处理程序必须在多线程应用的所有线程之间共享;不过,每个线程必须有自己的挂起信号掩码和阻塞信号掩码。

POSIX库函数kill()和sigqueue()必须向所有的多线程应用而不是某个特殊的线程发送信号。所有由内核产生的信号同样如此。

每个发送给多线程应用的信号仅传送给一个线程,这个线程是由内核在从不会阻塞该信号的线程中随意选择出来的

如果向多线程应用发送了一个致命的信号,那么内核将杀死该应用的所有线程,而不仅仅是杀死接收信号的那个线程。

Linux内核2.6把多线程应用实现为一组属于同一个线程组的轻量级进程。

如果一个挂起信号被发送给了某个特定进程,那么这个信号是私有的;如果被发送给了整个线程组,它就是共享的

[3]与信号相关的数据结构

对系统中的每个进程来说,内核必须跟踪什么信号当前正在挂起或被屏蔽,以及每个线程组是如何处理所有信号的。为了完成这些操作,内核使用几个处理器描述符可存取的数据结构:参考图11-1***

深入理解Linux内核--信号(阅读笔记)(原创)

(1)信号描述符和信号处理程序描述符

进程描述符signal字段指向信号描述符(signaldescriptor)--一个signal_struct类型的结构,用来跟踪共享挂起信号。

除了信号描述符以外,每个进程还引用一个信号处理程序描述符(signal handler deseriplor),它是一个sighand_struct类型的结构,用来描述每个信号必须怎样被线程组处理

(2)sigaction数据结构

一些体系结构把特性赋给仅对内核可见的信号。因此,信号的特性存放在k_sigaction结构中,k_sigaciton结构既包含对用户态进程所隐藏的特性,也包含大家熟悉的sigaction结构,该结构保存了用户态进程能看见的所有特性。实际上,在80x86平台上,信号的所有特性对用户态的进程都是可见的。因此,k_sigaction结构只不过简化为类型为sigaction的单个sa结构。字段:

sa_handler:指定要执行操作的类型。它的值可以是指向信号处理程序的一个指针,SIG_DFL(即值0,指定执行缺省操作),或者SIG_IGN(即值1,指定忽略信号)

sa_flags:是一个标志集,指定必须怎样处理信号。

sa_mask:类型为sigset_t的变量,指定当运行信号处理程序时要屏蔽的信号

(3)挂起信号队列

有几个系统调用能产生发送给整个线程组的信号,如kill()和rt_sigqueueinfo(),而其他的一些则产生发送给特定进程的信号,如tkill()和tgkill()

为了跟踪当前的挂起信号是什么,内核把两个挂起信号队列与每个进程相关联:

共享挂起信号队列,它位于信号描述符的shared_pending字段,存放整个线程组的挂起信号

私有挂起信号队列,它位于进程描述符的pending字段,存放特定进程的挂起信号

[4]在信号数据结构上的操作:参考p429-430的函数列表




2、产生信号

很多内核函数都会产生信号:它们完成信号处理第一步的工作,即根据需要更新一个或多个进程的描述符。它们不直接执行第二步的信号传递操作,而是可能根据信号的类型和目标进程的状态唤醒一些进程,并促使这些进程接收信号。

当发送给进程一个信号时,这个信号可能来自内核,也可能来自另一个进程。内核通过对如表11-9所示的某个函数进行调用而产生信号

当一个信号被发往整个线程组时,这个信号可能来自内核,也可能来自另一个进程。内核通过对如表11-10所示的某个函数进行调用而产生信号

[1]specific_send_sig_info()函数:向指定进程发送信号,步骤:参考p433

[2]send_signal()函数:在挂起信号队列中插入一个新元素,步骤:参考p434

[3]group_send_sig_info()函数:向整个线程组发送信号,步骤:参考p435-437



3、传递信号

为确保进程的挂起信号得到处理内核所执行的操作。

内核在允许进程恢复用户态下的执行之前,检查进程TIF_SIGPENDING标志的值。每当内核处理完一个中断或异常时,就检查是否存在挂起信号

为了处理非阻塞的挂起信号,内核调用do_signal()函数

通常只是在CPU要返回到用户态时才调用do_signal()函数

do_signal()函数的核心由重复调用dequeue_signal()函数的循环组成,直到在私有挂起信号队列和共享挂起信号队列中都没有非阻塞的挂起信号时,循环才结束。

dequeue_singal()函数首先考虑私有挂起信号队列中的所有信号,并从最低编号的挂起信号开始。然后考虑共享队列中的信号。它更新数据结构以表示信号不再是挂起的,并返回它的编号。

do_signal()函数如何处理每一个挂起的信号,其编号由dequeue_signal()返回。首先,它检查current接收进程是否正受到其他一些进程的监控;在肯定的情况下,do_signal()调用do_notify_parent_cldstop()和schedule()让监控进程知道进程的信号处理。

然后,do_signal()把要处理信号的k_sigaction数据结构的地址赋给局部变量ka;根据ka的内容可以执行三种操作:忽略信号、执行缺省操作或执行信号处理程序。如果显式忽略被传递的信号,那么do_signal()函数仅仅继续执行循环,并由此考虑另一个挂起信号

[1]执行信号的缺省操作

如果ka->sa.sa_handler等于SIG_DFL,do_signal()就必须执行信号的缺省操作。唯一的例外是当接收进程是init时,这个信号被丢弃。

SIGSTOP与其他信号的差异比较微妙:SIGSTOP总是停止线程组,而其他信号只停止不在“孤儿进程组”中的线程组。POSIX标准规定,只要进程组中一个进程有父进程,尽管进程处于不同的进程组中但在同一个会话中,那么这个进程组就不是孤儿。因此,如果父进程死亡,但启动该进程的用户并登录在线,那么该进程组就不是一个孤儿。

缺省操作为Dump的信号可以在进程的工作目录中创建一个“转储”文件,这个文件列出进程地址空间和CPU寄存器的全部内容

[2]捕获信号


如果信号有一个专门的处理程序,do_signal()就函数必须强迫该处理程序执行。这是通过调用handle_signal()进行的

注意do_signal()的处理了一个单独的信号后怎样返回。直到下一次调用do_signal()时才考虑其他挂起的信号。这种方式确保了实时信号将以适当的顺序得到处理

执行一个信号处理程序是件相当复杂的任务,因此在用户态和内核态之间切换时需要谨慎地处理栈中的内容。我们将正确地解释这里所承担的任务

信号处理程序是用户态进程所定义的函数,并包含在用户态的代码段中。handle_signal()函数运行在内核态,而信号处理程序运行在用户态,这就意味着在当前进程恢复“正常”执行之前,它必须首先执行用户态的信号处理程序。此外,当内核打算恢复进程的正常执行时,内核态堆栈不再包含被中断程序的硬件上下文,因此每当从内核态向用户态转换时,内核态堆栈都被清空。而另外一个复杂性是因为信号处理程序可以调用系统调用,在这种情况下,执行了系统调用的服务例程以后,控制权必须返回到信号处理程序而不是到被中断程序的正常代码流。

linux所采用的解决方法是把保存在内核态堆栈中的硬件上下文拷贝到当前进程的用户态堆栈中。用户态堆栈也以这样的方式被修改,即当信号处理程序终止时,自动调用sigreturn()系统调用把这个硬件上下文拷贝回到内核态堆栈中,并恢复用户态堆栈中原来的内容。

图11-2说明了有关捕捉一个信号的函数的执行流:

一个非阻塞的信号发送给一个进程。当中断或异常发生时,进程切换到内核态。

正要返回到用户态前,内核执行do_signal()函数,

这个函数又依次处理信号(通过调用handle_signal())和建立用户态堆栈(通过调用setup_frame()或setup_rt_frame())

当进程又切换到用户态时,因为信号处理程序的起始地址被强制放进程序计数器中,因此开始执行信号处理程序。

当处理程序终止时,setup_frame()或setup_rt_frame()函数放在用户态堆栈中的返回代码就被执行。这个代码调用sigreturn()或rt_sigrenturn()系统调用,相应的服务例程把正常程序的用户态堆栈硬件上下文拷贝到内核堆栈,并把用户态堆栈恢复到它原来的状态(通过调用restore_sigcongtext()).当这个系统调用结束时,普通进程就因此能恢复自己的执行

图:11-2***

深入理解Linux内核--信号(阅读笔记)(原创)



(1)建立帧

为了适当地建立进程的用户态堆栈,handle_signal()函数或者调用setup_frame()或者调用setup_rt_frame()

setup_frame()函数把一个叫做帧(frame)的数据结构推进用户态堆栈中,这个帧含有处理信号所需要的信息,并确保正确返回到handle_signal()函数

setup_frame()函数把保存在内核态堆栈的段寄存器内容重新设置成它们的缺省值以后才结束。现在,信号处理程序所有需的信息就在用户态堆栈的顶部。

(2)检查信号标志

建立了用户态堆栈以后,handle_signal()函数检查与信号相关的标志值。如果信号没有设置SA_NODEFER标志,在sigaction表中sa_make字段对应的信号就必须在信号处理程序执行期间被阻塞,然后,handle_signal()返回到do_signal(),do_signal()也立即返回

(3)开始执行信号处理程序

do_signal()返回时,当前进程恢复它在用户态的执行。由于如前所述setup_frame()的准备,eip寄存器指向信号处理程序的第一条指令,而esp指向已推进用户态堆栈顶的帧的第一个内存单元。因此,信号处理程序被执行。

(4)终止信号处理程序

信号处理程序结束时,返回栈顶地址,该地址指向帧的pretcode字段所引用的vsyscall页中的代码。因此,信号编号(即帧的sig字段)被从栈中丢弃,然后调用sigreturn()系统调用

sys_rt_sigreturn()服务例程把来自扩展帧的进程硬件上下文拷贝到内核态堆栈,并通过从用户态堆栈删除扩展帧以恢复用户态堆栈原来的内容。

(5)系统调用的重新执行

内核并不总是能立即满足系统调用发出的请求,在这种情况发生时,把发出系统调用的进程置为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE状态

如果进程处于TASK_INTERRUPTIBLE状态,并且某个进程向它发送了一个信号,那么,内核不完成系统调用就把进程置成TASK_RUNNING状态。当切换回用户态时信号被传递给进程。当这种情况发生时,系统调用服务例程没有完成它的工作,但返回EINTR,ERESTARTNOHAND,ERESTART_RESTARTBLOCK,ERESTARTSYS或ERESTARTNOINTR错误码。实际上,这种情况下用户态进程获得的唯一错误码是EINTR,这个错误码表示系统调用还没有执行完。内核内部使用剩余的错误码来指定信号处理程序结束后是否自动重新执行系统调用。

与未完成的系统调用相关的出错码及这些出错码对信号三种可能的操作产生的影响。

Terminate:不会自动重新执行系统调用

Reexecut:内核强迫用户态进程把系统调用号重新装入eax寄存器,并重新执行int$0x80指令或sysenter指令。进程意识不到这种重新执行,因此出错码也不传递给进程。

Depends:只有被传递信号的SA_RESTART标志被设置,才重新执行系统调用;否则系统调用-EINTER出错码结束

当传递信号时,内核在试图重新执行一个系统调用前必须确定进程确实发出过这个系统调用。这就是regs硬件上下文的orig_eaz字段起重要作用之处 

a、重新执行被未捕获信号中断的系统调用

如果信号被显式地忽略,或者如果它的缺省操作已被强制执行,do_signal()就分析系统调用的出错码,并如表11-11中所说明的那样决定是否重新自动执行未完成的系统调用。如果必须重新开始执行系统调用,那么do_signal()就修改regs硬件上下文,以便在进程返回到用户态时,eip指向int$0x80指令或sysenter指令,且eax包含系统调用号

b、为所捕获的信号重新执行系统调用

如果信号被捕获,那么handle_signal()分析出错码,也可能分析sigaction表的SA_RESTART标志来决定是否必须重新执行未完成的系统调用

如果系统调用必须被重新开始执行,handle_signal()就与do_signal()完全一样地继续执行;否则,它向用户态进程返回一个出错码-ENTR

4、与信号处理相关的系统调用

在用户态运行的进程可以发送和接收信号。这意味着必须定义一组系统调用用来完成这些操作。遗憾的是,由于历史的原因,已经存在几个具有相同功能的系统调用,因此,其中一些系统调用从未被调用。例如:系统调用sys_sigaction()和sys_rt_sigaciton()几乎是相同的,因此C库中封装函数sigaction()调用sys_rt_sigaction()而不是sys_sigaction()。

[1]kill()系统调用

一般用kill(pid,sig)系统调用向普通进程或多线程应用发送信号,其相应的服务例程是sys_kill()函数

kill()系统调用能发送任何信号,即使编号在32-64之间的实时信号。kill()系统调用不能确保把一个新的元素加入到目标进程的挂起信号队列,因此,挂起信号的多个实例可能被丢失。实时信号应该当通过rt_siggueueinfo()系统调用进行发送

[2]tkill和gkill()系统调用


tkill()和tgkill()系统调用向线程组中的指定进程发送信号

[3]改变信号的操作

sigaction(sig,act,oact)系统调用允许用户为信号指定一个操作。当然,如果没有自定义的信号操作,那么内核执行与传递的信号相关的缺省操作

[4]检查挂起的阻塞信号

sigpending()系统调用允许进程检查挂起的阻塞信号的集合,也就是说,检查信号被阻塞时已产生的那些信号

[5]修改阻塞信号的集合

sigprocmask()系统调用允许进程修改阻塞信号的集合。这个系统调用只应用于常规信号

[6]挂起进程

sigsuspend()系统调用把进程置为TASK_INTERRUPTIBLE状态,当然这是把mask参数指向的位掩码数组所指定的标准信号阻塞以后设置的。只有当一个非忽略、非阻塞的信号发送到进程以后,进程才被唤醒

[7]实时信号的系统调用

系统调用只应用到标准信号,因此,必须引入另外的系统调用来允许用户态进程处理实时信号

实时信号的几个系统调用:rt_sigaction()rt_sigpending()rt_sigprocmask()rt_sigsuspend()
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深入理解Linux内核--信号 的相关文章

  • 在内核中创建一个简单的只写过程条目

    include
  • __NR_gettid 和 SYS_gettid 之间的区别

    我只是在寻找在 Linux 中获取唯一线程 ID 的方法 我发现的方法是将两个参数中的任何一个作为参数进行系统调用 NR gettid OR SYS gettid 有人能解释一下它们之间有何不同吗 Nothing in
  • SDL - 窗口不显示任何内容

    我正在执行 SDL C 的第一步 并从 www sdl org 上学习了一些教程 但有一个问题 我已经在我的 Linux Mint 系统上安装了 SDL2 编译了教程代码 ifdef cplusplus include
  • 安装 python-dev 和链接库后,Cython 中的 Hello World 程序因 gcc 失败

    我创建了一个简单的 hello world 程序 并尝试使用 gcc 执行生成的 C 程序 但无论我做什么 我都会得到大量未定义的引用 SO 有很多类似的问题 但他们都说安装 python dev 或其某些变体 或添加用于链接和加载库的标志
  • 如何在 Ubuntu x64 中使用 ptrace 插入 int3?

    我正在努力追随本指南 http eli thegreenplace net 2011 01 27 how debuggers work part 2 breakpoints 通过设置断点达到相同的结果 唯一的区别是我在 x64 系统上 所以
  • 拼写检查 shell 脚本

    我有一些疑问 我对一个应该是简单拼写检查器的脚本有疑问 它的目的是 当发现错误的单词时 它会提示用户输入该单词的正确拼写 如果用户输入正确的拼写 则会显示更正的单词以及错误的单词 下面 在读完所有单词之后 但是 如果用户只是按 Enter
  • SO_BINDTODEVICE Linux 套接字选项的问题

    我有一台带有两个网卡的电脑 一 eth0 用于 LAN 互联网 另一个用于与一个微控制器设备进行 UDP 通信 微控制器有一个 IP 192 168 7 2 和一个 MAC 地址 第二个电脑网络适配器 eth1 有 192 168 7 1
  • SO_REUSEPORT 可以在 Unix 域套接字上使用吗?

    Linux 内核 gt 3 9 允许通过设置在内核负载平衡的进程之间共享套接字SO REUSEPORT http lwn net Articles 542629 http lwn net Articles 542629 这如何用于类型的套接
  • Linux C++ 错误:未定义对“dlopen”的引用

    我在 Linux 上使用 C Eclipse 工作 并且想要使用一个库 Eclipse 向我显示一个错误 undefined reference to dlopen 你知道解决办法吗 这是我的代码 include
  • 内核驱动程序从用户空间读取正常,但写回始终为 0

    因此 我正在努力完成内核驱动程序编程 目前我正在尝试在应用程序和内核驱动程序之间构建简单的数据传输 我使用简单的字符设备作为这两者之间的链接 并且我已成功将数据传输到驱动程序 但我无法将有意义的数据返回到用户空间 内核驱动程序如下所示 in
  • linux新手关于嵌入式linux设备驱动的问题

    最近在研究linux驱动 正如我读过的那些文章所说 设备驱动程序模块很可能会根据内核的需要自动加载 因此我想知道内核如何确定为特定设备 声卡 I2C spi 设备 等 我也无法彻底想象内核如何在启动时检测每个硬件设备 与嵌入式linux相关
  • Linux中如何避免sleep调用因信号而中断?

    我在 Linux 中使用实时信号来通知串行端口中新数据的到达 不幸的是 这会导致睡眠呼叫在有信号时被中断 有人知道避免这种行为的方法吗 我尝试使用常规信号 SIGUSR1 但我不断得到相同的行为 来自 nanosleep 联机帮助页 nan
  • 在 scapy 中通过物理环回发送数据包

    我最近发现了 Scapy 它看起来很棒 我正在尝试查看 NIC 上物理环回模块 存根上的简单流量 但是 Scapy sniff 没有给出任何结果 我正在做的发送数据包是 payload data 10 snf sniff filter ic
  • 在 Linux 中重新启动时,新创建的文件变为 0 kb(数据被覆盖为空)

    我遇到了一个奇怪的问题 这让我发疯 当前的任务是在 root 用户第一次登录时启动一组文件 并在同一用户第二次登录时启动另一组文件 我决定使用 profile 和 bashrc 文件 并在第一次登录期间发生的任务结束时重新加载 bashrc
  • 更新Linux中的包含路径

    我的 my path to file 文件夹中有几个头文件 我知道如何将这些文件包含在新的 C 程序中 但每次我都需要在包含它之前输入头文件的完整路径 我可以在linux中设置一些路径变量 以便它自动查找头文件吗 您可以创建一个 makef
  • MySQL 与 PHP 的连接无法正常工作

    这是我的情况 我正在尝试使用 Apache 服务器上的 PHP 文件连接到 MySQL 数据库 现在 当我从终端运行 PHP 时 我的 PHP 可以连接到 MySQL 数据库 使用 php f file php 但是当我从网页执行它时 它只
  • 为什么 OS X 和 Linux 之间的 UTF-8 文本排序顺序不同?

    我有一个包含 UTF 8 编码文本行的文本文件 mac os x cat unsorted txt foo foo 津 如果它有助于重现问题 这里是文件中确切字节的校验和和转储 以及如何自己生成文件 在 Linux 上 使用base64 d
  • Bash:将字符串添加到文件末尾而不换行

    如何将字符串添加到文件末尾而不换行 例如 如果我使用 gt gt 它将添加到文件末尾并换行 cat list txt yourText1 root host 37 echo yourText2 gt gt list txt root hos
  • Crontab 每 5 分钟一次 [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我如何告诉 crontab 每 5 分钟运行一次 但从每小时的第二分钟开始 换句话说 我想在以下时间执行我的脚本minute 5 2 例如 我的脚本应
  • 来自守护程序的错误响应:加入会话密钥环:创建会话密钥:超出磁盘配额

    我尝试在我的服务器上安装 docker 使用本教程 https docs docker com install linux docker ce ubuntu 我想远程运行 docker 镜像并使用 portainer Web 界面来管理一切

随机推荐

  • k8s基础

    目录 一 基本介绍 二 组件介绍 1 master组件 2 node组件 三 核心概念 1 Pod 2 controller 3 service 四 单master搭建集群 1 系统初始化 2 安装k8s核心组件 3 容器化安装其他插件 4
  • 论文解读:Tips and Tricks for Visual Question Answering: Learnings from the 2017 Challenge

    这是关于VQA问题的第十二篇系列文章 这篇论文具有很强的指导意义 xff0c 本篇文章将介绍论文 xff1a 主要思想 xff1b 模型方法 xff1b 试验细节 有兴趣可以查看原文 xff1a Tips and Tricks for Vi
  • 总结2014——迷茫以及迷茫过后的坚持

    首先 xff0c 借用一句话和大家共勉 xff1a 少一些功利主义的追求 xff0c 多一些不为什么的坚持 xff01 xff01 不知不觉15年也快过了1个月了 xff0c 还是想着要为14年做一下总结 xff1a 记录一下自己的历程 今
  • 在faster rcnn中使用soft nms,faster rcnn的改进(一)

    1 背景介绍 我的项目是利用faster rcnn检测kiiti数据集 xff0c 用原始nms xff0c iters 61 10000的情况下 xff0c 得到的mAP 61 0 586 在改用soft nms后 xff0c 其他参数均
  • 建立DATAGUARD最大保护模式-测试手记

    建立DATAGUARD 最大保护模式 xff08 自写 xff09 xff08 备注 xff1a 本文档符合最大保护模式 xff0c 所有参数均为最大保护模式下适用 xff0c 其他模式不适用 xff09 1 主库 xff0c 启动归档 x
  • docker中安装ping | vim | nginx镜像

    docker安装nginx镜像并常见nginx容器 docker pull nginx latest docker run detach publish 9999 80 name nginxSer restart unless stoppe
  • 从操作系统内核解释电脑死机原理

    关于电脑死机的原因或者说原理 xff0c 即电脑为什么会死机 xff0c 电脑死机时计算机底层都发生了什么 一直不太明白 xff0c 在网上也查过相关的资料 xff0c 但是都没有找到自己想要的 网上谈的都是外部导致电脑死机的原因 xff0
  • 自己动手写操作系统第二章 pmtest1.asm分析

    34 pm inc 34 描述符 Usage Descrptor Base Limit Attr Base dd Limit dd Low 20 bits available Attr dw lower 4 bits of higher b
  • Linux 0.11 内核在内核空间创建进程时不使用写时复制技术

    在Linux0 12内核完全剖析中 xff0c 有这样一段话 34 由于创建新进程的过程是通过完全复制父进程代码段和数据段的方式实现 xff0c 因此在首次使用fork 创建新进程init 时 xff0c 为了确保新进程用户态栈中没有进程0
  • putty 登陆VMware虚拟机下的linux系统

    物理机的操作系统是Windows XP 虚拟机是在VMware上安装的CentOS xff0c 版本是5 6 因为每次登陆虚拟机鼠标会被限定在虚拟机的登陆界面 xff0c 所以想通过远程登陆工具来登陆虚拟机 虚拟机使用的网络是桥接模式 注意
  • Minx内核中scanf函数实现代码

    include lt stdio h gt include lt stdarg h gt include 34 loc incl h 34 int scanf const char format va list ap int retval
  • 双系统Linux下突然挂载Windows分区失败

    问题描述 xff0c 装了双系统之后 xff0c 一开始在Linux下还能访问Windows的分区 xff0c 可是突然之间就不能访问了 xff0c 错误信息如下 xff1a Error mounting dev sda1 at media
  • 对Linux0.11 "内核空间不使用写时复制机制" 本质理解

    一个页面被多个进程共享 xff0c 每当一个进程产生一次写保护 错误 xff0c 内核将给进程分配一个新的物理页面 xff0c 将共享页面的内容复制过来 xff0c 新的页面将设置为可读写 xff0c 而共享页面仍然是只读的 xff0c 只
  • Session && Cookie

  • windowsxp远程桌面端口号改变的位置

    HKEY LOCAL MACHINE SYSTEM CurrentControlSet Control Terminal Server Wds rdpwd Tds tcp 下的PortNamber HKEY LOCAL MACHINE SY
  • linux0.11 进程切换

    move to user mode是在堆栈中创建一个任务切换的假象 xff0c 用iret跳转到外层3 xff0c 这样cpu就会自动根据tr加载tss xff0c 并初始化各个寄存器运行任务0 所以 xff0c 任务0其实就是内核空间中的
  • Linux0.11 进程0

    Linux中1号进程是由0号进程来创建的 xff0c 因此必须要知道的是如何创建0号进程 xff0c 由于在创建进程时 xff0c 程序一直运行在内核态 xff0c 而进程运行在用户态 xff0c 因此创建0号进程涉及到特权级的变化 xff
  • Linux0.11 由进程睡眠函数sleep_on()中的堆栈变量tmp引发的思考 关于进程内核堆栈

    sleep on cpp view plaincopy 功能 xff1a 当前进程进入不可中断睡眠态 xff0c 挂起在等待队列上 参数 xff1a p 等待队列头 返回 xff1a xff08 无 xff09
  • 关于Windows系统环境变量的引用问题

    做Leap Motion开发时 xff0c 新建了LEAP SDK的系统环境变量 xff0c 按照官方SDK文档中说明的 xff0c 在工程中引入 LEAP SDK include 之前半年的时间里都是这样做的 xff0c 没有任何问题 x
  • 深入理解Linux内核--信号

    信号用于在用户态进程间通信 内核也用信号通知进程系统所发生的事情 1 信号的作用 信号 signal 是很短的消息 xff0c 可以被发送到一个进程或一组进程 发送给进程的唯一信息通常是一个数 xff0c 以此来标识信号 使用信号的两个主要