The Process
Process is the living result of running code.
Process include not just executing program code also open files, pending signals, internal kernel data, processor state, a memory address space with one or more memory mappings, one or more thread of execution, and a data section containing global variables
Threads are objects within process. It includes a unique program counter, process stack, set of process registers. The kernel schedules individual threads, not process.
In Linux, there is no difference between process and threads. A thread is just a special kind of process. Process provide two virtualization: a virtualized processor which give a illusion to process that it alone monopolizes the system,also the "Process Scheduling" and virtual memory which is "Memory Management".
Process Life
Life:fork()->exec()->exit().
Parent process calls fork(), new process created is the child.
fork() creates a child process that is a copy of the current task. It differs from the parent only in its PID, and its PPID(parents PID, which is set to the original process), and certain resources and statistics, such as pending signals, which are not inherited.
exec() creates new memory space and load a new program(executable) into it and begin executing.
exit() terminates the process and free all its resources.
Parents can get status of a terminated child via the wait4() system call.
The fork() system call return from kernel to user space for 2 times. Once in the parent process, which indicates parents resumes execution. Again in the child process, which indicates that child start execution.
Process Descriptor
Task Structure
Linux kernel stores list of process in a circular doubly linked list called the task list.
Each elements in the task list is a process descriptor of the type struct task_struct
Allocate the Process Descriptor
struct thread_info is created and lives at the end of of the process kernel stack. There is one pointer to the task_struct in thread_info elements.
`struct thread_info {
struct task_struct *task;
struct exec_domain *exec_domain;
__u32 flags;
__u32 status;
__u32 cpu;
int preempt_count;
mm_segment_t addr_limit;
struct restart_block restart_block;
void *sysenter_return;
int uaccess_err;
};`
Consequently, it is useful to be able to quickly look up the process descriptor of the currently executing task, which is done via the current macro. On x86, current is calculated by masking out 13 least-significant bits of the stack pointer to obtain the thread_info structure. This is done by current_thread_info() function.
The thread_info is stored at the bottom of stack, which means that it is the lowest address of the stack.
The code above illustrates that sp is the register address of stack pointer . And we can calculate the current process address by 'sp&(and) mask', which is also the lowest address of stack.
Process state
Remember there is a state field in the process descriptor. It represents the current conditions of the process and its value is represented by one of five flags:
TASK_RUNNING: Currently running or ready to run in the ready queue.
TASK_INTERRUPTIBLE: Sleeping (blocked). waiting for some condition to exist. When condition exist or receive a signal(interrupt), turn to TASK_RUNNING.
TASK_UNINTERRUPTIBLE: Identical to TASK_INTERRUPTIBLE, but doesn't wake up and become runnable if it receives a signal.
__TASK_TRACED: The process is being traced by another process, such as a debugger, via ptrace.
__TASK_STOPPED: Process execution has stopped; the task is not running nor is it eligible to run. This occurs if the task receives the SIGSTOP , SIGTSTP , SIGTTIN , or SIGTTOU signal or if it receives any signal while it is being debugged.
Manipulating the Current Process State
The mechanism to change a process's state is using set_task_state(task, state).
Also the method set_current_state(state) is synonymous to set_task_state(current, state)
System calls and exception handlers are well-defined interfaces into the kernel.A process can begin executing in kernel-space only through one of these interfaces