* 本文的系统调用的分析基于ARM体系结构
* CrossTool:gcc-3.4.5,libc库:glibc-2.3.6
* 本文的内容均来自arm交叉编译工具链目录下的相关头文件

linux中,进程和线程对内核而言都被看作任务,平等参与调度。本文深入追踪讨论几种创建任务的用户态函数:
fork、vfork、clone、pthread_create,通过这几个函数分析,了解arm体系结构下系统调用的方法,
最终目的是深入讨论内核中进程管理的部分。

用户接口介绍:
fork:
    #include <sys/types.h>
    #include <unistd.h>
   
    pid_t fork(void);
    ********* sys/types.h ********
    #ifndef __pid_t_defined
    typedef __pid_t pid_t;
    # define __pid_t_defined
    #endif
    ********* unistd.h ***********
    /* Clone the calling process, creating an exact copy.
       Return -1 for errors, 0 to the new process,
       and the process ID of the new process to the old process.  */
    extern __pid_t fork (void) __THROW;
    __THROW意思是使用该fork函数将会抛出一个异常,下同
    ******************************
   
vfork:
    #include <sys/types.h>
    #include <unistd.h>
   
    pid_t vfork(void);
    ********* sys/types.h ********
    #ifndef __pid_t_defined
    typedef __pid_t pid_t;
    # define __pid_t_defined
    #endif
    ********* unistd.h ***********
    #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED
    /* Clone the calling process, but without copying the whole address space.
       The calling process is suspended(唤醒) until the new process exits or is
       replaced by a call to `execve'.  Return -1 for errors, 0 to the new process,
       and the process ID of the new process to the old process.  */
    extern __pid_t vfork (void) __THROW;
    #endif /* Use BSD. */
    ******************************
    ++++ fork和vfork的区别 ++++
    fork创建一个子进程时,将会创建一个新的地址空间,并且要拷贝父进程的资源,但是往往在子进程中会执行
    exec调用,那这样前面的拷贝动作就有点多余了。这种情况下vfork就出现了,它和fork一样都创建一个子进程,
    但是它并部将父进程的地址空间完全复制到子进程中,同时在子进程退出或者调
    用exec之前,父进程是阻塞的,因为此时子进程使用的是父进程的地址空间。也意味这vfork会保证子进程先
    运行,但是如果调用该函数后子进程依赖父进程的进一步执行动作,则会导致系统死锁。
    同时子进程在vfork返回后直接运行在父进程的地址空间,并使用父进程的内存和堆栈空间,可能会破坏
    父进程的运行环境导致父进程崩溃。
    ++++++++++++++++++++++++++
   
clone:
    #define _GNU_SOURCE
  #include <bits/sched.h>
   
    __BEGIN_DECLS
    /* Clone current process.  */
    #ifdef __USE_MISC
    extern int clone (int (*__fn) (void *__arg), void *__child_stack, int __flags, void *__arg) __THROW;
    #endif
    __END_DECLS
   
    #ifdef __USE_MISC
    /* Cloning flags.  */
    # define CSIGNAL       0x000000ff /* Signal mask to be sent at exit.  */
    指定子进程结束时发送到父进程的信号编号,通常选择SIGCHLD信号
   
    # define CLONE_VM      0x00000100 /* Set if VM shared between processes.  */
    进程间共享内存描述符和所有的页表
   
    # define CLONE_FS      0x00000200 /* Set if fs info shared between processes.  */
    共享根目录, 当前目录, 创建文件初始权限
   
    # define CLONE_FILES   0x00000400 /* Set if open files shared between processes.  */
    进程间共享打开的文件
   
    # define CLONE_SIGHAND 0x00000800 /* Set if signal handlers shared.  */
    共享信号处理句柄,阻塞和悬挂的信号。如果这个标识为真,那么CLONE_VM必须也被设置为真
   
    # define CLONE_PTRACE  0x00002000 /* Set if tracing continues on the child.  */
    如果创建进程可被跟踪,那么该标识表明父进程也希望子进程能被跟踪
   
    # define CLONE_VFORK   0x00004000 /* Set if the parent wants the child to wake it up on mm_release.  */
    CLONE_VFORK标志设置时,子进程运行时会使父进程投入睡眠,直到子进程不再使用父进程的内存或者子进程退出去才会将父进程唤醒。
    这样做是因为父子进程共享同一个地址区域
   
    # define CLONE_PARENT  0x00008000 /* Set if we want to have the same parent as the cloner.  */
    表明创建进程与子进程是兄弟进程(同父)
   
    # define CLONE_THREAD  0x00010000 /* Set to add to same thread group.  */
    将孩子进程插入同一个父进程的线程组,强制它共享父进程的信号描述符。如果该标识被设置,CLONE_SIGHAND也必须被设置才有意义
   
    # define CLONE_NEWNS   0x00020000 /* Set to create new namespace.  */
    表明clone出来的子进程需要自己的名字空间,也就是说,需要对挂载的文件系统需要自己的视角来操作,不要同时指定CLONE_NEWNS和CLONE_FS
   
    # define CLONE_SYSVSEM 0x00040000 /* Set to shared SVID SEM_UNDO semantics.  */
    共享System V 进程间通信方式:undoable信号量的操作
   
    # define CLONE_SETTLS  0x00080000 /* Set TLS info.  */
    为线程(轻量级进程)创建一个新的TLS(线程局部存储)段。该段被参数tls指向的结构体所描述。TLS只是对全局量和静态变量才有意义,局部量存在于具体线程的堆栈上。
   
    # define CLONE_PARENT_SETTID 0x00100000 /* Store TID in userlevel buffer before MM copy.  */
    将子进程的PID写到由ptid参数指向的父进程用户态的变量
   
    # define CLONE_CHILD_CLEARTID 0x00200000 /* Register exit futex and memory location to clear.  */
    如果存在该标识,当子进程将要退出或者是将要执行一个新的程序时就会触发内核启动一种机制,在这种情况下,内核会清除由ctid参数指向的用户态变量TID,
    同时唤醒任意一个等待该事件(子进程死亡)的进程。
   
    # define CLONE_DETACHED 0x00400000 /* Create clone detached.  */
    遗留标识,会被内核忽略
   
    # define CLONE_UNTRACED 0x00800000 /* Set if the tracing process can't force CLONE_PTRACE on this clone.  */
    内核设置,覆盖CLONE_PTRACE标识的值(用来内核线程的跟踪禁止)
   
    # define CLONE_CHILD_SETTID 0x01000000 /* Store TID in userlevel buffer in the child.  */
    子进程的PID写入到有ctid参数指向的子进程的用户模式变量
   
    # define CLONE_STOPPED    0x02000000 /* Start in stopped state.  */
    强制子进程在TASK_STOPPED状态开始运行
    #endif
   
    依赖定义关系:
    CLONE_THREAD <-- CLONE_SIGHAND <-- CLONE_VM
    定义前者,必须也定义后者才有意义。
    在linux内核include/linux/sched.h头文件中,同样存在这上述flags一样的定义,只是多了下面一些宏定义而已:
    #define CLONE_NEWUTS                    0x04000000                /* New utsname group? */
    #define CLONE_NEWIPC                    0x08000000                /* New ipcs */
    #define CLONE_NEWUSER                    0x10000000                /* New user namespace */
    #define CLONE_NEWPID                    0x20000000                /* New pid namespace */
    #define CLONE_NEWNET                    0x40000000                /* New network namespace */
    #define CLONE_IO                            0x80000000                /* Clone io context */
   
   
pthread_create:
    linux内核只提供来轻量级进程的支持,未实现线程模型。实际上linux用一个轻量级进程对应一个线程,
    将线程和进程全部当作任务来调度。linux中所谓的“线程”只是在被创建的时候“克隆”(clone)了父进程的资源,
    因此,clone 出来的进程表现为“线程”。目前linux中最流行的线程机制为LinuxThreads,
    所采用的就是线程-进程“一对一”模型,调度交给核心 , 而在用户级实现一个包括信号处理在内的线程管理机制。
    LinuxThreads由 Xavier Leroy负责开发完成,并已绑定在GLIBC中发行,它实现了一种BiCapitalized面向
    linux的Posix 1003.1c“pthread”标准接口。Linuxthread可以支持 Intel、Alpha、MIPS 等平台上的多处理器系统。
  按照POSIX 1003.1c标准编写的程序与Linuxthread库相链接即可支持linux平台上的多线程,
  在程序中需包含头文件pthread.h,在编译链接加上-Ipthread
   
    #include <pthread.h>
    /* Create a thread with given attributes ATTR (or default attributes
       if ATTR is NULL), and call function START_ROUTINE with given
       arguments ARG.  */
      extern int pthread_create (pthread_t *__restrict __threadp,
                   __const pthread_attr_t *__restrict __attr,
                   void *(*__start_routine) (void *),
                   void *__restrict __arg) __THROW;

Logo

更多推荐