0% found this document useful (0 votes)
24 views43 pages

MySlide Process

Linux organizes processes using process descriptors stored in kernel memory. Each process is represented by a task_struct containing state, scheduling, and other information. Process descriptors are linked together using doubly linked lists for different process states like running, waiting, stopped etc. Process IDs are mapped to descriptors using a hash table for efficient lookup. Parent-child relationships are tracked to form process tree structures. Context switching occurs by saving/restoring process contexts during state transitions.

Uploaded by

Juan Ignacio
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
24 views43 pages

MySlide Process

Linux organizes processes using process descriptors stored in kernel memory. Each process is represented by a task_struct containing state, scheduling, and other information. Process descriptors are linked together using doubly linked lists for different process states like running, waiting, stopped etc. Process IDs are mapped to descriptors using a hash table for efficient lookup. Parent-child relationships are tracked to form process tree structures. Context switching occurs by saving/restoring process contexts during state transitions.

Uploaded by

Juan Ignacio
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 43

Linux Internals: Process

and Process Management


System Structure
Processes

System calls interface

File systems Central kernel


ext2fs xiafs proc
Task management
minix nfs msdos Scheduler
iso9660 Signals
Loadable modules
Buffer Cache Memory management

Peripheral managers
Network Manager
block character
ipv4
sound card cdrom isdn ethernet
netwo ...
scsi pci
rk

Machine interface

Machine
Linux Kernel Architecture
Entering Kernel Mode
A user process will enter kernel-mode
z When it decides to execute a system-call

z When it is interrupted (e.g. by the timer)

z When ‘exception’ occurs (e.g. divide by 0)


Switching to Kernel Stack
z Entering kernel involves a stack-switch
z Necessary for robustness
z Ex. user-mode stack might be exhausted
z Desirable for security
z Ex. illegal parameters might be supplied
Location of User-mode Stack

z Each task has a private user-mode stack


z The user-mode stack grows downward
from the highest address in user space
z From (0xBFFFFFFF), top 1 GB reserved for kernel
space
What’s on the User Stack?
Upon entering ‘main()’:
z A program’s exit-address is on user stack

z Command-line arguments on user stack

z Environment variables are on user stack

During execution of ‘main()’:


z Function parameters and return-addresses

z Storage locations for local variables


What’s on the Kernel Stack?
Upon entering kernel-mode:
z task’s registers are saved on kernel stack

(e.g., address of task’s user-mode stack)

During execution of kernel functions


z Function parameters and return addresses

z Storage locations for local variables


Outline of Things to Come
Now

z Process Descriptors
z Identifying the Current Process
z Process States
z Process Lists and management
z Context Switch
Process Descriptors
Linux Processes
z Each process is represented by a task_struct data
structure, containing:
z Process State
z Scheduling Information
z Identifiers
z Inter-Process Communication
z Times and Timers
z File system
z Virtual memory
z Processor Specific Context
z Others…
z This is the generic PCB we studied earlier…
z In /include/linux/sched.h
List of Processes: Doubly Linked
List
task_struct: Some Fields
z state: process state
z thread_info: low-level information for the process
z mm: pointers to memory area descriptors
z tty: tty associated with the process
z fs: current directory
z files: pointers to file descriptors
z signal: signals received
z blocked: masked signals
z *next_task, *prev_task: links to next and previous tasks in the list of
tasks
z priority
z policy: scheduling policy for this process (sched_FIFO, sched_RR,
sched_others…)
z utime, stime, cutime, cstime, start_time: various time info
z Many other fields (total 100+)
Linux Process Descriptor
Where is the Descriptor
Stored?
z Linux uses part of a task’s kernel-stack to store that
task’s process descriptor
z Actually thread_info structure is stored which has a task filed that
points to the process descriptor
z The stack and descriptor are overlayed

union task_union {
unsigned long stack[INIT_THREAD_SIZE/sizeof(long) ];
struct thread_info task;
};
z Two pages (8KB assuming 4KB page size)
allocated for stack and the thread_info structure
z Task’s process descriptor is 1696 bytes
z So kernel stack can grow to about 6.5KB
8192 bytes – 1696 bytes = 6496 bytes
z Each task_union object is ‘8KB-aligned’
Why is this done like this?
z Identifying current process is now easy
z Linked to esp: current stack pointer
z thread_info pointer = esp with lower 13 bits masked
z Obtain the address of thread_info structure from
the esp register
z AND the esp register value with 0xFFFFE000

movl %esp, %ebx


andl $0xFFFFE000, %ebx
(Now %ebx = thread_info’s base-address)
z 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()
Process State
Process State
z TASK_RUNNING (executing on CPU or runnable)
z TASK_INTERRUPTIBLE (waiting on a condition:
interrupts, signals and releasing resources may “wake”
process)
z TASK_UNINTERRUPTIBLE (Sleeping process cannot be
woken by a signal)
z TASK_STOPPED (stopped process e.g., by a SIGSTOP)
z EXIT_ZOMBIE (terminated before waiting for parent)
z EXIT_DEAD (terminated)
Process State

creation stopped
signal signal

termination
Zombie/
ready scheduling executing
Dead

input / output
end of
input / output suspended
Identifying and Retrieving
Processes
Identifying a Process
z Process descriptor pointers: 32-bit
z Process ID (PID): 16-bit (~32767 for compatibility)
z Each process, or independently scheduled execution
context, has its own process descriptor
z Programmers expect threads in the same group to
have a common PID
z Thread group: a collection of LWPs (Light Weight
Processes)
z The PID of the first LWP in the group is the process
id returned for all threads in the group
z tgid field in process descriptor: using getpid()
system call
Parenthood
z New tasks get created by calling ‘fork()’
z Process 0 and 1: created by the kernel
z Process 1 (init): the ancestor of all processes
z Old tasks get terminated by calling ‘exit()’
z When ‘fork()’ is called, two tasks return
z One task is known as the ‘parent’ process
z And the other is called the ‘child’ process
z The kernel keeps track of this relationship
Parenthood Relationships among
Processes
z Process 0 and 1: created by the kernel
z Process 1 (init): the ancestor of all processes
z Fields in process descriptor for parenthood
relationships
z real_parent
z parent
z children
z sibling
Parenthood Relationships among
Five Processes
pidhash Table and Chained Lists
z User gives pid, need to map to process descriptor
z Sequential search in the process list by pid is inefficient
z PIDs are converted to matching process descriptors
using a hash function.
z A pidhash table maps PID to descriptor.

z Collisions are resolved by chaining.


z find_task_by_pid()searches hash table and
returns a pointer to a matching process descriptor or
NULL.
A Simple Example PID Hash Table
and Chained Lists
z The pid_hash array contains four hash tables
and corresponding field in the process descriptor
z pid: PIDTYPE_PID
z tgid: PIDTYPE_TGID (thread group leader)
z pgrp: PIDTYPE_PGID (group leader)
z session: PIDTYPE_SID (session leader)
z Chaining is used to handle PID collisions
z Size of each pidhash table: dependent on the
available memory
z pids field of the process descriptor: the pid data
structures
z nr: PID number
z pid_chain: links to the previous and the next elements
in the hash chain list
z pid_list: head of the per-PID list (in thread group)
The PID Hash Tables
Different Process Lists
How Processes are Organized
z Processes in TASK_STOPPED, EXIT_ZOMBIE,
EXIT_DEAD: not linked in lists
z Processes in TASK_RUNNING: run queue
z Processes in TASK_INTERRUPTABLE,
TASK_UNINTERRUPTABLE: wait queues
z Two kinds of sleeping processes
z Exclusive process
z Nonexclusive process: always woken up by the kernel
when the event occurs
The Runqueue
z Processes are scheduled for execution from a doubly-
linked list of TASK_RUNNING processes, called the
runqueue.
z prev_run & next_run fields of process descriptor are used to
build runqueue.
z init_task heads the list.
z add_to_runqueue(), del_from_runqueue(),
move_first_runqueue(), move_last_runqueue()
functions manipulate list of process descriptors.
z NR_RUNNING macro stores number of runnable processes.
z wake_up_process() makes a process runnable.

z QUESTION: Is a doubly-linked list the best data


structure for a run queue?
z Linux 2.6 implements the runqueue differently
z To achieve scheduler speedup, Linux 2.6 splits the runqueue into
140 lists of each priority!
z array field of process descriptor: pointer to the prio_array_t data
structure
z nr_active: # of process descriptors in the list
z bitmap: priority bitmap

z queue: the 140 list_heads


z enqueue_task(p, array), dequeue_task(p, array)
Wait Queues

z TASK_(UN)INTERRUPTIBLE processes are


grouped into classes that correspond to specific
events.
z e.g., timer expiration, resource now available.
z There is a separate wait queue for each class / event.
z Processes are “woken up” when the specific event
occurs.
Wait Queues
z struct _ _wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct _ _wait_queue_head wait_queue_head_t;

z struct _ _wait_queue {
unsigned int flags;
struct task_struct * task;
wait_queue_func_t func;
struct list_head task_list;
};
typedef struct _ _wait_queue wait_queue_t;
Wait Queue Example
void sleep_on(wait_queue_head_t *wq)
{ wait_queue_t wait;
init_waitqueue_entry = wait, current);
current->state = TASK_UNINTERRUPTIBLE;
add_wait_queue(wq, &wait)
schedule();
Remove_wait_queue(wq, &wait);
}

•sleep_on() inserts the current process, P, into the specified wait


queue and invokes the scheduler.
•When P is awakened it is removed from the wait queue.
Process Resource Limits
z RLIMIT_AS
z RLIMIT_CORE
z RLIMIT_CPU
z RLIMIT_DATA
z RLIMIT_FSIZE
z RLIMIT_LOCKS
z RLIMIT_MEMLOCK
z RLIMIT_MSGQUEUE
z RLIMIT_NOFILE
z RLIMIT_NPROC
z RLIMIT_RSS
z RLIMIT_SIGPENDING
z RLIMIT_STACK
Miscelleneous
Kernel Threads
z Some (background) system processes run only in kernel
mode.
z e.g., flushing disk caches, swapping out unused page frames.
z Can use kernel threads for these tasks.
z Ex.
z Process 0 (swapper process), the ancestor of all processes
z Process 1 (init process)
z Others: keventd, kapm, kswapd, kflushd (also bdflush),
kupdated, ksoftirqd
z Kernel threads only execute kernel functions – normal
processes execute these fns via syscalls.
z Kernel threads only execute in kernel mode as opposed
to normal processes that switch between kernel and user
modes.
Process Termination
z Usually occurs when a process calls exit().
z Kernel can determine when to release resources owned by
terminating process.
z e.g., memory, open files etc.
z do_exit() called on termination, which in turn calls
__exit_mm/files/fs/sighand() to free appropriate
resources.
z Exit code is set for terminating process.
z exit_notify() updates parent/child relationships: all
children of terminating processes become children of
init process.
z schedule() is invoked to execute a new process.

You might also like