linux-kernel - `task_struct` 和 `pid_namespace` 之间有什么关系?

标签 linux-kernel scheduled-tasks scheduler linux-namespaces

我正在研究一些内核代码并试图了解数据结构是如何链接在一起的。我知道调度程序如何工作的基本概念,以及 PID 是什么。但是我不知道在这种情况下命名空间是什么,也无法弄清楚所有这些是如何协同工作的。

我已经阅读了一些解释(包括 O'Reilly “Understanding the Linux Kernel”的部分内容)并理解可能是同一个 PID 进入了两个进程,因为一个进程已经终止并且 ID 被重新分配。但我无法弄清楚这一切是如何完成的。

所以:

  • 在这种情况下,什么是命名空间?
  • task_struct 之间有什么关系?和 pid_namespace ? (我已经认为它与 pid_t 有关,但不知道如何)

  • 一些引用资料:
  • pid_namespace 的定义
  • task_struct 的定义
  • upid 的定义(另见 pid 正下方)
  • 最佳答案

    也许这些链接可能会有所帮助:

  • PID namespaces in operation
  • A brief introduction to PID namespaces (this one comes from a sysadmin)

  • 通过第二个链接后,很明显命名空间是隔离资源的好方法。在包括 Linux 在内的任何操作系统中,进程都是最重要的资源之一。用他自己的话说

    Yes, that’s it, with this namespace it is possible to restart PID numbering and get your own “1″ process. This could be seen as a “chroot” in the process identifier tree. It’s extremely handy when you need to deal with pids in day to day work and are stuck with 4 digits numbers…



    因此,您可以创建自己的私有(private)流程树,然后将其分配给特定用户和/或特定任务。在这棵树中,进程不必担心 PID 与“容器”外的 PID 冲突。因此,这与将这棵树完全交给不同的“根”用户一样好。这位好人已经做了一个很棒的工作,用一个很好的小例子来解释这些事情,所以我不会在这里重复。

    就内核而言,我可以为您提供一些指导以帮助您入门。我不是这里的专家,但我希望这对您有所帮助。

    此 LWN article ,描述了查看 PID 的旧方法和新方法。用它自己的话来说:

    All the PIDs that a task may have are described in the struct pid. This structure contains the ID value, the list of tasks having this ID, the reference counter and the hashed list node to be stored in the hash table for a faster search. A few more words about the lists of tasks. Basically a task has three PIDs: the process ID (PID), the process group ID (PGID), and the session ID (SID). The PGID and the SID may be shared between the tasks, for example, when two or more tasks belong to the same group, so each group ID addresses more than one task. With the PID namespaces this structure becomes elastic. Now, each PID may have several values, with each one being valid in one namespace. That is, a task may have PID of 1024 in one namespace, and 256 in another. So, the former struct pid changes. Here is how the struct pid looked like before introducing the PID namespaces:

    struct pid {
     atomic_t count;                          /* reference counter */
     int nr;                                  /* the pid value */
     struct hlist_node pid_chain;             /* hash chain */
     struct hlist_head tasks[PIDTYPE_MAX];    /* lists of tasks */
     struct rcu_head rcu;                     /* RCU helper */
    };
    

    And this is how it looks now:

    struct upid {
       int nr;                            /* moved from struct pid */
       struct pid_namespace *ns;          /* the namespace this value
                                           * is visible in */
       struct hlist_node pid_chain;       /* moved from struct pid */
    };
    
    struct pid {
       atomic_t count;
       struct hlist_head tasks[PIDTYPE_MAX];
       struct rcu_head rcu;
       int level;                     /* the number of upids */
       struct upid numbers[0];
    };
    

    As you can see, the struct upid now represents the PID value -- it is stored in the hash and has the PID value. To convert the struct pid to the PID or vice versa one may use a set of helpers like task_pid_nr(), pid_nr_ns(), find_task_by_vpid(), etc.



    虽然有点过时,但这些信息足以让您入门。这里还有一个更重要的结构需要提及。是struct nsproxy .这个结构是所有事物命名空间相对于它所关联的进程的焦点。它包含一个指向 的指针。此进程的子进程将使用的 PID 命名空间 .当前进程的 PID 命名空间使用 task_active_pid_ns 找到。 .

    struct task_struct 内,我们有一个命名空间代理指针,恰本地称为 nsproxy ,它指向这个进程的 struct nsproxy结构体。如果您跟踪创建新流程所需的步骤,您可以找到 task_struct 之间的关系。 , struct nsproxystruct pid .

    Linux 中的新进程总是从现有进程中派生出来,然后使用 execve 替换它的镜像(或 exec 系列的类似功能)。因此,作为 do_fork 的一部分, copy_process被调用。

    作为复制父进程的一部分,会发生以下重要事情:
  • task_struct首先使用 dup_task_struct 复制.
  • 也使用 copy_namespaces 复制父进程的命名空间.这也创建了一个新的 nsproxy子结构,它的 nsproxy 指针指向这个新创建的结构
  • 对于非 INIT 进程(原始全局 PID 也就是启动时产生的第一个进程),PID使用 alloc_pid 分配结构它实际上为新的 fork 分配了一个新的 PID 结构。编辑过程。此函数的简短片段:
    nr = alloc_pidmap(tmp);
    if(nr<0)
       goto out_free;
    pid->numbers[i].nr = nr;
    pid->numbers[i].ns = tmp;
    

  • 这填充 upid通过给它一个新的 PID 以及它当前所属的命名空间来构建结构。

    进一步作为 copy process 的一部分函数,这个新分配的 PID 然后链接到相应的 task_struct通过函数pid_nr即它的全局 ID(从 INIT 命名空间中看起来是原始 PID nr)存储在字段 pid 中在 task_struct .

    copy_process 的最后阶段, task_struct 之间建立链接还有这个新的pid结构通过pid_link task_struct 内的字段通过函数attach_pid .

    它还有很多,但我希望这至少能给你一些先机。

    注意:我指的是最新的(截至目前)内核版本,即。 3.17.2.

    关于linux-kernel - `task_struct` 和 `pid_namespace` 之间有什么关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26779416/

    相关文章:

    c - Windows 中进程的最短保证时间是多少?

    c++ - 内存访问冲突的操作系统处理与内存写入冲突的处理

    c - 如何获取内核中一个线程的运行时间?

    autofac - 多个注册表 FluentScheduler

    playframework-2.0 - play 框架 2.1 - 调度异步任务

    coldfusion - 如何找出计划任务的下一次运行时间?

    c - 进程调度器

    linux - Linux 上的可清除内存区域

    linux - Linux Pipe命令是否需要一个进程来执行?

    ASP.NET 计划作业