目录
linux 5.10.8,本文以(上下文切换时,用户态task和内核task对fpu的load/store的区别)为主线
关于pthread和kthread的说明
pthread时os对外提供的POSIX接口,并不是linux的概念。用户态程序可以调用pthread的接口创建、运行和销毁用户态线程。在下面的内容中,用pthread表示用户态线程,用kthread表示内核线程。在linux中,用户态线程和内核线程都是用struct task_struct
表示的。
和kthread/pthread区别对待相关的数据结构
linux中的TCB是task_struct
,定义在文件./include/linux/sched.h
中,和调度时和kthread和pthread区别对待相关的域如下:
struct task_struct {
/* ... */
struct thread_info thread_info;
/* ... */
/* Per task flags (PF_*), defined further below: */
unsigned int flags;
/* ... */
struct mm_struct *mm;
struct mm_struct *active_mm;
/* ... */
}
/*
* Per process flags
*/
#define PF_IDLE 0x00000002 /* I am an IDLE thread */
#define PF_EXITING 0x00000004 /* Getting shut down */
#define PF_VCPU 0x00000010 /* I'm a virtual CPU */
#define PF_WQ_WORKER 0x00000020 /* I'm a workqueue worker */
#define PF_FORKNOEXEC 0x00000040 /* Forked but didn't exec */
#define PF_MCE_PROCESS 0x00000080 /* Process policy on mce errors */
#define PF_SUPERPRIV 0x00000100 /* Used super-user privileges */
#define PF_DUMPCORE 0x00000200 /* Dumped core */
#define PF_SIGNALED 0x00000400 /* Killed by a signal */
#define PF_MEMALLOC 0x00000800 /* Allocating memory */
#define PF_NPROC_EXCEEDED 0x00001000 /* set_user() noticed that RLIMIT_NPROC was exceeded */
#define PF_USED_MATH 0x00002000 /* If unset the fpu must be initialized before use */
#define PF_USED_ASYNC 0x00004000 /* Used async_schedule*(), used by module init */
#define PF_NOFREEZE 0x00008000 /* This thread should not be frozen */
#define PF_FROZEN 0x00010000 /* Frozen for system suspend */
#define PF_KSWAPD 0x00020000 /* I am kswapd */
#define PF_MEMALLOC_NOFS 0x00040000 /* All allocation requests will inherit GFP_NOFS */
#define PF_MEMALLOC_NOIO 0x00080000 /* All allocation requests will inherit GFP_NOIO */
#define PF_LESS_THROTTLE 0x00100000 /* Throttle me less: I clean memory */
#define PF_KTHREAD 0x00200000 /* I am a kernel thread */
#define PF_RANDOMIZE 0x00400000 /* Randomize virtual address space */
#define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */
#define PF_MEMSTALL 0x01000000 /* Stalled due to lack of memory */
#define PF_UMH 0x02000000 /* I'm an Usermodehelper process */
#define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_mask */
#define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */
#define PF_MEMALLOC_NOCMA 0x10000000 /* All allocation request will have _GFP_MOVABLE cleared */
#define PF_IO_WORKER 0x20000000 /* Task is an IO worker */
#define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */
#define PF_SUSPEND_TASK 0x80000000 /* This thread called freeze_processes() and should not be frozen */
flag
字段是task的标志位,标志位所有的信息如上所示。其中PF_KTHREAD
标志位置1表示task是一个kthread。
struct mm_struct
是记录用户虚拟地址空间的数据结构。对于内核线程,mm
为NULL
。由于内核线程之前可能是任何用户层进程在执行,故用户空间部分的内容本质上是随机的,内核线程决不能修改其内容,故将mm
设置为NULL
,同时如果切换出去的是用户进程,内核将原来进程的mm存放在新内核线程的active_mm
中,因为某些时候内核必须知道用户空间当前包含了什么。在linux的代码实现中,这个字段和fpu的load/store没有关系,只是和kthread和pthread的区别对待有关系。
thread_info
定义在./arch/x86/include/asm/thread_info.h
的结构如下。它的flag
字段设有32个标志位,如下所示。其中TIF_NEED_FPU_LOAD
标志位置1,当task被调度到,在返回用户态之前,或者kernel需要用到fpu时,fpu会被加载到cpu上。
struct thread_info {
unsigned long flags; /* low level flags */
u32 status; /* thread synchronous flags */
};
/*
* thread information flags
*