You are on page 1of 34

Process Management

Processes and threads


• A process is a program (object code stored on
some media) in execution.
– A program itself is not a process; a process is an
active program and related resources.
• Threads are the objects of activity within the
process.
– To Linux, a thread is just a special kind of process.
– The clone system call – creating a thread
System calls (Linux)
• fork() & clone()
– to create a process/thread
• exec()
– to create a new address space and load a new
program into it.
• exit()
• wait4()
– to enable a process to wait for the termination of
a specific process
Process control block
• The process descriptor (task_struct) contains
all the information about a specific process.
task_struct and thread_info
• The task_struct structure is allocated via the
slab allocator to prevent memory
fragmentation
• struct thread_info, was created and it lives at
the bottom of the stack
Identifying the current process
• current is calculated by masking out the 13
(depends on the stack size) least significant
bits of the stack pointer to obtain the
thread_info structure.
8KB
Process State

The process
becomes runnable
if it receives a
signal.

the task does not


respond to signals
in this state
Process Context
• Normal program execution occurs in user-
space.
• When a program executes a system call or
triggers an exception (e.g., segmentation
fault), it enters kernel-space.
– the kernel is said to be "executing on behalf of the
process" and is in process context.

Interrupt context, on the other hand, is not


associated with a process.
The Process Family Tree

All processes are


descendants of the init
process, whose PID is 1.
The task list
for_each_process(task) {
/* this pointlessly prints the name and PID of each
task */
printk("%s[%d]\n", task->comm, task->pid);
}
fork, vfork, clone
int sys_fork(struct pt_regs *regs)
{
return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
}
int sys_vfork(struct pt_regs *regs)
{
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0,
NULL, NULL);
}
sys_clone(unsigned long clone_flags, unsigned long newsp,
void __user *parent_tid, void __user *child_tid, struct pt_regs *regs)
{
if (!newsp)
newsp = regs->sp;
return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
}
do_fork
long do_fork(unsigned long clone_flags,
unsigned long stack_start,
struct pt_regs *regs,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)
• clone_flags: A flag set to specify duplication properties.
• stack_start: The start address of the user mode stack to
be used.
• regs: holding all registers in the order in which they are saved
on the parent’s kernel stack when a system call is executed
• parent_tidptr and child_tidptr: two pointers to addresses in
userspace that hold the TIDs of the parent and child processes.
Code flow diagram for do_fork
copy_process
flags (CLONE_XXX & copy_XXX)
flags (CLONE_XXX & copy_XXX)
Kernel Threads
• kernel threads do not have an address space
(in fact, their mm pointer is NULL).
• Kernel threads are, however, schedulable and
preemptable as normal processes.
– Example: pdflush task and the ksoftirqd task.
• A kernel thread can be created only by
another kernel thread.
– int kernel_thread(int (*fn)(void *), void * arg,
unsigned long flags)
Note: pdflush

• Linux usually writes data out of the page


cache using a process called pdflush.
• At any moment, between 2 and 8 pdflush
threads are running on the system.
• You can monitor how many are active by
looking at /proc/sys/vm/nr_pdflush_threads.
Note: ksoftirqd

• ksoftirqd is used to process deferrable “driver


functions.”
Starting New Programs

• New programs are started by replacing an


existing program with new code.

• Linux provides the execve system call for this


purpose
• execve() ->...->sys_execve() -> do_execve()

<-user mode----><-kernel mode------------->


do_execve
int do_execve(char * filename,
char __user *__user *argv,
char __user *__user *envp,
struct pt_regs * regs)

• filename: the executable file


• argv & envp: The argument vector and environment
• regs: holding all registers in the order in which they are
saved on the kernel stack when the system call is
executed
Note: __user
• The kernel uses __user to identify pointers to
areas in user address space
• The kernel needs to ensure that the page frame
in RAM that backs the destination is actually
present
Reference:
• /include/linux/compiler.h
• http://www.linuxjournal.com/article/7272
Code flow diagram for
do_execve
bprm_init
1. call mm_alloc to generate a new instance of
mm_struct to manage the process address
space.
2. call init_new_context to initial architecture-
specific functions that initializes the
process/program
3. call bprm_mm_init to set up an initial stack.
Prepare_binprm
• int prepare_binprm(struct
linux_binprm *bprm)
• Various parameters of the new process are,
for the sake of simplicity, combined into a
structure of type linux_binprm (that is bprm).
including:
– a number of parent process values
– SUID and SGID bits
search_binary_handler

• search_binary_handler is used at the end of


do_execve to find a suitable binary format for
the particular file.

• each format can be recognized by reference to


special characteristics (usually a ‘‘magic
number‘‘ at the beginning of the file).
Note: Magic number

• Compiled Java class files (bytecode) start with


hex 0xCAFEBABE. When compressed with
Pack200 the bytes are changed to
0xCAFED00D.
Note: Magic number
shiwulo@shiwulo-laptop:/bin$ readelf -h ls
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little
endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-
64
Version: 0x1
Entry point address: 0x4026e0
Start of program headers: 64 (bytes into file)
Start of section headers: 112176 (bytes into file)

http://www.linuxjournal.com/article/1060
search_binary_handler
• It releases all resources used by the old
process.
• It maps the application into virtual address
space.
– text, pre-initialized data, heap, stack
• It sets the instruction pointer of the process
and some other architecture-specific registers
Note: Interpreting Binary Formats
<binfmts.h>
struct linux_binfmt {
struct linux_binfmt * next;
struct module *module;
int (*load_binary)
(struct linux_binprm *, struct pt_regs * regs);
int (*load_shlib)
(struct file *);
int (*core_dump)
(long signr, struct pt_regs * regs, struct file * file);
unsigned long min_coredump; /* minimal dump size */
};
Process termination
1. set the PF_EXITING flag in the flags member
of the task_struct.
2. calls del_timer_sync() to remove any kernel
timers (that are software timers).
3. calls __exit_mm() to release the mm_struct
4. calls exit_sem(). If the process is queued
waiting for an IPC semaphore, it is dequeued
here.
Process termination
5. calls __exit_files(), __exit_fs(),
exit_namespace(), and exit_sighand() to
decrement the usage count of objects
6. sets the task's exit code, stored in the
exit_code member of the task_struct
7. calls exit_notify() to send signals to the task's
parent
8. calls schedule()
Removal of the Process Descriptor

After the parent has obtained information on its


terminated child (by invoking wait4), or signified
to the kernel that it does not care, the child's
task_struct is deallocated.
Summary
• how Linux stores and represents processes
(with task_struct and thread_info),
• how processes are created (via clone() and
fork()),
• how new executable images are loaded into
address spaces (via the exec()),
• how parents gather information about their
children (via the wait4())

You might also like