精华内容
下载资源
问答
  • 之前有听到别人的面试题是问系统创建进程的具体过程是什么,首先想到的是CreateProcess,但是对于具体过程却不是很清楚,今天整理一下。 从操作系统的角度来说 创建进程步骤: 1.申请进程块 2.为进程分配内存资源 ...

    之前有听到别人的面试题是问系统创建进程的具体过程是什么,首先想到的是CreateProcess,但是对于具体过程却不是很清楚,今天整理一下。

    从操作系统的角度来说

    创建进程步骤:
            1.申请进程块      
            2.为进程分配内存资源
            3.初始化进程块
            4.将进程块链入就绪队列

    课本上的知识。。。

     

    从CreateProcess的具体流程来说:

    CreateProcess它首先创建一个执行体进程对象,即EPROCESS 对象,然后创建一个初始线程,为初始线程建立一个栈,并设置好它的初始执行环境。完成这些工作以后,该线程就可以参与系统的线程调度了。然而,通过Windows API 函数创建的进程也要接受Windows 子系统的管理,在这种情况下,仅仅内核部分的工作还不够,系统在创建进程过程中,还需要跟子系统打交道。另外,还需建立起独立的内存地址空间。

    CreateProcess通过内核创建进程的步骤,大致分为六个阶段:

    NtCreateProcess,它只是简单地对参数稍作处理,然后把创建进程的任务交给NtCreateProcessEx 函数,所以我们来看NtCreateProcessEx 的原型及其流程。

     

    NTSTATUS  
    NtCreateProcessEx(  
    __out PHANDLE ProcessHandle,  
    __in ACCESS_MASK DesiredAccess,  
    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,  
    __in HANDLE ParentProcess,  
    __in ULONG Flags,  
    __in_opt HANDLE SectionHandle,  
    __in_opt HANDLE DebugPort,  
    __in_opt HANDLE ExceptionPort,  
    __in ULONG JobMemberLevel  
    ); 

     

    NtCreateProcessEx 函数的代码只是简单地检查ProcessHandle 参数代表的句柄是否可写,然后把真正的创建工作交给PspCreateProcess 函数,所以,PspCreateProcess 才是真正创建进程的函数。

    PsCreateSystemProcess 可用于创建系统进程对象,它创建的进程都是PsInitialSystemProcess 的子进程。所以,PspCreateProcess函数负责创建系统中的所有进程,包括System 进程。下面介绍此函数的基本流程。

     

     

    第一阶段:打开目标映像文件

    第二阶段:创建内核中的进程对象

    第三阶段:创建初始线程

    第四阶段:通知windows子系统进程csrss.exe进程来对新进程进行管理

    第五阶段:启动初始线程

    第六阶段:用户空间的初始化和Dll连接

     

    具体内容:

    在Windows中,CreateProcess要先通过系统调用NtCreateProcess创建进程,成功以后就立即通过系统调用NtCreateThread创建其第一个线程。
     
    第一阶段:打开目标映像文件
     
    首先用CreateProcess(实际上是CreateProcessW)打开指定的可执行映像文件,并创建一个内存区对象。注意,内存区对象并没有被映射到内存中(由于目标进程尚未建立起来,不可能完成内存映射),但它确实是打开了。
     
     
    第二阶段:创建内核中的进程对象
     
    实际上就是创建以EPROCESS为核心的相关数据结构,主要包括:
     
    调用内核中的NtCreateProcessEx 系统服务,实际的调用过程是这样的:kernel32.dll 中的CreateProcessW调用ntdll.dll 中的存根函数NtCreateProcessEx,而ntdll.dll的NtCreateProcessEx 利用处理器的陷阱机制切换到内核模式下;在内核模式下,系统服务分发函数KiSystemService 获得控制,它利用当前线程指定的系统服务表,调用到执行体层的NtCreateProcessEx 函数。然后,执行体层的NtCreateProcessEx 函数执行前面介绍的进程创建逻辑,包括创建EPROCESS 对象、初始化其中的域、创建初始的进程地址空间、创建和初始化句柄表,并设置好EPROCESS 和KPROCESS 中的各种属性,如进程优先级、安全属性、创建时间等。到这里,执行体层的进程对象已经建立起来,进程的地址空间已经初始化,并且EPROCESS 中的PEB 也已初始化。
     
    第三阶段:创建初始线程
     
    这个阶段是通过调用NtCreateThread()完成的,主要包括:
     现在,虽然进程对象已经建立起来,但是它没有线程,所以,它自己还不能做任何事情。接下来需要创建一个初始线程,在此之前,首先要构造一个栈以及一个可供运行的环境。初始线程的栈的大小可以通过映像文件获得,而创建线程则可以通过调用ntdll.dll 中的NtCreateThread 函数来完成。
    创建和设置目标线程的ETHREAD数据结构,并处理好与EPROCESS的关系(例如进程块中的线程计数等等)。
    在目标进程的用户空间创建并设置目标线程的TEB。
    将目标线程在用户空间的起始地址设置成指向Kernel32.dll中的BaseProcessStart()或BaseThreadStart(),前者用于进程中的第一个线程,后者用于随后的线程。
         用户程序在调用NtCreateThread()时也要提供一个用户级的起始函数(地址), BaseProcessStart()和BaseThreadStart()在完成初始化时会调用这个起始函数。
         ETHREAD数据结构中有两个成份,分别用来存放这两个地址。
    调用KeInitThread设置目标线程的KTHREAD数据结构并为其分配堆栈和建立执行环境。
       特别地,将其上下文中的断点(返回点)设置成指向内核中的一段程序KiThreadStartup,使得该线程一旦被调度运行时就从这里开始执行。
    系统中可能登记了一些每当创建线程时就应加以调用的“通知”函数,调用这些函数。
     
     
    第四阶段:通知windows子系统
     
    每个进程在创建/退出的时候都要向windows子系统进程csrss.exe进程发出通知,因为它担负着对windows所有进程的管理的责任,
    注意,这里发出通知的是CreateProcess的调用者,不是新建出来的进程,因为它还没有开始运行。
     
    至此,CreateProcess的操作已经完成,但子进程中的线程却尚未开始运行,它的运行还要经历下面的第五和第六阶段。
     
     
    第五阶段:启动初始线程
     

    在内核中,新线程的启动例程是KiThreadStartup函数,这是当PspCreateThread 调用KeInitThread 函数时,KeInitThread 函数调用KiInitializeContextThread(参见base\ntos\ke\i386\thredini.c 文件)来设置的。

    KiThreadStartup 函数首先将IRQL 降低到APC_LEVEL,然后调用系统初始的线程函数PspUserThreadStartup。这里的PspUserThreadStartup 函数是PspCreateThread 函数在调用KeInitThread 时指定的,。注意,PspCreateThread函数在创建系统线程时指定的初始线程函数为PspSystemThreadStartup  。线程启动函数被作为一个参数传递给PspUserThreadStartup,在这里,它应该是kernel32.dll 中的BaseProcessStart。

    PspUserThreadStartup 函数被调用。逻辑并不复杂,但是涉及异步函数调用(APC)机制。


    新创建的线程未必是可以被立即调度运行的,因为用户可能在创建时把标志位CREATE_ SUSPENDED设成了1;
    如果那样的话,就需要等待别的进程通过系统调用恢复其运行资格以后才可以被调度运行。否则现在已经可以被调度运行了。至于什么时候才会被调度运行,则就要看优先级等等条件了。
     
     
    第六阶段:用户空间的初始化和Dll连接
     

    PspUserThreadStartup 函数返回以后,KiThreadStartup 函数返回到用户模式,此时,PspUserThreadStartup 插入的APC 被交付,于是LdrInitializeThunk 函数被调用,这是映像加载器(image loader)的初始化函数。LdrInitializeThunk 函数完成加载器、堆管理器等初始化工作,然后加载任何必要的DLL,并且调用这些DLL 的入口函数。最后,当LdrInitializeThunk 返回到用户模式APC 分发器时,该线程开始在用户模式下执行,调用应用程序指定的线程启动函数,此启动函数的地址已经在APC 交付时被压到用户栈中。


    DLL连接由ntdll.dll中的LdrInitializeThunk()在用户空间完成。在此之前ntdll.dll与应用软件尚未连接,但是已经被映射到了用户空间
    函数LdrInitializeThunk()在映像中的位置是系统初始化时就预先确定并记录在案的,所以在进入这个函数之前也不需要连接。

     

    涉及到了Windows内核的知识,细节处还有待理解。。。

    参考资料:

    http://www.cnblogs.com/csyisong/archive/2010/10/22/1858115.html

    http://www.cnblogs.com/Gotogoo/p/5262536.html

    http://book.51cto.com/art/201011/235767.htm

    《Windows内核原理与实现》潘爱民

     

    转载于:https://www.cnblogs.com/HsinTsao/p/6534317.html

    展开全文
  • 原文:详解CreateProcess调用内核创建进程的过程 昨天同学接到了腾讯的电面,有一题问到了CreateProcess创建进程的具体实现过程,他答得不怎么好吧应该是, 为了以防万一,也为了深入学习一下,今天我翻阅了...

    原文:详解CreateProcess调用内核创建进程的过程

     

     

    昨天同学接到了腾讯的电面,有一题问到了CreateProcess创建进程的具体实现过程,他答得不怎么好吧应该是,

     

    为了以防万一,也为了深入学习一下,今天我翻阅了好多资料,整理了一下,写篇博客,也算是加深理解吧

     

     

     

    1.函数原型:

     

    复制代码
    BOOL
    WINAPI
    CreateProcessW(
        LPCWSTR lpApplicationName,
        LPWSTR lpCommandLine,
        LPSECURITY_ATTRIBUTES lpProcessAttributes,
        LPSECURITY_ATTRIBUTES lpThreadAttributes,
        BOOL bInheritHandles,
        DWORD dwCreationFlags,
        LPVOID lpEnvironment,
        LPCWSTR lpCurrentDirectory,
        LPSTARTUPINFOW lpStartupInfo,
        LPPROCESS_INFORMATION lpProcessInformation
        )
    复制代码

     

    2.参数意义:

     

    第一参数:lpApplicationName

     

    指向一个NULL结尾的、用来指定可执行模块的字符串。

     

    这个字符串可以是可执行模块的绝对路径,也可以是相对路径,在后一种情况下,函数使用当前驱动器和目录建立可执行模块的路径。

     

    这个参数可以被设为NULL,在这种情况下,可执行模块的名字必须处于 lpCommandLine 参数最前面并由空格符与后面的字符分开。

     

     

     

     

     

    第二参数:lpCommandLine

     

    指向一个以NULL结尾的字符串,该字符串指定要执行的命令行。

     

    这个参数可以为空,那么函数将使用lpApplicationName参数指定的字符串当做要运行的程序的命令行。

     

    如果lpApplicationName和lpCommandLine参数都不为空,那么lpApplicationName参数指定将要被运行的模块,lpCommandLine参数指定将被运行的模块的命令行。新运行的进程可以使用GetCommandLine函数获得整个命令行。C语言程序可以使用argc和argv参数。

     

     

     

     

     

    第三参数:lpProcessAttributes

     

    指向一个SECURITY_ATTRIBUTES结构体,这个结构体决定是否返回的句柄可以被子进程继承。如果lpProcessAttributes参数为空(NULL),那么句柄不能被继承。

     

    在Windows NT中:SECURITY_ATTRIBUTES结构的lpSecurityDescriptor成员指定了新进程的安全描述符,如果参数为空,新进程使用默认的安全描述符。

     

     

     

     

     

    第四参数:lpThreadAttributes

     

    同lpProcessAttribute,不过这个参数决定的是线程是否被继承.通常置为NULL.

     

     

     

     

     

    第五参数:bInheritHandles

     

    指示新进程是否从调用进程处继承了句柄。

     

    如果参数的值为真,调用进程中的每一个可继承的打开句柄都将被子进程继承。被继承的句柄与原进程拥有完全相同的值和访问权限。

     

     

     

     

     

    第六参数:dwCreationFlags

     

    指定附加的、用来控制优先类和进程的创建的标志。以下的创建标志可以以除下面列出的方式外的任何方式组合后指定。

     

    ⑴值:CREATE_DEFAULT_ERROR_MODE

     

    含义:新的进程不继承调用进程的错误模式。CreateProcess函数赋予新进程当前的默认错误模式作为替代。应用程序可以调用SetErrorMode函数设置当前的默认错误模式。

     

    这个标志对于那些运行在没有硬件错误环境下的多线程外壳程序是十分有用的。

     

    对于CreateProcess函数,默认的行为是为新进程继承调用者的错误模式。设置这个标志以改变默认的处理方式。

     

    ⑵值:CREATE_NEW_CONSOLE

     

    含义:新的进程将使用一个新的控制台,而不是继承父进程的控制台。这个标志不能与DETACHED_PROCESS标志一起使用。

     

    ⑶值:CREATE_NEW_PROCESS_GROUP

     

    含义:新进程将是一个进程树的根进程。进程树中的全部进程都是根进程的子进程。新进程树的用户标识符与这个进程的标识符是相同的,由lpProcessInformation参数返回。进程树经常使用GenerateConsoleCtrlEvent函数允许发送CTRL+C或CTRL+BREAK信号到一组控制台进程。

     

    ⑷值:CREATE_SEPARATE_WOW_VDM

     

    如果被设置,新进程将会在一个私有的虚拟DOS机(VDM)中运行。另外,默认情况下所有的16位Windows应用程序都会在同一个共享的VDM中以线程的方式运行。单独运行一个16位程序的优点是一个应用程序的崩溃只会结束这一个VDM的运行;其他那些在不同VDM中运行的程序会继续正常的运行。同样的,在不同VDM中运行的16位Windows应用程序拥有不同的输入队列,这意味着如果一个程序暂时失去响应,在独立的VDM中的应用程序能够继续获得输入。

     

    ⑸值:CREATE_SHARED_WOW_VDM

     

    如果WIN.INI中的Windows段的DefaultSeparateVDM选项被设置为真,这个标识使得CreateProcess函数越过这个选项并在共享的虚拟DOS机中运行新进程。

     

    ⑹值:CREATE_SUSPENDED

     

    含义:新进程的主线程会以暂停的状态被创建,直到调用ResumeThread函数被调用时才运行。

     

    ⑺值:CREATE_UNICODE_ENVIRONMENT

     

    含义:如果被设置,由lpEnvironment参数指定的环境块使用Unicode字符,如果为空,环境块使用ANSI字符。

     

    ⑻值:DEBUG_PROCESS

     

    含义:如果这个标志被设置,调用进程将被当做一个调试程序,并且新进程会被当做被调试的进程。系统把被调试程序发生的所有调试事件通知给调试器。

     

    如果你使用这个标志创建进程,只有调用进程(调用CreateProcess函数的进程)可以调用WaitForDebugEvent函数。

     

    ⑼值:DEBUG_ONLY_THIS_PROCESS

     

    含义:如果此标志没有被设置且调用进程正在被调试,新进程将成为调试调用进程的调试器的另一个调试对象。如果调用进程没有被调试,有关调试的行为就不会产生。

     

    ⑽值:DETACHED_PROCESS

     

    含义:对于控制台进程,新进程没有访问父进程控制台的权限。新进程可以通过AllocConsole函数自己创建一个新的控制台。这个标志不可以与CREATE_NEW_CONSOLE标志一起使用。

     

    〔11〕值:CREATE_NO_WINDOW

     

    含义:系统不为新进程创建CUI窗口,使用该标志可以创建不含窗口的CUI程序。

     

     

     

     

     

     

     

     

     

    第七参数:lpEnvironment

     

    指向一个新进程的环境块。如果此参数为空,新进程使用调用进程的环境。

     

    一个环境块存在于一个由以NULL结尾的字符串组成的块中,这个块也是以NULL结尾的。每个字符串都是name=value的形式。

     

    因为相等标志被当做分隔符,所以它不能被环境变量当做变量名。

     

    与其使用应用程序提供的环境块,不如直接把这个参数设为空,系统驱动器上的当前目录信息不会被自动传递给新创建的进程。对于这个情况的探讨和如何处理,请参见注释一节。

     

    环境块可以包含Unicode或ANSI字符。如果lpEnvironment指向的环境块包含Unicode字符,那么dwCreationFlags字段的CREATE_UNICODE_ENⅥRONMENT标志将被设置。如果块包含ANSI字符,该标志将被清空。

     

    请注意一个ANSI环境块是由两个零字节结束的:一个是字符串的结尾,另一个用来结束这个快。一个Unicode环境块是由四个零字节结束的:两个代表字符串结束,另两个用来结束块。

     

     

     

     

     

    第八参数:lpCurrentDirectory

     

    指向一个以NULL结尾的字符串,这个字符串用来指定子进程的工作路径。这个字符串必须是一个包含驱动器名的绝对路径。如果这个参数为空,新进程将使用与调用进程相同的驱动器和目录。这个选项是一个需要启动应用程序并指定它们的驱动器和工作目录的外壳程序的主要条件。

     

     

     

     

     

    第九参数:lpStartupInfo

     

    指向一个用于决定新进程的主窗体如何显示的STARTUPINFO结构体

     

     

     

     

     

    第十参数:lpProcessInformation

     

    指向一个用来接收新进程的识别信息的PROCESS_INFORMATION结构体。 

     

     

     

    下面是CreateProcess的一个简单实例,打开了一个notepad:

     

    复制代码
    #include<stdio.h>
    #include<windows.h>
    int main(int argc,char*argv[])
    {
        char szCommandLine[]="notepad";
        STARTUPINFO si={sizeof(si)};
        PROCESS_INFORMATION pi;
        si.dwFlags=STARTF_USESHOWWINDOW;//指定wShowWindow成员效
        si.wShowWindow=TRUE;//此成员设为TRUE的话则显示新建进程的主窗口
        BOOL bRet=CreateProcess(
            NULL,//不在此指定可执行文件的文件名
            szCommandLine,//命令行参数
            NULL,//默认进程安全性
            NULL,//默认进程安全性
            FALSE,//指定当前进程内句柄不可以被子进程继承
            CREATE_NEW_CONSOLE,//为新进程创建一个新的控制台窗口
            NULL,//使用本进程的环境变量
            NULL,//使用本进程的驱动器和目录
            &si,
            &pi);
        if(bRet)
        {
            //不使用的句柄最好关掉
            CloseHandle(pi.hThread);
            CloseHandle(pi.hProcess);
            printf("新进程的ID号:%d\n",pi.dwProcessId);
            printf("新进程的主线程ID号:%d\n",pi.dwThreadId);
        }
    
        getchar();
        return 0;
    }
    复制代码

     

     

     

     

     

     

    3.CreateProcess通过内核创建进程的步骤,大致分为六个阶段:

     

     

     

    在Windows中,进程是不活动的,只是作为线程的容器,现代操作系统将线程作为最小调度单位,进程作为资源分配的最小单位。

     

    所以,CreateProcess作为一个相对高层的函数,要先通过系统调用NtCreateProcess()创建进程(容器),成功以后就立即通过系统调用NtCreateThread()创建其第一个线程。

     

     

     

    第一阶段:打开目标映像文件

     

     

     

    对于32位exe映像,CreateProcess先打开其映像文件,在为其创建一个Section即文件映射区,将文件内容映射进来,前提是目标文件是一个合格的EXE文件(PE文件头部检测);

     

     

     

     

     

    第二阶段:创建内核中的进程对象

     

     

     

    实际上就是创建以EPROCESS为核心的相关数据结构,这就是系统调用NtCreateProcess()要做的事情,主要包括:

     

     

     

      ①分配并设置EPROCESS数据结构;

     

      ②其他相关的数据结构的设置,如句柄表等等;

     

      ③为目标进程创建初始的地址空间;

     

      ④对EPROCESS进行初始化;

     

      ⑤将系统Dll映射到目标用户空间,如ntdll.dll等

     

      ⑥设置目标进程的PEB;

     

      ⑦将其他需要映射到用户空间,如与”当地语言支持“即NLS有关的数据结构;

     

      ⑧完成EPROCESS创建,将其挂入进程队列并插入创建者的句柄表

     

     

     

     

     

    第三阶段:创建初始线程

     

     

     

    前面说过,进程只是一个容器,干活儿是里面的线程,所以下一步就是创建目标进程的初始线程

     

     

     

    与EPROCESS对应,线程的数据结构是ETHREAD,与进程环境块PEB对应,线程也有线程环境块TEB;

     

    PEB在用户空间的位置大致是固定的,在7ffd0000左右,PEB的下方就是TEB,进程有几个线程就有几个TEB,每个TEB占一个4KB的页面;

     

    这个阶段是通过调用NtCreateThread()完成的,主要包括:

     

     

     

      ①创建和设置目标线程的ETHREAD数据结构,并处理好与EPROCESS的关系(例如进程块中的线程计数等等)。

      ②在目标进程的用户空间创建并设置目标线程的TEB。

      ③将目标线程在用户空间的起始地址设置成指向Kernel32.dll中的BaseProcessStart()或BaseThreadStart(),前者用于进程中的第一个线程,后者用于随后的线程。

         用户程序在调用NtCreateThread()时也要提供一个用户级的起始函数(地址), BaseProcessStart()和BaseThreadStart()在完成初始化时会调用这个起始函数。

         ETHREAD数据结构中有两个成份,分别用来存放这两个地址。

      ④调用KeInitThread设置目标线程的KTHREAD数据结构并为其分配堆栈和建立执行环境。

         特别地,将其上下文中的断点(返回点)设置成指向内核中的一段程序KiThreadStartup,使得该线程一旦被调度运行时就从这里开始执行。

      ⑤系统中可能登记了一些每当创建线程时就应加以调用的“通知”函数,调用这些函数。

     

     

     

     

    第四阶段:通知windows子系统

     

     

     

    关于windows子系统  http://book.51cto.com/art/201011/235712.htm

     

     

     

    每个进程在创建/退出的时候都要向windows子系统进程csrss.exe进程发出通知,因为它担负着对windows所有进程的管理的责任,

     

    注意,这里发出通知的是CreateProcess的调用者,不是新建出来的进程,因为它还没有开始运行。

     

     

     

    至此,CreateProcess的操作已经完成,但子进程中的线程却尚未开始运行,它的运行还要经历下面的第五和第六阶段。

     

     

     

     

     

    第五阶段:启动初始线程

     

     

     

    新创建的线程未必是可以被立即调度运行的,因为用户可能在创建时把标志位CREATE_ SUSPENDED设成了1;

     

    如果那样的话,就需要等待别的进程通过系统调用恢复其运行资格以后才可以被调度运行。否则现在已经可以被调度运行了。至于什么时候才会被调度运行,则就要看优先级等等条件了。

     

     

     

     

     

    第六阶段:用户空间的初始化和Dll连接

     

     

     

    DLL连接由ntdll.dll中的LdrInitializeThunk()在用户空间完成。在此之前ntdll.dll与应用软件尚未连接,但是已经被映射到了用户空间(第二阶段第⑤步)

     

    函数LdrInitializeThunk()在映像中的位置是系统初始化时就预先确定并记录在案的,所以在进入这个函数之前也不需要连接。

     

    转载于:https://www.cnblogs.com/zhehan54/p/6047217.html

    展开全文
  • windows创建进程的过程

    2016-05-06 16:34:00
    进程的一部分是操作系统管理进程的内核对象。系统使用内核对象来存放进程的信息  2.进程的另一部分是进程的地址空间,它包含进程运行所需要的代码和数据  我们可以使用CreateProcess函数来创建一个进程,因为...

      进程,顾名思义,是一个进行中的程序,即操作系统正在运行的程序的实例。它由两部分组成:

      1.进程的一部分是操作系统管理进程的内核对象。系统使用内核对象来存放进程的信息

      2.进程的另一部分是进程的地址空间,它包含进程运行所需要的代码和数据

      我们可以使用CreateProcess函数来创建一个进程,因为进程由两部分组成,所以系统在调用CreatProcess函数的时候,会创建一个进程内核对象,并将进程内核对象的是使用计数设置为1,然后系统为新进程创建一个虚拟的地址空间,并将进程运行需要的可执行文件和DLL文件的代码和数据加载到这个进程的地址空间中。

      进程就像一个容器,它自生是无法运行的,必须依靠一个在进程环境中的线程来负责执行进程中的代码。因此,进程创建的过程中,系统会为新进程创建一个主线程,然后通过执行C/C++运行库的启动代码就可以引发主线程的执行,主线程接着就会调用(w)WinMain和(w)main函数。

    转载于:https://www.cnblogs.com/liujack/p/5466169.html

    展开全文
  • 本文为我学习linux内核的总结。 ... 1、概述  前面分析了系统调用的原理和过程。本文分析fork这个系统调用,重点分析进程的创建主要动作和流程。 2、fork 系统调用的主要动作    如上图,fork、vfo...

    本文为我学习linux内核的总结。

    唐建 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000。

    1、概述

      前面分析了系统调用的原理和过程。本文分析fork这个系统调用,重点分析进程的创建主要动作和流程。

    2、fork 系统调用的主要动作

      

      如上图,fork、vfork、clone,最终都是调用do_fork。不过他们之间的差异也可以在do_fork及后续代码中看到,不过这里不讲述。

          do_fork 的主要逻辑为调用copy_process,又函数名就可以看到进程的生成逻辑就在copy_process.

      copy_process主要调用了:

            dup_task_struct()——主要是创建和复制进程

             copy_fs            ——拷贝文件句柄之类的

      copy_files         ——拷贝文件句柄之类的

            copy_mm         ——拷贝虚拟内存

      copy_io             ——拷贝io

      copy_thread     ——拷贝thead_info信息

           下面我们着重分析 dup_task_struct 和 copy_thread 。    

         2.1 、dup_task_struct:申请内存,拷贝task_struct和thread_info       

      如上图所示,前面两个调用为申请task_struct、thread_info 的内存,arch_dup_task_struct就是将父进程的

      task_struct 拷贝给子进程。

           setup_thread_stack:这个函数是将父进程的堆栈thread_info拷贝给子进程。

      

       2.2、copy_thread :准备栈信息

     如上图信息childregs保存父进程的堆栈信息,然后赋值给子进程堆栈。右图pt_regs为系统调用开始通过save_all保存的信息。

    同时可以看到如果是内核创建线程走的不同的分支,不同的处理。

    上面可以看到childregs->ax=0,就是返回值,也就是子进程返回的pid为0的原因。

    p->thread.ip = (unsigned long) ret_from_fork,前面设置了sp栈顶,这里再设置ip。

    ret_from_fork->syscall_exit。这里就很熟悉了,就是我们上一篇博客中的系统调用完成后的执行过程,ip为子进程执行的起点,所以可以知道
    子进程开始调度时是从ret_from_fork开始执行的。
    2.3、父进程

    如上图所示,子进程完全准备完毕,获取子进程id作用父进程的返回值,同时唤醒子进程。这样两个进程都可以运行了 。

    3、debug

      下面我们来跟踪fork内核执行过程,我们断住主要函数do_fork、copy_process、dup_task_struct、copy_thread 、

    ret_from_fork

    4、总结

      fork创建一个进程,实际上就将父进程的进程信息拷贝给子进程,子进程的起点就是父进程系统调用结束的位置。只有子进程信息完全准备好后,父进程要返回前才唤醒子进程。

     

     

    
    

      

     

     





    转载于:https://www.cnblogs.com/tjyuanxi/p/9245563.html

    展开全文
  • 进程(Process)是具有一定独立功能程序关于某个数据集合上一次运行活动,是系统进行资源分配...它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而被撤消,反映了一个程序在一定...
  • 注意:signal.c和fork.c文件编译选项内不能有vc变量优化选项/Og,因为这两个文件 内函数参数内包含了函数返回地址等内容。如果加了/Og选项,编译器就会在认为 这些参数不再使用后占用该内存,导致函数返回时...
  • 进程能创建多少线程与进程逻辑地址空间(32位地址长度...一些操作系统是这样创建进程的:在新的地址空间创建进程,读入可执行文件,最后开始执行。 Unix和Linux采用另一种方式: 它把创建进程分成两步,fork()和exe...
  • 进程创建的过程

    2019-09-25 20:06:10
    1.什么是进程?  进程提供程序所需的资源,如: 数据、代码等等(空间上的概念) ...进程的创建过程 映射EXE文件 创建内核对象EPROCESS 映射系统DLL(ntdll.dll) 创建线程内核对象ETHR...
  • 进程的创建过程

    千次阅读 2019-05-18 17:47:47
    所有的进程都是由别的进程创建出来的,用鼠标双击运行一个程序的时候,实际上是由...进程的创建过程: 映射EXE文件 创建内核对象EPROCESS(一个进程对应一个EPROCESS) 映射系统DLL(ntdll.dll) 创建线程内核对象ET...
  • 进程创建过程

    千次阅读 2019-02-25 16:07:26
    进程创建时,调用do_fork函数来创建进程,那么和调度相关操作主要有两个,一个是sched_fork,这是对一个进程进行调度初始化,另外一个就是wake_up_new_task,这个是把刚刚创建的进程唤醒加入到调度器中...
  • 追踪Linux系统创建进程的过程,在实验楼虚拟中使用gdb调试工具进行调试
  •  linux创建进程的过程  系统允许一个进程创建新进程,新进程即为子进程,子进程还可以创建新的子进程,形成进程树结构模型。整个linux系统的所有进程也是一个树形结构。树根是系统自动构造的,即在内核态下...
  • 多进程编程---创建进程 头文件:#include<unistd.h> 创建一个新进程 :pid_t fork(void) 如果出错返回-1 fork 调用一次,两次返回,原来的进程返回新进程的pid(父进程) 新进程中返回0(子进程) ...
  • Linux进程的创建过程

    2020-12-03 17:20:34
    进程的产生极大地提高的cpu的利用率,进程是cpu的执行单元。cpu可以通过进程切换提高使用率。那么Linux的进程是如何创建的呢? 这里一副图,我们先看个大概: 1、首先,我们得知道,我们的进程准备要干什么,这就...
  • 本文主要介绍Linux内核创建一个新进程的过程,需要的朋友可以参考下。
  • 不管在什么系统中,所有的任务都是以进程为载体的,所以理解进程的创建对于理解操作系统的原理是非常重要的,本文是我在学习linux内核中所做的笔记,如有错误还请大家批评指正。注:我所阅读的内核版本是0.11。  ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,809
精华内容 3,523
关键字:

创建进程的过程