MySlide Process
MySlide Process
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 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
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 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);
}