1 / 18

Linux kernel internals

Linux kernel internals. Introduction to process descriptors. Upon entering the kernel…. A user process will enter ‘kernel-mode’: When it decides to execute a system-call When it is interrupted (e.g. by the timer) When ‘exception’ occurs (e.g. divide by 0). Switch to kernel-mode stack.

Download Presentation

Linux kernel internals

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Linux kernel internals Introduction to process descriptors

  2. Upon entering the kernel… A user process will enter ‘kernel-mode’: • When it decides to execute a system-call • When it is interrupted (e.g. by the timer) • When ‘exception’ occurs (e.g. divide by 0)

  3. Switch to kernel-mode stack • Entering kernel involves a stack-switch • Necessary for robustness: e.g., user-mode stack might be exhausted • Desirable for security: e.g, illegal parameters might be supplied

  4. Location of user-mode stack • Each task has a private user-mode stack • The user-mode stack grows downward from the highest address in user space (i.e., 0xBFFFFFFF) • A program’s exit-address is on user stack • Command-line arguments on user stack • Environment variables on user stack • Upon entering ‘main()’:

  5. What’s on the user stack? Upon entering ‘main()’: • A program’s exit-address is on user stack • Command-line arguments on user stack • Environment variables are on user stack During execution of ‘main()’: • Function parameters and return-addresses • Storage locations for ‘automatic’ variables

  6. What’s on the kernel stack? Upon entering kernel-mode: • task’s registers are saved on kernel stack (e.g., address of task’s user-mode stack) During execution of kernel functions: • Function parameters and return-addresses • Storage locations for ‘automatic’ variables

  7. And also something else! • Linux uses part of a task’s kernel-stack to store that task’s ‘process descriptor’ • The stack and descriptor are overlayed: union task_union { unsigned long stack[ 2048 ]; struct task_struct task; };

  8. Union of descriptor and stack Room here for stack to expand as needed Kernel-mode stack 8K Process descriptor

  9. The kernel is ‘task manager’ • So each task has a ‘process descriptor’: struct task_struct { volatile long state; unsigned long flags; int sigpending; mm_segment_t addr_limit; /* plus many other fields */ };

  10. The ‘task_union’ object • Linux stores stack with process descriptor • It allocates 8KB to these combined objects • Task’s process descriptor is 1696 bytes • So kernel stack can grow to about 6.5KB 8192 bytes – 1696 bytes = 6496 bytes • Each ‘task_union’ object is ‘8KB-aligned’

  11. Finding the descriptor info • During task-execution in kernel-mode: • It’s quick for a process to find its descriptor by using two assembly-language instructions: movl %esp, %ebx andl $0xFFFFE000, %ebx (Now %ebx = descriptor’s base-address)

  12. The ‘current’ process • Kernel-headers define useful macros • static inline struct task_struct * get_current( void ) { struct task_struct *current; __asm__( “ andl %%esp, %0 ; “ \ : “=r” (current) : “0” (~0x1FFF) ); return current; } • #define current get_current()

  13. Parenthood • New tasks get created by calling ‘fork()’ • Old tasks get terminated by calling ‘exit()’ • When ‘fork()’ is called, two tasks return • One task is known as the ‘parent’ process • And the other is called the ‘child’ process • The kernel keeps track of this relationship

  14. A parent can have many children • If a user task calls ‘fork()’ twice, that will create two distinct ‘child’ processes • These children are called ‘siblings’ • Kernel keeps track of all this with pointers struct task_struct *p_ptr, // parent *p_cptr, // youngest child *p_ysptr, // younger sibling *p_osptr, // older sibling

  15. Parenthood relationbships P1 P2 P3 P4 P5 See “Linux Kernel Programming” (Chapter 3) for additional details

  16. The kernel’s ‘process-list’ • Kernel keeps a list of process descriptors • A ‘doubly-linked’ circular list is used • The ‘init_task’ serves as a fixed header • Other tasks inserted/deleted dynamically • Tasks have forward & backward pointers: struct task_struct *next_task; struct task_struct *prev_task;

  17. Doubly-linked circular list next_task init_task (pid=0) newest task … prev_task

  18. Tasks have ’states’ • From kernel-header: <linux/sched.h> • #define TASK_RUNNING 0 • #define TASK_INTERRUPTIBLE 1 • #define TASK_UNINTERRUPTIBLE 2 • #define TASK_ZOMBIE 4 • #define TASK_STOPPED 8

More Related