Linux內核學習筆記(2)-- 父進程和子進程及它們的訪問方法

  Linux系統中,進程之間有一個明顯的繼承關係,全部進程都是 PID 爲1的 init 進程的後代。內核在系統啓動的最後階段啓動 init 進程。該進程讀取系統的初始化腳本(initscript)並執行其餘的相關程序,最終完成系統啓動的整個過程。linux

  系統中每一個進程必有一個父進程,相應的,每一個進程也能夠由零個或者多個子進程。擁有同一個父進程的全部進程被稱爲兄弟。進程之間的關係存放在進程描述符 task_struct 中。每一個 task_struct 都包含一個指向其父進程 task_struct 的指針 parent,還有一個被稱爲 children 的子進程鏈表。函數

 

1、父進程的訪問方法this

  對於當前進程,可使用下面代碼訪問其父進程,得到其進程描述符:spa

struct task_struct *my_parent = current -> parent;

   其中,current 是一個宏,在 linux/asm-generic/current.h中有定義:指針

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __ASM_GENERIC_CURRENT_H
#define __ASM_GENERIC_CURRENT_H

#include <linux/thread_info.h>

#define get_current() (current_thread_info()->task)
#define current get_current()

#endif /* __ASM_GENERIC_CURRENT_H */

  而 current_thread_info() 函數在 arch/arm/include/asm/thread_info.h 中有定義:code

/*
 * how to get the thread information struct from C
 */
static inline struct thread_info *current_thread_info(void) __attribute_const__;

static inline struct thread_info *current_thread_info(void)
{
    return (struct thread_info *)
        (current_stack_pointer & ~(THREAD_SIZE - 1));        // 讓SP堆棧指針與棧底對齊    
}    

   能夠看到,current 其實是指向當前執行進程的 task_struct 指針的。orm

 

2、子進程的訪問方法blog

  可使用如下方法訪問子進程:繼承

struct task_struct *task;
struct list_head *list;

list_for_each(list,&current->children){
    task = list_entry(list,struct task_struct,sibling);      
}

  能夠看到,這裏使用的是鏈表相關的操做來訪問子進程。咱們知道, task_struct 是存放在一個雙向循環鏈表 task_list(任務隊列)中的,而一個 task_struct 包含了一個具體進程的全部信息,所以,咱們只須要找到子進程的 task_struct 便可以訪問子進程了,上面代碼就是這麼作的。那麼,具體是如何找到子進程的進程描述符 task_struct的呢?下面對上面的代碼進行詳細分析:隊列

  list_head: 在 linux/types.h 中定義

struct list_head{
    struct list_head *next,*prev;  
};

  顯然,list_head 其實就是一個雙向鏈表,並且通常來講,都是雙向循環鏈表。

 

  list_for_each: 在linux/list.h 中定義

#define list_for_each(pos, head) \
    for (pos = (head)->next; pos != (head); pos = pos->next)

  這是一個宏定義。其中,pos 是指向 list_head 的指針,而 head 是雙鏈表 list_head 中的指針,定義了從哪裏開始遍歷這個鏈表。這個宏的做用就是對一個雙向循環鏈表進行遍歷。

 

  list_entry: 在 linux/list.h 中定義,也是一個宏定義

/**
 * list_entry - get the struct for this entry
 * @ptr:    the &struct list_head pointer.
 * @type:    the type of the struct this is embedded in.
 * @member:    the name of the list_head within the struct.
 */
#define list_entry(ptr, type, member) \
    container_of(ptr, type, member)

  list_entry 實際上就是 container_of。

 

  container_of : 在 linux/kernel.h 中定義

/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:    the pointer to the member.
 * @type:    the type of the container struct this is embedded in.
 * @member:    the name of the member within the struct.
 *
 */
#define container_of(ptr, type, member) ({                \
    void *__mptr = (void *)(ptr);                    \
    BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&    \
             !__same_type(*(ptr), void),            \
             "pointer type mismatch in container_of()");    \
    ((type *)(__mptr - offsetof(type, member))); })

  container_of 實現了根據一個結構中的一個成員變量的指針來獲取指向整個結構的指針的功能。其中,offsetof 也是一個宏,它的功能是得到成員變量基於其所在結構的地址的偏移量,定義以下:

#define offsetof(TYPE,MEMBER)  ((size_t) &((TYPE *)0) -> MEMBER)        // 得到成員變量member基於其所在結構的地址的偏移量,該宏在 linux/stddef.h 中有定義

  分析一下 offsetof 宏:

1)、((TYPE *) 0) : 將 0 轉換成 TYPE 類型的指針。這聲明瞭一個指向 0 的指針,且這個指針是 TYPE 類型的;

2)、((TYPE *) 0) -> MEMBER: 訪問結構中的成員MEMBER,一個指向 0 的 TYPE 類型的結構;顯然,MEMBER 的地址就是偏移地址;

3)、&((TYPE *) 0) -> MEMBER :取數據成員MEMBER的地址(不是按位與,不要看錯了);

4)、((size_t) &((TYPE *) 0) -> MEMBER): 強制類型轉換成 size_t 類型。 

相關文章
相關標籤/搜索