1 |
\chapter{Process Management} |
\chapter{Process Management} |
2 |
\section{Process 0 swapper} |
\section{Process 0 swapper} |
3 |
When the CPU switches from real mode to protected mode, it initializes segmentation and paging. Then, it sets up execution environment for the process 0\index{swapper} [swapper]. The assembly code to create the startup swapper proces is in the file \url{arch/i386/kernel/head.S}. |
\textbf{\Large W}hen the CPU switches from real mode to protected mode, it initializes segmentation and paging. Then, it sets up execution environment for the process 0\index{swapper} [swapper]. The assembly code to create the startup swapper process is in the file \url{arch/i386/kernel/head.S}. |
4 |
% TODO startup_32 \index {startup\_32} |
% TODO startup_32 \index {startup\_32} |
5 |
% TODO init_idle |
|
6 |
|
\section{Process 1 init} \index{init} |
7 |
\section{Process 1 init} \index{init} |
After the initialization of paging, memory and timers in the \textit{start\_kernel} function, kernel threads are created. The function \textit{kernel\_thread()} is defined in \url{arch/i386/kernel/process.c} and called from the initialization routine start\_kernel (Refer to section~\ref{init:sk}). |
8 |
After the initialization of paging, memory and timers in the \textit{start\_kernel} function, kernel threads \index{kernel\_thread} are created. The function \textit{kernel\_thread()} is defined in \url{arch/i386/kernel/process.c} and called from the initialization routine start\_kernel (Refer to section~\ref{init:sk}). |
|
9 |
|
\subsection{kernel\_thread} \label{proc:kt} \index{kernel\_thread} |
10 |
\subsection{kernel\_thread} \label{proc:kt} \index{kernel\_thread} |
A Kernel\_thread is a cloned thread. Some of the properties of a kernel\_thread are listed below: |
11 |
% TODO kernel_thread |
\begin{enumerate} |
12 |
|
\item A kernel\_thread usually runs in the background, releasing its memory map,and the files struct and becoming one with "init" by calling daemonize() function defined in \url{kernel/sched.c}. |
13 |
\par The init function (fn parameter to kernel\_thread) locks the kernel and performs the basic setup related to foll. items. |
\item Kernel thread run in kernel address space and do not interact with user. They are generally created during sytem bootup and run until sytem shutdown. |
14 |
|
\item A running kernel thread blocks till someone calls schedule\_task by putting itself into its wait\_queue,calling schedule,thereby waiting for someone to wake it up through a call to schedule\_task. The schedule\_task queues up the tq\_struct and then wakes up the keventd process,blocking in its wait\_queue,for someone to wake it up,in order to consume the tq\_context queue. |
15 |
\newline \textbf{Function : do\_basic\_setup} \newline |
\end{enumerate} |
16 |
The function do\_basic\_setup starts a migration thread, context thread and performs socket initialization. |
\par The famous process 0 and 1 are created using kernel\_thread. Another good example of a Kernel Thread is "keventd" which is started as a kernel\_thread using start\_context\_thread(context\_thread,NULL,CLONE\_FILES | CLONE\_FS) in \url{kernel/context.c} which has the operations for the kernel thread keventd. |
17 |
|
\par The kernel\_thread is created as follows: |
18 |
\begin{description} |
\begin{verbatim} |
19 |
\item[migration thread] \index{migration\_thread} A migration thread (kernel\_thread) is started by calling \textit{migration\_init} function [\url{kernel/sched.c} ] for all cpus. Refer to section ~\ref{smp:all} for SMP initialization details. |
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) |
20 |
|
{ |
21 |
\subsection{migration\_thread} \label{proc:mt} \index{migration\_thread} |
long retval, d0; |
22 |
% TODO migration _thread |
|
23 |
\begin{verbatim} |
__asm__ __volatile__( |
24 |
|
"movl %%esp,%%esi\n\t" /* [1]. */ |
25 |
/* Note, smp_num_cpus is configured during smp boot process |
"int $0x80\n\t" /* Linux/i386 system call */ |
26 |
in smp_boot_cpu function in arch/i386/kernel/smpboot.c |
"cmpl %%esp,%%esi\n\t" /* child or parent? [2]. */ |
27 |
*/ |
"je 1f\n\t" /* parent - jump */ |
28 |
for (cpu = 0; cpu < smp\_num\_cpus; cpu++) { |
"movl %4,%%eax\n\t" |
29 |
if (kernel\_thread(migration\_thread, (void *) (long) cpu, |
"pushl %%eax\n\t" |
30 |
CLONE\_FS | CLONE\_FILES | CLONE\_SIGNAL) < 0) |
"call *%5\n\t" /* call fn */ /* [3]. */ |
31 |
BUG(); |
"movl %3,%0\n\t" /* exit */ |
32 |
} |
"int $0x80\n" /* [4]. */ |
33 |
|
"1:\t" |
34 |
\end{verbatim} |
:"=&a" (retval), "=&S" (d0) |
35 |
\item[Sockets] Performs initialization related to sockets. The function sock\_init is defined in \url{net/socket.c}. |
:"0" (__NR_clone), "i" (__NR_exit), |
36 |
% TODO kern_mount NFS mount |
"r" (arg), "r" (fn), |
37 |
\item[context\_thread] The function start\_context\_thread creates a kernel\_thread named context\_thread. The function is defined in \url{kernel/context.c} |
"b" (flags | CLONE_VM) |
38 |
\begin{verbatim} |
: "memory"); |
39 |
|
return retval; |
40 |
kernel_thread(context_thread, NULL, CLONE_FS | CLONE_FILES); |
} |
41 |
|
\end{verbatim} |
42 |
\end{verbatim} |
\begin{enumerate} |
43 |
|
\item The kernel thread invokes \textit{"clone"} system call to create new kernel process, with the parent proces 0 (Init). [\textit{ clone(0, flags | CLONE\_VM); }] |
44 |
\item[init\_calls] The function do\_init\_call flushes the pending tasks in the init queue, if any. |
\item If checks, whether the return value of clone function is parent or child. For parent process, it makes a far jump to return from ther function. |
45 |
\end{description} |
\item For child process, it invokes the function passed as argument |
46 |
|
\item It also invokes another system call to exit from the function. Thus, the kernel thread starts executing independantly. |
47 |
\par The init function opens a console (viz. /dev/console) and finally, executes the "/sbin/init" or "/etc/init" or "/bin/init" or "/bin/sh" program (in this priority order). |
\end{enumerate} |
48 |
|
|
49 |
\newline \par The code is explained below. |
\\ \par The init function (fn parameter to kernel\_thread) locks the kernel and performs the basic setup related to following items. |
50 |
|
|
51 |
\begin{verbatim} |
\\ \textbf{Function : do\_basic\_setup} \\ |
52 |
|
The function do\_basic\_setup starts a migration thread, context thread and performs socket initialization. |
53 |
lock_kernel(); |
|
54 |
do_basic_setup(); |
\begin{description} |
55 |
|
\item[migration thread] \index{migration\_thread} A migration thread (kernel\_thread) is started by calling \textit{migration\_init} function [\url{kernel/sched.c} ] for all cpus. Refer to section ~\ref{smp:all} for SMP initialization details. |
56 |
prepare_namespace(); |
|
57 |
free_initmem(); |
\subsection{migration\_thread} \label{proc:mt} \index{migration\_thread} |
58 |
unlock_kernel(); |
The migration\_thread is a SMP specific process and is started by calling the \textit{migration\_init} function defined in \url{kernel/sched.c}. The function is executed only on the boot (first) processor and other CPUs use the scheduler to run the migration\_thread. This thread is a part of the system runqueue along with the \textit{migration\_queue}. Migration is used to lock multiple runqueues running on different CPUs using a semaphore. This is how migration works.\footnote{Migration steps are explained in \url{kernel/sched.c}.} |
59 |
|
|
60 |
if (open("/dev/console", O_RDWR, 0) < 0) |
\begin{enumerate} |
61 |
printk("Warning: unable to open an initial console.\n"); |
\item Queue a \textit{migration\_req\_t} structure in the source CPU's runqueue and wake up that CPU's migration thread. |
62 |
|
\item down() the locked semaphore, hence the thread blocks. |
63 |
(void) dup(0); |
\item Migration thread wakes up (implicitly it forces the migrated thread off the CPU) |
64 |
(void) dup(0); |
\item It gets the migration request and checks whether the migrated task is still in the wrong runqueue. |
65 |
if (execute_command) |
\item If it's in the wrong runqueue then the migration thread removes it and puts it into the right queue. |
66 |
execve(execute_command,argv_init,envp_init); |
\item Migration thread up()s the semaphore. |
67 |
execve("/sbin/init",argv_init,envp_init); |
\item The process wakes up and the migration is done. |
68 |
execve("/etc/init",argv_init,envp_init); |
\end{enumerate} |
69 |
execve("/bin/init",argv_init,envp_init); |
|
70 |
execve("/bin/sh",argv_sh,envp_init); |
The migration\_thread function is described below: |
71 |
panic("No init found. Try passing init= option to kernel."); |
\begin{verbatim} |
72 |
|
|
73 |
\end{verbatim} |
/* Note, smp_num_cpus is configured during smp boot process |
74 |
|
in smp_boot_cpu function in arch/i386/kernel/smpboot.c |
75 |
\subsection{Namespaces} \index{prepare\_namespace} |
*/ |
76 |
% TODO prepare_namespace, dup |
for (cpu = 0; cpu < smp\_num\_cpus; cpu++) { |
77 |
The function calls prepare\_namespace. |
if (kernel\_thread(migration\_thread, (void *) (long) cpu, |
78 |
|
CLONE\_FS | CLONE\_FILES | CLONE\_SIGNAL) < 0) |
79 |
\subsection{Function init()} \index{init} |
BUG(); |
80 |
\newline \par The \textit{init} program is the first process run after the kernel is up. It is configured with the "/etc/inittab" file. It contains following system configuration. |
} |
81 |
|
|
82 |
\begin{description} |
\end{verbatim} |
83 |
\item[Runlevel] Start up system run level. |
% TODO migration _thread function |
84 |
\item[Startup-process] Processes to be executed during system boot. |
\item[Sockets] Performs initialization related to sockets. The function sock\_init is defined in \url{net/socket.c}. The reason behind network initialization at this point is related to file system mounting. In order to mount the file system from NFS, the network should be up and running . Hence, the VFS file system is mounted using the \textit{kern\_mount} function invoked from the sock\_init function which takes care of network booting. |
85 |
\item[Runlevel-processes] Processes to be run when the specified runlevel is entered. |
\item[context\_thread] The function start\_context\_thread creates a kernel\_thread named context\_thread. The function is defined in \url{kernel/context.c} |
86 |
\item[Action-processes] Processes to be run on certain runlevels with actions like respawn so the process is restarted any time it terminates. |
\begin{verbatim} |
87 |
\item[Other prcesses] Certain actions or processes to be run if certain signals or user actions are indicated. |
kernel_thread(context_thread, NULL, CLONE_FS | CLONE_FILES); |
88 |
\end{description} |
\end{verbatim} |
89 |
|
|
90 |
\section{Structures} |
\item[init\_calls] The function do\_init\_call flushes the pending tasks in the init queue, if any. |
91 |
Within the linux kernel, every process is associated with a process descriptor defined by struct \textit{task\_struct} \footnote{defined in \url{include/linux/sched.h}}. The structure contains various information related to process state, process threads, executable domain, process priority, signals, parent child relationships,filesystems and various limits. All the elements of these structure are initialized when a new process is created and destroyed when the process terminates. In order to understand process scheduling, it is necessary to understand how these scheduling information is initialized. This is explained in the do\_fork ~\ref{proc:do_fork} function. First we shall describe the \textit{task\_struct} in detail. |
\end{description} |
92 |
|
|
93 |
\subsection{The process [task\_struct] structure} \index{task\_struct} |
\\ \par The code is explained below. |
94 |
% TODO task_struct and others |
|
95 |
|
\begin{verbatim} |
96 |
\section{Creating New process} |
|
97 |
|
lock_kernel(); |
98 |
% TODO dup resource , copy on write , __clone LWP , _syscall |
do_basic_setup(); |
99 |
Linux kernel 2.4 supports 3 types of processes. |
|
100 |
\begin{description} |
prepare_namespace(); |
101 |
\item[\large{1. idle threads}] |
free_initmem(); |
102 |
\par The idle thread is created after initialization for the first CPU while for others, it is created by calling fork\_by\_hand() in \url{arch/i386/kernel/smpboot.c}. Idle tasks are unique per cpu with a pid of 0. |
unlock_kernel(); |
103 |
\item[\large{2. kernel threads}] |
|
104 |
\par Kernel threads are created using kernel\_thread() function. The "fn" argument is the function which starts executing in daemon mode using the daemonize() function. |
if (open("/dev/console", O_RDWR, 0) < 0) |
105 |
|
printk("Warning: unable to open an initial console.\n"); |
106 |
\begin{minipage}{0.90\textwidth} |
|
107 |
Example of a kernel\_thread : |
(void) dup(0); |
108 |
In order to create a migration\_thread, kernel\_thread is created in the function migration\_init. Refer to \url{kernel/sched.c} for each cpu. |
(void) dup(0); |
109 |
\begin{verbatim} |
if (execute_command) |
110 |
|
execve(execute_command,argv_init,envp_init); |
111 |
for (cpu = 0; cpu < smp\_num\_cpus; cpu++) { |
execve("/sbin/init",argv_init,envp_init); |
112 |
if (kernel\_thread(migration\_thread, (void *) (long) cpu, |
execve("/etc/init",argv_init,envp_init); |
113 |
CLONE\_FS | CLONE\_FILES | CLONE\_SIGNAL) < 0) |
execve("/bin/init",argv_init,envp_init); |
114 |
BUG(); |
execve("/bin/sh",argv_sh,envp_init); |
115 |
} |
panic("No init found. Try passing init= option to kernel."); |
116 |
|
|
117 |
\end{verbatim} |
\end{verbatim} |
118 |
The function migration\_init daemonizes itself. |
Before starting the init program, the basic setup related to migration, init calls, context thread is done as explained above. The function \textit{prepare\_namespace} is related namespace explained in the Next section. The bootup command line parameters to lilo (or other boot program) are also invoked. The init function opens a console (viz. /dev/console) and finally, executes the "/sbin/init" or "/etc/init" or "/bin/init" or "/bin/sh" program (in this priority order) and the init process is started from the available location. |
119 |
\begin{verbatim} |
|
120 |
|
% \subsection{Namespaces} \index{prepare\_namespace} |
121 |
static int migration\_thread(void * bind\_cpu) { |
% software_resume in kernel/suspend.c |
122 |
int ret; |
% mount_devfs : mounts /dev ; do_mount ("none", "/dev", "devfs", 0, ""); |
123 |
\end{verbatim} |
% TODO prepare_namespace, dup |
124 |
\textbf{ daemonize();} |
% The function calls prepare\_namespace. |
125 |
\begin{verbatim} |
|
126 |
sigfillset(¤t->blocked); |
\subsection{Function init()} \index{init} |
127 |
set\_fs(KERNEL\_DS); |
\\ \par The \textit{init} program is the first process run after the kernel is up. It is configured with the "/etc/inittab" file. It contains following system configuration. |
128 |
} |
|
129 |
|
\begin{description} |
130 |
\end{verbatim} |
\item[Runlevel] Start up system run level. |
131 |
\end{minipage} \end{center} |
\item[Startup-process] Processes to be executed during system boot. |
132 |
|
\item[Runlevel-processes] Processes to be run when the specified runlevel is entered. |
133 |
\item[\large{3. user tasks}] |
\item[Action-processes] Processes to be run on certain runlevels with actions like respawn so the process is restarted any time it terminates. |
134 |
\par user tasks are generally created by user applications using fork() or clone() function calls. |
\item[Other prcesses] Certain actions or processes to be run if certain signals or user actions are indicated. |
135 |
\end{description} |
\end{description} |
136 |
|
|
137 |
\section{fork, clone system calls} |
\section{Structures} |
138 |
New processes are created by using fork, clone, vfork system calls. When a user mode program invokes a system call, the libc library transfers control to kernel mode using software interrupt 0x80 registered during IRQ initialization and the kernel executes the system call related function. The system call within the kernel is its counterpart in user space prefixed by sys. So, when user calls fork/clone/vfork, kernel executes sys\_fork/sys\_clone/sys\_vfork function. |
Within the linux kernel, every process is associated with a process descriptor defined by struct \textit{task\_struct} \footnote{defined in \url{include/linux/sched.h}}. The structure contains various information related to process state, process threads, executable domain, process priority, signals, parent child relationships, filesystems and various limits. All the elements of these structure are initialized when a new process is created and destroyed when the process terminates. In order to understand process scheduling, it is necessary to understand how these scheduling information is initialized. This is explained in the do\_fork ~\ref{proc:do_fork} function. First we shall describe the \textit{task\_struct} in detail. |
139 |
\par These functions are defined in \url{arch/i386/kernel/process.c} while the system call numbers are defined in \url{include/asm-i386/unistd.h} |
|
140 |
|
\subsection{The process [task\_struct] structure} \index{task\_struct} \label{taskstruct} |
141 |
\par Example of fork system call : \index{fork} |
The complete process structure is discussed below. The scheduler related members of the process structure are explained in detail in the scheduling chapter ~\ref{sched:structs}. |
142 |
|
|
143 |
\begin{enumerate} |
\begin{verbatim} |
144 |
\item User calls fork(); |
struct task_struct { |
145 |
\item The libc library generates software interrupt [0x80] and tansfers control to kernel mode. |
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ |
146 |
\item Kernel executes system\_call() and saves kernel mode stack registers. |
struct thread_info *thread_info; |
147 |
\item Kernel invokes function sys\_fork(); |
atomic_t usage; |
148 |
\item Kernel exits the handler by calling ret\_from\_sys\_call(); |
unsigned long flags; /* per process flags, defined below */ |
149 |
\end{enumerate} |
unsigned long ptrace; |
150 |
|
|
151 |
\par When a new process is created using fork/clone/vfork system call, kernel executes sys\_fork/sys\_clone/sys\_vfork function respectively, defined in \url{arch/i386/kernel/process.c}. These functions are architecture specific which call the generic function do\_fork to create the new process. The first "flags" parameter is properly substituted and the function do\_fork is invoked. |
int lock_depth; /* Lock depth */ |
152 |
|
|
153 |
\newline \par Example of sys\_clone function : |
int prio, static_prio; |
154 |
|
list_t run_list; |
155 |
\begin{verbatim} |
prio_array_t *array; |
156 |
|
|
157 |
asmlinkage int sys_clone(struct pt_regs regs) |
unsigned long sleep_avg; |
158 |
{ |
unsigned long sleep_timestamp; |
159 |
struct task_struct *p; |
|
160 |
unsigned long clone_flags; |
unsigned long policy; |
161 |
unsigned long newsp; |
unsigned long cpus_allowed; |
162 |
clone_flags = regs.ebx; |
unsigned int time_slice; |
163 |
newsp = regs.ecx; |
|
164 |
if (!newsp) |
struct list_head tasks; |
165 |
newsp = regs.esp; |
|
166 |
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0); |
struct mm_struct *mm, *active_mm; |
167 |
return IS_ERR(p) ? PTR_ERR(p) : p->pid; |
struct list_head local_pages; |
168 |
} |
|
169 |
|
unsigned int allocation_order, nr_local_pages; |
170 |
\end{verbatim} |
|
171 |
|
struct linux_binfmt *binfmt; |
172 |
\subsection{do\_fork function} \index{do\_fork} |
int exit_code, exit_signal; |
173 |
Function do\_fork() \label{proc:do_fork} |
int pdeath_signal; /* The signal sent when the parent dies */ |
174 |
\textit{File: }\url{kernel/fork.c}\\ \newline |
unsigned long personality; |
175 |
|
int did_exec:1; |
176 |
\par Following paragraph explains the steps taken by the kernel do\_fork function in order to create a new process. The steps are more relevant from process scheduling point of view. |
pid_t pid; |
177 |
|
pid_t pgrp; |
178 |
\begin{verbatim} |
pid_t tty_old_pgrp; |
179 |
struct task_struct *do_fork(unsigned long clone_flags, |
pid_t session; |
180 |
unsigned long stack_start, |
pid_t tgid; |
181 |
struct pt_regs *regs, |
/* boolean value for session group leader */ |
182 |
unsigned long stack_size) |
int leader; |
183 |
\end{verbatim} |
struct task_struct *real_parent; /* real parent process (when being debugged) */ |
184 |
|
struct task_struct *parent; /* parent process */ |
185 |
The do\_fork function takes foll. arguments. |
struct list_head children; /* list of my children */ |
186 |
\begin{description} |
struct list_head sibling; /* linkage in my parent's children list */ |
187 |
\item[clone\_flags] : Flags to create process. This is different for fork/clone/vfork calls. |
struct list_head thread_group; |
188 |
\item[stack\_start] : top of stack required for copy\_routine. |
|
189 |
\item[regs] : The register structure defined in \url{include/asm-i386/ptrace.h} |
/* PID hash table linkage. */ |
190 |
\item[stack\_size] : Size of stack, usually 0. |
struct task_struct *pidhash_next; |
191 |
\item[] \& |
struct task_struct **pidhash_pprev; |
192 |
\item[return value] : (pointer to) Newly created task. |
|
193 |
\end{description} |
wait_queue_head_t wait_chldexit; /* for wait4() */ |
194 |
|
struct completion *vfork_done; /* for vfork() */ |
195 |
\par The code is explained below in parts. |
|
196 |
|
unsigned long rt_priority; |
197 |
\begin{verbatim} |
unsigned long it_real_value, it_prof_value, it_virt_value; |
198 |
|
unsigned long it_real_incr, it_prof_incr, it_virt_incr; |
199 |
/*** Vaildity checks ***/ |
struct timer_list real_timer; |
200 |
|
struct tms times; |
201 |
if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) |
unsigned long start_time; |
202 |
return ERR_PTR(-EINVAL); |
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS]; |
203 |
|
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap; |
204 |
retval = -ENOMEM; |
int swappable:1; |
205 |
p = dup_task_struct(current); |
uid_t uid,euid,suid,fsuid; |
206 |
if (!p) |
gid_t gid,egid,sgid,fsgid; |
207 |
goto fork_out; |
int ngroups; |
208 |
|
gid_t groups[NGROUPS]; |
209 |
retval = -EAGAIN; |
kernel_cap_t cap_effective, cap_inheritable, cap_permitted; |
210 |
if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur) { |
int keep_capabilities:1; |
211 |
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE)) |
struct user_struct *user; |
212 |
goto bad_fork_free; |
/* limits */ |
213 |
} |
struct rlimit rlim[RLIM_NLIMITS]; |
214 |
|
unsigned short used_math; |
215 |
atomic_inc(&p->user->__count); |
char comm[16]; |
216 |
atomic_inc(&p->user->processes); |
/* file system info */ |
217 |
|
int link_count, total_link_count; |
218 |
if (nr_threads >= max_threads) |
struct tty_struct *tty; /* NULL if no tty */ |
219 |
goto bad_fork_cleanup_count; |
unsigned int locks; /* How many file locks are being held */ |
220 |
|
/* ipc stuff */ |
221 |
\end{verbatim} |
struct sysv_sem sysvsem; |
222 |
Initially, the kernel checks for validity for clone\_flags. If the process is part of New Namespace Group (CLONE\_NEWNS) AND fs sharing flag (CLONE\_FS) are set,simoultaneously, it retuns an error. Then it creates a new task by duplicating the currently running task(current). |
/* CPU-specific state of this task */ |
223 |
\newline \par The kernel limits the number of user processes owned by a process.\footnote{Refer to \url{include/asm-i386/resource.h} for the resource constants.} If this value, is greater or equal to current resource limit of number of processes, it returns an error. Else, it updates the user struct\footnote{defined in \url{linux/sched.h}} for that process. The function \textit{"capable()"} checks for a particular capability. The file \url{include/linux/capability.h} enumerates the list of capabilities e.g. CAP\_SYS\_ADMIN. Then, the kernel checks if the number of threads exceed the limit max\_therads.\footnote{limit set up in fork\_init function of start\_kernel code}. |
struct thread_struct thread; |
224 |
% TODO dup_task_struct |
/* filesystem information */ |
225 |
|
struct fs_struct *fs; |
226 |
\begin{verbatim} |
/* open file information */ |
227 |
|
struct files_struct *files; |
228 |
/*** Initialize task data variables and flags ***/ |
/* namepaces */ |
229 |
|
struct namespace *namespace; |
230 |
get_exec_domain(p->thread_info->exec_domain); |
/* signal handlers */ |
231 |
|
spinlock_t sigmask_lock; /* Protects signal and blocked */ |
232 |
if (p->binfmt && p->binfmt->module) |
struct signal_struct *sig; |
233 |
__MOD_INC_USE_COUNT(p->binfmt->module); |
|
234 |
|
sigset_t blocked; |
235 |
p->did_exec = 0; |
struct sigpending pending; |
236 |
p->swappable = 0; |
|
237 |
p->state = TASK_UNINTERRUPTIBLE; |
unsigned long sas_ss_sp; |
238 |
|
size_t sas_ss_size; |
239 |
copy_flags(clone_flags, p); |
int (*notifier)(void *priv); |
240 |
p->pid = get_pid(clone_flags); |
void *notifier_data; |
241 |
p->proc_dentry = NULL; |
sigset_t *notifier_mask; |
242 |
|
|
243 |
\end{verbatim} |
/* Thread group tracking */ |
244 |
|
u32 parent_exec_id; |
245 |
Linux kernel has the ability to execute the binaries compiled for other operating systems (assuming kernel compatible machine code). The execution domain for the running thread is specified by the structure exec\_domain defined in \url{include/linux/personality.h} \footnote{map\_segment TODO }. The structure defines varioous personlities of the target execution environment supported by the kernel. e.g. PER\_LINUX for linux systems, PER\_BSD for bsd uix. The personality value is set by \textit{personality()} system call. the macro \textit{get\_exec\_domain} is used to increament the module count of the module associated with the \textit{exec\_domain} while its counterpart \textit{put\_exec\_domain} is used to decreament it. |
u32 self_exec_id; |
246 |
|
/* Protection of (de-)allocation: mm, files, fs, tty */ |
247 |
% TODO map_segment |
spinlock_t alloc_lock; |
248 |
\par Then, the kernel increments the module's reference count only for modularised binary format. Then, it resets executed, swappable flags ans sets task state to TASK\_UNINTERRUPTIBLE. The new flags are set for the process p, especially in case of \textit{sys\_clone} call. |
|
249 |
|
/* journalling filesystem info */ |
250 |
\begin{verbatim} |
void *journal_info; |
251 |
|
struct dentry *proc_dentry; |
252 |
/*** Initialize task wait queue, lists and pointers ***/ |
\end{verbatim} |
253 |
|
|
254 |
INIT_LIST_HEAD(&p->run_list); |
\\ These task structure elements are grouped for specific purposes and used for that particular reason. They are stated below in short: |
255 |
|
|
256 |
INIT_LIST_HEAD(&p->children); |
\begin{itemize} |
257 |
INIT_LIST_HEAD(&p->sibling); |
|
258 |
init_waitqueue_head(&p->wait_chldexit); |
\item state : The process state defined as per process life cycle. |
259 |
p->vfork_done = NULL; |
\item thread\_info : The thread information associated with a process. |
260 |
if (clone_flags & CLONE_VFORK) { |
\item usage : The usage usually associated with loadable modules. |
261 |
p->vfork_done = &vfork; |
\item flags : Process flags related to fork, core dump, start execution, signaled, free pages , I/O as defined in \url{include/linux/sched.h} |
262 |
init_completion(&vfork); |
\item ptrace : Whether the process under execution is being traced or NOT. |
263 |
} |
\item lock\_depth : Initialized to -1 and used as thread preemption counter while switching tasks with spinlocks held. |
264 |
spin_lock_init(&p->alloc_lock); |
\item prio, static\_prio, run\_list, array : These fields are related to process scheduling and are explained in the chapter ~\ref{sched:all}. |
265 |
|
\item sleep\_avg, sleep\_timestamp : The sleep times of the process are used for priority calculation. The more time a task spends sleeping, it gets higher average and higher priority boost as well. |
266 |
clear_tsk_thread_flag(p,TIF_SIGPENDING); |
\item policy : Either of SCHED\_FIFO, SCHED\_RR, SCHED\_OTHER predefined values. |
267 |
init_sigpending(&p->pending); |
\item cpus\_allowed, time\_slice : The number of cpus allowed are set using the cpu\_logical\_map. While time\_slice is used as a measure for which the cpu is alloted to the process. The deault value is Hz. |
268 |
|
\item list\_head tasks : The list fo tasks to which the current task is going to get linked. |
269 |
p->it_real_value = p->it_virt_value = p->it_prof_value = 0; |
\item mm, active\_mm, local\_pages, allocation order, nr\_local\_pages : These fields are related to the memory associated with the process. |
270 |
p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0; |
\item binfmt : The binary format used by the process. |
271 |
|
\item exit\_code, exit\_signal, pdeath\_signal : These fields are updated when the process terminates. The pdeath\_signal is updated when the parent of the process dies. |
272 |
/*** some initialization related to timer ***/ |
\item personality : The personality is set as some value related to the operating system. Linux kernel setups the default value as PER\_LINUX personality. |
273 |
|
\item did\_exec : The executable flag set up when the process is created. |
274 |
init_timer(&p->real_timer); |
\item pid, pgrp, tty\_old\_pgrp, session, tgid, leader : The session credetials related with the process. The process id, group characters, session properties and leadership. |
275 |
p->real_timer.data = (unsigned long) p; |
\item real\_parent, parent, children , sibling : The pointers to original parent and real parent, children and other silblings. |
276 |
|
\item pidhash\_next, pidhash\_pprev : The process ids are obtained using the hash function. These fields are used to keep track of the hashing accountings. Refer to section ~\ref{hashpid} for details. |
277 |
p->leader = 0; /* session leadership doesn't inherit */ |
\item wait\_chldexit : This field is related to wait queue of processes. This field is initialized with \textit{WAIT\_QUEUE\_HEAD\_INITIALIZER} macro and updated when the process exits. At the exit time, the parent and all the others in its thread\_group are waken up by calling \textit{send\_siginfo}. The waiting processes are kept blocking on its wait\_chldexit wait\_queue. |
278 |
p->tty_old_pgrp = 0; |
\item vfork\_done : This field is of struct completion type, which contains a waitqueue pointer along with a done flag. This struct is dedicated to vfork system call. |
279 |
p->times.tms_utime = p->times.tms_stime = 0; |
\item rt\_priority : The real time priority associated with the process. This is used for process scheduling of \textit{SCHED\_OTHER} policy. |
280 |
p->times.tms_cutime = p->times.tms_cstime = 0; |
\item it\_real\_value, it\_prof\_value, it\_virt\_value, it\_real\_incr, it\_prof\_incr, it\_virt\_incr : These fields are related to virtual and profile timer clock and SIGVTALRM, SIGPROF signals. |
281 |
|
\item real\_timer, start\_time : The timer list associated with the process and updated with every timer interrupt. |
282 |
\end{verbatim} |
\item times : The time accountings related to times system call. |
283 |
|
\item per\_cpu\_utime, per\_cpu\_stime : The per processor time spent in user and system space. |
284 |
The \textit{INIT\_LIST\_HEAD} macro is used to initialize the next and prev pointers of a linked list. Both the pointers are set to the macro argument, representing a circular linked list of a single element \footnote{Linked lists are described \url{include/linux/list.h}} while \textit{init\_waitqueue\_head} initializes the waitqueue header node which contains the spinlock along with the linked list. |
\item min\_flt, maj\_flt,nswap, cmin\_fltcmaj\_flt, cnswap : These are resource control/accounting fields similar to struct usage in \url{include/linux/resource.h}. They are used to store memory and paging information like page faults, reclaims. |
285 |
\par The inline function \textit{clear\_tsk\_thread\_flag} (defined in \url{include/linux/sched.h}) calls \textit{clear\_ti\_thread\_flag} (defined in \url{include/linux/thread_info.h}) to clear the flag information of the thread within the task structure. |
\item swappable : The flag indicating whether the process is swappable or not. |
286 |
|
\item uid, euid, suid, fsuid, gid, egid, sgid, fsgid : The unix system ids assoicated with the process. |
287 |
\index{bitops} \index{btrl} |
\item ngroups, groups[NGROUPS] : The groups is an array of size 32, of type gid\_t. The numer of valid groups is set to ngroups. |
288 |
\begin{verbatim} |
\item cap\_effective, cap\_inheritable, cap\_permitted, keep\_capabilities : The kernel capability structure associated with the process, also part of linux binary format structure in \url{include/linux/binfmt.h}. |
289 |
|
\item user\_struct user : The user struct contain user space information like the refrence count, user processes, open files , hashing information and uid. |
290 |
/*** File : {include/asm-i386/bitops.h} ***/ |
\item rlim, used\_math : rlim is process usage limits structure used to setup the RLIMIT\_CPU, RLIMIT\_FSIZE (file size), RLIMIT\_DATA (heap size), RLIMIT\_AS (address size), RLIMIT\_RSS (page frames). |
291 |
static __inline__ void clear_bit(int nr, volatile unsigned long * addr) |
\item link\_count, total\_link\_count : These fields are used in pathname lookup mechanisms. Currently the recursive symlink is limited to 8, while consecutive symlinks are limited to 40. Refer to \url{fs/namei.c} for more details. |
292 |
{ |
\item tty : The terminal information if the process is associated with a tty device. |
293 |
__asm__ __volatile__( LOCK_PREFIX |
\item locks : The number of file locks being held by the process. |
294 |
"btrl %1,%0" |
\item sysvsem : The IPC realted information within the process. |
295 |
:"=m" (ADDR) |
\item thread, fs, files : The file system and open files information for the process. |
296 |
:"Ir" (nr)); |
\item sigmask, sig, blocked, pending : The signal related structures. Refer to section ~\ref{signalstruct} for details. |
297 |
} |
\item sas\_ss\_sp, sas\_ss\_size : These fields are used while switching stacks during execution of signal handlers. |
298 |
|
\item notifier, notifier\_data, notifier\_mask : Used to notify the system that a driver wants to block all signals for this process, and wants to be notified if any signals at all were to be sent/acted upon. |
299 |
\end{verbatim} |
\item parent\_exec\_id, self\_exec\_id : The exec ids setup during startup of processes. If the parent exec id doesn't match the exec id, saved when we the process started then it is notied that the parent has changed security domain. |
300 |
% TODO explain code |
\item alloc\_lock : The spin lock used for task\_lock and task\_unlock purposes. |
301 |
\textit{init\_completion} is wrapper inline function to initialize the wait queue header specially used during \textit{vfork()} system call. The function \textit{init\_sigpending} initializes the signal structure containing struct sigqueue\footnote{defined in \url{include/linux/signal.h}} and sigset\_t\footnote{defined in \url{include/asm-i386/signal.h}} structure. Refer to section ~\ref{sig:structs} for more details. The head and tail pointers of sigqueue are set to NULL to initialize the circular linked list of single element while the number of words per signal [\_NSIG\_WORDS] of sigset\_t structure are set to zero. |
\item journal\_info, proc\_dentry : The journaling information stored for journling filesystems like ext3. |
302 |
\par The dynamic timer associated with the task structure is \textit{real\_timer}. When, a new task is created, the timer is initialized using \textit{init\_timer} and the data is field set to the newly created process p. Thus, the whole process structure is available to the function which is called when the timer expires. |
\end{itemize} |
303 |
\begin{verbatim} |
|
304 |
|
\section{Creating New process} |
305 |
#ifdef CONFIG_SMP |
|
306 |
{ |
% TODO dup resource , copy on write , __clone LWP , _syscall |
307 |
int i; |
Linux kernel 2.4 supports 3 types of processes. |
308 |
|
\begin{description} |
309 |
/* ?? should we just memset this ?? */ |
\item[\large{1. idle threads}] |
310 |
for(i = 0; i < smp_num_cpus; i++) |
\par The idle thread is created after initialization for the first CPU while for others, it is created by calling fork\_by\_hand() in \url{arch/i386/kernel/smpboot.c}. Idle tasks are unique per cpu with a pid of 0. |
311 |
p->per_cpu_utime[cpu_logical_map(i)] = |
\item[\large{2. kernel threads}] |
312 |
p->per_cpu_stime[cpu_logical_map(i)] = 0; |
\par Kernel threads are created using kernel\_thread() function. The "fn" argument is the function which starts executing in daemon mode using the daemonize() function. |
313 |
spin_lock_init(&p->sigmask_lock); |
|
314 |
} |
Example of a kernel\_thread : |
315 |
#endif |
In order to create a migration\_thread, kernel\_thread is created in the function migration\_init. Refer to \url{kernel/sched.c} for each cpu. |
316 |
|
\begin{verbatim} |
317 |
\end{verbatim} |
|
318 |
This part of code is SMP specific. It resets the values of user timer (utime) and system time (stime) for all cpus for the current process. It also initializes the \textit{sigmask\_lock} used to block the signals by the process. Refer to ~\ref{sig:structs} for more details. |
for (cpu = 0; cpu < smp\_num\_cpus; cpu++) { |
319 |
|
if (kernel\_thread(migration\_thread, (void *) (long) cpu, |
320 |
\begin{verbatim} |
CLONE\_FS | CLONE\_FILES | CLONE\_SIGNAL) < 0) |
321 |
|
BUG(); |
322 |
p->array = NULL; |
} |
323 |
p->lock_depth = -1; /* -1 = no lock */ |
|
324 |
p->start_time = jiffies; |
\end{verbatim} |
325 |
|
The function migration\_init daemonizes itself. |
326 |
INIT_LIST_HEAD(&p->local_pages); |
\begin{verbatim} |
327 |
|
|
328 |
retval = -ENOMEM; |
static int migration\_thread(void * bind\_cpu) { |
329 |
|
int ret; |
330 |
/*** copying all process resources ***/ |
\end{verbatim} |
331 |
|
\textbf{ daemonize();} |
332 |
/* copy all the process information */ |
\begin{verbatim} |
333 |
if (copy_semundo(clone_flags, p)) |
sigfillset(¤t->blocked); |
334 |
goto bad_fork_cleanup; |
set\_fs(KERNEL\_DS); |
335 |
if (copy_files(clone_flags, p)) |
} |
336 |
goto bad_fork_cleanup_semundo; |
|
337 |
if (copy_fs(clone_flags, p)) |
\end{verbatim} |
338 |
goto bad_fork_cleanup_files; |
|
339 |
if (copy_sighand(clone_flags, p)) |
\item[\large{3. user tasks}] |
340 |
goto bad_fork_cleanup_fs; |
\par user tasks are generally created by user applications using fork() or clone() function calls. |
341 |
if (copy_mm(clone_flags, p)) |
\end{description} |
342 |
goto bad_fork_cleanup_sighand; |
|
343 |
if (copy_namespace(clone_flags, p)) |
\section{fork, clone system calls} |
344 |
goto bad_fork_cleanup_mm; |
New processes are created by using fork, clone, vfork system calls. When a user mode program invokes a system call, the libc library transfers control to kernel mode using software interrupt 0x80 registered during IRQ initialization and the kernel executes the system call related function. The system call within the kernel is its counterpart in user space prefixed by sys. So, when user calls fork/clone/vfork, kernel executes sys\_fork/sys\_clone/sys\_vfork function. |
345 |
retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); |
\par These functions are defined in \url{arch/i386/kernel/process.c} while the system call numbers are defined in \url{include/asm-i386/unistd.h} |
346 |
|
|
347 |
\end{verbatim} |
\par Example of fork system call : \index{fork} |
348 |
The initial part of code sets the task starting time to jiffies.\footnote{jiffies contains the time right from the system startup and the value is increamented during every timer interrupt}. The final process execution time is updated during process accounting [do\_acct\_process function in \url{kernel/acct.c}]. |
|
349 |
\par Then, various system resources are copied to the newly created process. The following explains the the functions in short. |
\begin{enumerate} |
350 |
\begin{itemize} |
\item User calls fork(); |
351 |
\item copy\_semundo : This copies the sem\_undo\_list object from parent task to child. This object is required to avoid deadlock, when tasks are spawned with the semundo locks. Please refer to \url{ipc/sem.c} for details. |
\item The libc library generates software interrupt [0x80] and tansfers control to kernel mode. |
352 |
\item copy\_files : This function [defined in \url{kernel/fork.c}] determines the number of open files by the parent process and copies those file descriptors to the child process. |
\item Kernel executes system\_call() and saves kernel mode stack registers. |
353 |
\item copy\_fs : This function [defined in \url{kernel/fork.c}] copies the file system information associated with the process [struct fs\_struct]. It contains elements like root, umask, pwd etc. |
\item Kernel invokes function sys\_fork(); |
354 |
\item copy\_sighand : This function copies all signal handlers actions from the parent to child process. Thus, all signals are inherited to child depending on clone\_flags. |
\item Kernel exits the handler by calling ret\_from\_sys\_call(); |
355 |
\item copy\_mm : This function [defined in \url{kernel/fork.c}] copies the memory resources form parent process to child [struct mm\_struct]. It is done by allocating new kmem\_cache for child process. |
\end{enumerate} |
356 |
\item copy\_namespace : This function [defined in \url{fs/namespace.c}] copies the namespace resources form parent process to child [struct namespace]. It is done by allocating new namespace in kernel to accomodate the new child task. |
|
357 |
\item copy\_thread : This function [defined in \url{arch/i386/kernel/process.c}] copies the thread information form parent process to child [struct thread\_struct]. This contains the stack pointer, instruction pointer. This thread structure contains the CPU specific state of the task. |
\par When a new process is created using fork/clone/vfork system call, kernel executes sys\_fork/sys\_clone/sys\_vfork function respectively, defined in \url{arch/i386/kernel/process.c}. These functions are architecture specific which call the generic function do\_fork to create the new process. The first "flags" parameter is properly substituted and the function do\_fork is invoked. |
358 |
\end{itemize} |
|
359 |
\begin{verbatim} |
\\ \par Example of sys\_clone function : |
360 |
|
|
361 |
/*** Now, setup other process attributes ***/ |
\begin{verbatim} |
362 |
|
|
363 |
p->parent_exec_id = p->self_exec_id; |
asmlinkage int sys_clone(struct pt_regs regs) |
364 |
|
{ |
365 |
/* ok, now we should be set up.. */ |
struct task_struct *p; |
366 |
p->swappable = 1; |
unsigned long clone_flags; |
367 |
p->exit_signal = clone_flags & CSIGNAL; |
unsigned long newsp; |
368 |
p->pdeath_signal = 0; |
clone_flags = regs.ebx; |
369 |
|
newsp = regs.ecx; |
370 |
\end{verbatim} |
if (!newsp) |
371 |
The \textit{self\_exec\_id} and \textit{parent\_exec\_id} are set to same value after a fork. When the execution domain of a process changes, its self\_exec\_id is increamented. These values are checked while existing the process, only. The death\_signal [cause of death of a process] is reset to 0. The signal value 0 is unused. Signals are listed in \url{include/asm-i386/signal.h}. |
newsp = regs.esp; |
372 |
|
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, ®s, 0); |
373 |
\begin{verbatim} |
return IS_ERR(p) ? PTR_ERR(p) : p->pid; |
374 |
|
} |
375 |
/*** Sharing timeslice between child and parent ***/ |
|
376 |
|
\end{verbatim} |
377 |
__save_flags(flags); |
|
378 |
__cli(); |
\subsection{do\_fork function} \index{do\_fork} |
379 |
p->time_slice = (current->time_slice + 1) >> 1; |
Function do\_fork() \label{proc:do_fork} |
380 |
current->time_slice >>= 1; |
\textit{File: }\url{kernel/fork.c}\\ \newline |
381 |
if (!current->time_slice) { |
|
382 |
current->time_slice = 1; |
\par Following paragraph explains the steps taken by the kernel do\_fork function in order to create a new process. The steps are more relevant from process scheduling point of view. |
383 |
scheduler_tick(0, 0); |
|
384 |
} |
\begin{verbatim} |
385 |
p->sleep_timestamp = jiffies; |
struct task_struct *do_fork(unsigned long clone_flags, |
386 |
__restore_flags(flags); |
unsigned long stack_start, |
387 |
|
struct pt_regs *regs, |
388 |
\end{verbatim} |
unsigned long stack_size) |
389 |
Since the code updates the process time\_slice, the interrupts should be disabled during this operation. The macros \_\_save\_flags, \_\_cli are used to clear interrupts on the current CPU while \_\_restore\_flgs enables it again. |
\end{verbatim} |
390 |
\par When new child process is created, the \textit{time\_slice}\footnote{Renamed counter field of kernel version 2.2 to time\_slice in kernel 2.4} of the parent process is split into two halves, one for the parent process and the other for child process. This is done to prevent an unlimited access to CPU by a single process. If the parent process is created recently in terms of time\_slice (time\_slice == 0 or 1), then the scheduler is called to reschedule the processes with the user and system time parameters as zero. These parameter are used by the \textit{scheduler\_tick()} function to update the kernel statisticks. |
|
391 |
|
The do\_fork function takes following arguments. |
392 |
\begin{verbatim} |
\begin{description} |
393 |
|
\item[clone\_flags] : Flags to create process. This is different for fork/clone/vfork calls. |
394 |
/*** Adding process info to Runqueue ***/ |
\item[stack\_start] : top of stack required for copy\_routine. |
395 |
|
\item[regs] : The register structure defined in \url{include/asm-i386/ptrace.h} |
396 |
p->tgid = p->pid; |
\item[stack\_size] : Size of stack, usually 0. |
397 |
INIT_LIST_HEAD(&p->thread_group); |
\item[] \& |
398 |
|
\item[return value] : (pointer to) Newly created task. |
399 |
/* Need tasklist lock for parent etc handling! */ |
\end{description} |
400 |
write_lock_irq(&tasklist_lock); |
|
401 |
|
\par The code is explained below in parts. |
402 |
/* CLONE_PARENT re-uses the old parent */ |
|
403 |
p->real_parent = current->real_parent; |
\begin{verbatim} |
404 |
p->parent = current->parent; |
|
405 |
if (!(clone_flags & CLONE_PARENT)) { |
/*** Vaildity checks ***/ |
406 |
p->real_parent = current; |
|
407 |
if (!(p->ptrace & PT_PTRACED)) |
if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) |
408 |
p->parent = current; |
return ERR_PTR(-EINVAL); |
409 |
} |
|
410 |
|
retval = -ENOMEM; |
411 |
if (clone_flags & CLONE_THREAD) { |
p = dup_task_struct(current); |
412 |
p->tgid = current->tgid; |
if (!p) |
413 |
list_add(&p->thread_group, ¤t->thread_group); |
goto fork_out; |
414 |
} |
|
415 |
|
retval = -EAGAIN; |
416 |
SET_LINKS(p); |
if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur) { |
417 |
hash_pid(p); |
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE)) |
418 |
nr_threads++; |
goto bad_fork_free; |
419 |
write_unlock_irq(&tasklist_lock); |
} |
420 |
|
|
421 |
\end{verbatim} |
atomic_inc(&p->user->__count); |
422 |
At this point of time, all the resources required by the process are available. So, the process can get a chance to execute on the CPU and Hence, it needs to be added to list of runqueues. The newly created process acts as the leader of thread group and initializes itself. But if the flags contain CLONE\_THREAD, [i.e. new process is derived from some other process] then the thread leadership is retained to the thread leader of the calling process and newly created process is added to the linked list of its parents' thread [i.e. calling process's thread]. |
atomic_inc(&p->user->processes); |
423 |
\par To set the parent child relationship for the newly created process, we need to access parent process also, Hence an irq lock is obtained. This lock will disable pre-eption on the SMP architecure. This lock is released when the process is added to runqueue. The macro SET\_LINKS inserts the new process in the linked list of process lists. Refer to list management in \url{include/linux/list.h}. |
|
424 |
\par \textbf{ |
if (nr_threads >= max_threads) |
425 |
\newline |
goto bad_fork_cleanup_count; |
426 |
Hashing Process Ids } \index{hash\_pid} |
|
427 |
\newline |
\end{verbatim} |
428 |
\par All the process ids (pids) are hashed in a hashing table pidhash[PIDHASH\_SZ] defined in \url{include/linux/sched.h}. This is an array of pointers to task\_struct of size PIDHASH\_SZ\footnote{This value is currently hardcoded to [4096/4], but should be dynamic and should be set to [NR\_TASKS/4]}. This hashed pids avoid sequencial scanning of the process list and thus, improves performance. The \textit{hash\_pid} function adds the new task to the hash table using process pid as key and pid\_fashfn as hashing function. |
Initially, the kernel checks for validity for clone\_flags. If the process is part of New Namespace Group (CLONE\_NEWNS) and fs sharing flag (CLONE\_FS) are set, simultaneously, it returns an error. Then it creates a new task by duplicating the currently running task(current). |
429 |
|
\\ \par The kernel limits the number of user processes owned by a process.\footnote{Refer to \url{include/asm-i386/resource.h} for the resource constants.} If this value, is greater or equal to current resource limit of number of processes, it returns an error. Else, it updates the user struct accountings [defined in \url{linux/sched.h}] for that process. The function \textit{"capable()"} checks for a particular capability. The file \url{include/linux/capability.h} enumerates the list of capabilities e.g. CAP\_SYS\_ADMIN. Then, the kernel checks if the number of threads exceed the limit max\_therads.\footnote{limit set up in fork\_init function of start\_kernel code}. |
430 |
\begin{verbatim} |
\par The function \textit{dup\_task\_struct} is used to create new kernel slab (memory) for the new task using \textit{kmem\_cache\_alloc()}. The thread information of the process is copied to the new task at this point of time. |
431 |
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) |
|
432 |
\end{verbatim} |
\begin{verbatim} |
433 |
|
|
434 |
The nr\_threads value (total number of processes) is increamented. This value should not exceed max\_threads limit. And the irq lock is returned will re-enables the process pre-emption. |
/*** Initialize task data variables and flags ***/ |
435 |
|
|
436 |
\begin{verbatim} |
get_exec_domain(p->thread_info->exec_domain); |
437 |
|
|
438 |
wake_up_forked_process(p); |
if (p->binfmt && p->binfmt->module) |
439 |
++total_forks; |
__MOD_INC_USE_COUNT(p->binfmt->module); |
440 |
if (clone_flags & CLONE_VFORK) |
|
441 |
wait_for_completion(&vfork); |
p->did_exec = 0; |
442 |
else |
p->swappable = 0; |
443 |
set_need_resched(); |
p->state = TASK_UNINTERRUPTIBLE; |
444 |
|
|
445 |
\end{verbatim} |
copy_flags(clone_flags, p); |
446 |
The \textit{wake\_up\_forked\_process} adds the newly created process to the runqueue and activates it.In order to activate task, it is queued at the tail of the runqueue using enqueue\_task function and the priority bitmap of the task is also updated. Refer to \url{kernel/sched.c} for detail functions. The exclusive operations related to runqueues are performed within the \textit{rq\_lock} and \textit{rq\_unlcok} function block. These functions enable and disable interrupts(irqs) on local cpu [cpu corresponding to the runqueue, usually refered by using \textit{smp\_processor\_id()} macro.] in addition to using spin\_lock. |
p->pid = get_pid(clone_flags); |
447 |
|
p->proc_dentry = NULL; |
448 |
\subsection{ABI: Application binary interface} |
|
449 |
% TODO ABI |
\end{verbatim} |
450 |
|
|
451 |
\section{Destroying process} |
Linux kernel has the ability to execute the binaries compiled for other operating systems (assuming kernel compatible machine code). The execution domain for the running thread is specified by the structure exec\_domain defined in \url{include/linux/personality.h} \footnote{map\_segment TODO }. The structure defines various personalities of the target execution environment supported by the kernel. e.g. PER\_LINUX for linux systems, PER\_BSD for bsd unix. The personality value is set by \textit{personality()} system call. the macro \textit{get\_exec\_domain} is used to increament the module count of the module associated with the \textit{exec\_domain} while its counterpart \textit{put\_exec\_domain} is used to decrement it. |
452 |
There are several reasons for tasks to terminate: |
|
453 |
|
% TODO map_segment |
454 |
\begin{enumerate} |
\par Then, the kernel increaments the module's reference count only for modularised binary format. Then, it resets executed, swappable flags and sets task state to TASK\_UNINTERRUPTIBLE. The new flags are set for the process p, especially in case of \textit{sys\_clone} call. |
455 |
\item exit() system call or end of program. |
|
456 |
\item sending a signal with default disposition to die. |
\begin{verbatim} |
457 |
\item forcing a task to die when kernel receives exception running on behalf of process. |
|
458 |
\end{enumerate} |
/*** Initialize task wait queue, lists and pointers ***/ |
459 |
|
|
460 |
The sys\_exit function is defined in \url{kernel/exit.c} which calls function do\_exit(). The do\_exit function releases all the resources such as memory, open files, semaphores owned by the process. Following code explains the step by step process. |
INIT_LIST_HEAD(&p->run_list); |
461 |
|
|
462 |
\subsection{do\_exit function} |
INIT_LIST_HEAD(&p->children); |
463 |
\newline \par The code is explained below in parts. |
INIT_LIST_HEAD(&p->sibling); |
464 |
|
init_waitqueue_head(&p->wait_chldexit); |
465 |
\begin{verbatim} |
p->vfork_done = NULL; |
466 |
|
if (clone_flags & CLONE_VFORK) { |
467 |
struct task_struct *tsk = current; |
p->vfork_done = &vfork; |
468 |
|
init_completion(&vfork); |
469 |
if (in_interrupt()) |
} |
470 |
panic("Aiee, killing interrupt handler!"); |
spin_lock_init(&p->alloc_lock); |
471 |
if (!tsk->pid) |
|
472 |
panic("Attempted to kill the idle task!"); |
clear_tsk_thread_flag(p,TIF_SIGPENDING); |
473 |
if (tsk->pid == 1) |
init_sigpending(&p->pending); |
474 |
panic("Attempted to kill init!"); |
|
475 |
tsk->flags |= PF_EXITING; |
p->it_real_value = p->it_virt_value = p->it_prof_value = 0; |
476 |
del_timer_sync(&tsk->real_timer); |
p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0; |
477 |
|
|
478 |
if (unlikely(preempt_get_count())) |
/*** some initialization related to timer ***/ |
479 |
printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", |
|
480 |
current->comm, current->pid, |
init_timer(&p->real_timer); |
481 |
preempt_get_count()); |
p->real_timer.data = (unsigned long) p; |
482 |
|
|
483 |
\end{verbatim} |
p->leader = 0; /* session leadership doesn't inherit */ |
484 |
The \textit{"current"} task global variable always points to the current task running. The process can not be destroyed while executing an interrupt handler. The processes 0 (idle), 1 (init) can not be destroyed. The macro "unlikely" is GNU compiler version specific\footnote{defined in \url{include/linux/compiler.h}} and gets reduced to macro argument while the macro \textit{"preempt\_get\_count"} is SMP PRE-EMPTION specific and returns the preemption count. This value should be 0 while exiting the system call. |
p->tty_old_pgrp = 0; |
485 |
|
p->times.tms_utime = p->times.tms_stime = 0; |
486 |
\begin{verbatim} |
p->times.tms_cutime = p->times.tms_cstime = 0; |
487 |
|
|
488 |
acct_process(code); |
\end{verbatim} |
489 |
__exit_mm(tsk); |
|
490 |
|
The \textit{INIT\_LIST\_HEAD} macro is used to initialize the next and prev pointers of a linked list. Both the pointers are set to the macro argument, representing a circular linked list of a single element \footnote{Linked lists are described \url{include/linux/list.h}} while \textit{init\_waitqueue\_head} initializes the waitqueue header node which contains the spinlock along with the linked list. |
491 |
sem_exit(); |
\par The inline function \textit{clear\_tsk\_thread\_flag} (defined in \url{include/linux/sched.h}) calls \textit{clear\_ti\_thread\_flag} (defined in \url{include/linux/thread_info.h}) to clear the flag information of the thread within the task structure. |
492 |
__exit_files(tsk); |
|
493 |
__exit_fs(tsk); |
\index{bitops} \index{btrl} |
494 |
exit_namespace(tsk); |
\begin{verbatim} |
495 |
exit_sighand(tsk); |
|
496 |
exit_thread(); |
/*** File : {include/asm-i386/bitops.h} ***/ |
497 |
|
static __inline__ void clear_bit(int nr, volatile unsigned long * addr) |
498 |
if (current->leader) |
{ |
499 |
disassociate_ctty(1); |
__asm__ __volatile__( LOCK_PREFIX |
500 |
|
"btrl %1,%0" |
501 |
put_exec_domain(tsk->thread_info->exec_domain); |
:"=m" (ADDR) |
502 |
if (tsk->binfmt && tsk->binfmt->module) |
:"Ir" (nr)); |
503 |
__MOD_DEC_USE_COUNT(tsk->binfmt->module); |
} |
504 |
|
|
505 |
tsk->exit_code = code; |
\end{verbatim} |
506 |
exit_notify(); |
The assembly instruction \textit{"btrl"} tests a particular bit from a long word and then resets it. Thus, the bit number "nr" of the "addr" is cleared after this instruction with changes to ADDR. The \textit{LOCK\_PREFIX} is smp specific and used as \textit{"lock"} instruction for interprocessor locking. |
507 |
|
\par The function \textit{init\_completion} is wrapper inline function to initialize the wait queue header specially used during \textit{vfork()} system call. The function \textit{init\_sigpending} initializes the signal structure containing struct sigqueue\footnote{defined in \url{include/linux/signal.h}} and sigset\_t\footnote{defined in \url{include/asm-i386/signal.h}} structure. Refer to section ~\ref{sig:structs} for more details. The head and tail pointers of sigqueue are set to NULL to initialize the circular linked list of single element while the number of words per signal [\_NSIG\_WORDS] of sigset\_t structure are set to zero. |
508 |
\end{verbatim} |
\par The dynamic timer associated with the task structure is \textit{real\_timer}. When, a new task is created, the timer is initialized using \textit{init\_timer} and the data is field set to the newly created process p. Thus, the whole process structure is available to the function which is called when the timer expires. |
509 |
|
\begin{verbatim} |
510 |
The code removes memory, files, filesystem resources. All these steps are exactly opposite to those performed while creating the process (only in reverse order). |
|
511 |
\par Before exiting a process, the file information changed by the process should be updated. These task of process accounting is performrd by the "acct\_process" function \footnote{refer to \url{kernel/acct.c} for detail accounting}. |
#ifdef CONFIG_SMP |
512 |
% TODO details exit_namespace , exit_sighand, exit_thread |
{ |
513 |
|
int i; |
514 |
\begin{verbatim} |
|
515 |
|
/* ?? should we just memset this ?? */ |
516 |
schedule(); |
for(i = 0; i < smp_num_cpus; i++) |
517 |
BUG(); |
p->per_cpu_utime[cpu_logical_map(i)] = |
518 |
|
p->per_cpu_stime[cpu_logical_map(i)] = 0; |
519 |
\end{verbatim} |
spin_lock_init(&p->sigmask_lock); |
520 |
Finally, it calls the schedule() function and does not return. The function prototype in \url{include/linux/kernel.h} indicates it, too. Thus, a process deletion leads to rescheduling of all the processes. |
} |
521 |
\begin{verbatim} |
#endif |
522 |
NORET\_TYPE void do\_exit(long code) ATTRIB_NORET; |
|
523 |
/* # define NORET_TYPE /**/ |
\end{verbatim} |
524 |
# define ATTRIB_NORET __attribute__((noreturn)) |
This part of code is SMP specific. It resets the values of user timer (utime) and system time (stime) for all cpus for the current process. It also initializes the \textit{sigmask\_lock} used to block the signals by the process. Refer to ~\ref{sig:structs} for more details. |
525 |
*/ |
|
526 |
\end{verbatim} |
\begin{verbatim} |
527 |
|
|
528 |
|
p->array = NULL; |
529 |
|
p->lock_depth = -1; /* -1 = no lock */ |
530 |
|
p->start_time = jiffies; |
531 |
|
|
532 |
|
INIT_LIST_HEAD(&p->local_pages); |
533 |
|
|
534 |
|
retval = -ENOMEM; |
535 |
|
|
536 |
|
/*** copying all process resources ***/ |
537 |
|
|
538 |
|
/* copy all the process information */ |
539 |
|
if (copy_semundo(clone_flags, p)) |
540 |
|
goto bad_fork_cleanup; |
541 |
|
if (copy_files(clone_flags, p)) |
542 |
|
goto bad_fork_cleanup_semundo; |
543 |
|
if (copy_fs(clone_flags, p)) |
544 |
|
goto bad_fork_cleanup_files; |
545 |
|
if (copy_sighand(clone_flags, p)) |
546 |
|
goto bad_fork_cleanup_fs; |
547 |
|
if (copy_mm(clone_flags, p)) |
548 |
|
goto bad_fork_cleanup_sighand; |
549 |
|
if (copy_namespace(clone_flags, p)) |
550 |
|
goto bad_fork_cleanup_mm; |
551 |
|
retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs); |
552 |
|
|
553 |
|
\end{verbatim} |
554 |
|
The initial part of code sets the task starting time to jiffies.\footnote{jiffies contains the time right from the system startup and the value is incremented during every timer interrupt}. The final process execution time is updated during process accounting [do\_acct\_process function in \url{kernel/acct.c}]. |
555 |
|
\par Then, various system resources are copied to the newly created process. The following explains the the functions in short. |
556 |
|
\begin{itemize} |
557 |
|
\item copy\_semundo : This copies the sem\_undo\_list object from parent task to child. This object is required to avoid deadlock, when tasks are spawned with the semundo locks. Please refer to \url{ipc/sem.c} for details. |
558 |
|
\item copy\_files : This function [defined in \url{kernel/fork.c}] determines the number of open files by the parent process and copies those file descriptors to the child process. |
559 |
|
\item copy\_fs : This function [defined in \url{kernel/fork.c}] copies the file system information associated with the process [struct fs\_struct]. It contains elements like root, umask, pwd etc. |
560 |
|
\item copy\_sighand : This function copies all signal handlers actions from the parent to child process. Thus, all signals are inherited to child depending on clone\_flags. |
561 |
|
\item copy\_mm : This function [defined in \url{kernel/fork.c}] copies the memory resources form parent process to child [struct mm\_struct]. It is done by allocating new kmem\_cache for child process. |
562 |
|
\item copy\_namespace : This function [defined in \url{fs/namespace.c}] copies the namespace resources form parent process to child [struct namespace]. It is done by allocating new namespace in kernel to accomodate the new child task. |
563 |
|
\item copy\_thread : This function [defined in \url{arch/i386/kernel/process.c}] copies the thread information form parent process to child [struct thread\_struct]. This contains the stack pointer, instruction pointer. This thread structure contains the CPU specific state of the task. Refer to section ~\ref{sched:thread} for details about process thread. |
564 |
|
\end{itemize} |
565 |
|
\begin{verbatim} |
566 |
|
|
567 |
|
/*** Now, setup other process attributes ***/ |
568 |
|
|
569 |
|
p->parent_exec_id = p->self_exec_id; |
570 |
|
|
571 |
|
/* ok, now we should be set up.. */ |
572 |
|
p->swappable = 1; |
573 |
|
p->exit_signal = clone_flags & CSIGNAL; |
574 |
|
p->pdeath_signal = 0; |
575 |
|
|
576 |
|
\end{verbatim} |
577 |
|
The \textit{self\_exec\_id} and \textit{parent\_exec\_id} are set to same value after a fork. When the execution domain of a process changes, its self\_exec\_id is incremented. These values are checked while existing the process, only. The death\_signal [cause of death of a process] is reset to 0. The signal value 0 is unused. Signals are listed in \url{include/asm-i386/signal.h}. |
578 |
|
|
579 |
|
\begin{verbatim} |
580 |
|
|
581 |
|
/*** Sharing timeslice between child and parent ***/ |
582 |
|
|
583 |
|
__save_flags(flags); |
584 |
|
__cli(); |
585 |
|
p->time_slice = (current->time_slice + 1) >> 1; |
586 |
|
current->time_slice >>= 1; |
587 |
|
if (!current->time_slice) { |
588 |
|
current->time_slice = 1; |
589 |
|
scheduler_tick(0, 0); |
590 |
|
} |
591 |
|
p->sleep_timestamp = jiffies; |
592 |
|
__restore_flags(flags); |
593 |
|
|
594 |
|
\end{verbatim} |
595 |
|
Since the code updates the process time\_slice, the interrupts should be disabled during this operation. The macros \_\_save\_flags, \_\_cli are used to clear interrupts on the current CPU while \_\_restore\_flgs enables it again. |
596 |
|
\par When new child process is created, the \textit{time\_slice}\footnote{Renamed counter field of kernel version 2.2 to time\_slice in kernel 2.4} of the parent process is split into two halves, one for the parent process and the other for child process. This is done to prevent an unlimited access to CPU by a single process. If the parent process is created recently in terms of time\_slice (time\_slice == 0 or 1), then the scheduler is called to reschedule the processes with the user and system time parameters as zero. These parameter are used by the \textit{scheduler\_tick()} function to update the kernel statistics. |
597 |
|
|
598 |
|
\begin{verbatim} |
599 |
|
|
600 |
|
/*** Adding process info to Runqueue ***/ |
601 |
|
|
602 |
|
p->tgid = p->pid; |
603 |
|
INIT_LIST_HEAD(&p->thread_group); |
604 |
|
|
605 |
|
/* Need tasklist lock for parent etc handling! */ |
606 |
|
write_lock_irq(&tasklist_lock); |
607 |
|
|
608 |
|
/* CLONE_PARENT re-uses the old parent */ |
609 |
|
p->real_parent = current->real_parent; |
610 |
|
p->parent = current->parent; |
611 |
|
if (!(clone_flags & CLONE_PARENT)) { |
612 |
|
p->real_parent = current; |
613 |
|
if (!(p->ptrace & PT_PTRACED)) |
614 |
|
p->parent = current; |
615 |
|
} |
616 |
|
|
617 |
|
if (clone_flags & CLONE_THREAD) { |
618 |
|
p->tgid = current->tgid; |
619 |
|
list_add(&p->thread_group, ¤t->thread_group); |
620 |
|
} |
621 |
|
|
622 |
|
SET_LINKS(p); |
623 |
|
hash_pid(p); |
624 |
|
nr_threads++; |
625 |
|
write_unlock_irq(&tasklist_lock); |
626 |
|
|
627 |
|
\end{verbatim} |
628 |
|
At this point of time, all the resources required by the process are available. So, the process can get a chance to execute on the CPU and Hence, it needs to be added to list of runqueues. The newly created process acts as the leader of thread group and initializes itself. But if the flags contain CLONE\_THREAD, [i.e. new process is derived from some other process] then the thread leadership is retained to the thread leader of the calling process and newly created process is added to the linked list of its parents' thread [i.e. calling process's thread]. |
629 |
|
\par To set the parent child relationship for the newly created process, we need to access parent process also, Hence an irq lock is obtained. This lock will disable pre-eption on the SMP architecture. This lock is released when the process is added to runqueue. The macro SET\_LINKS inserts the new process in the linked list of process lists. Refer to list management in \url{include/linux/list.h}. |
630 |
|
\par \textbf{ |
631 |
|
\newline |
632 |
|
Hashing Process Ids } \index{hash\_pid} \label{hashpid} |
633 |
|
\newline |
634 |
|
\par All the process ids (pids) are hashed in a hashing table pidhash[PIDHASH\_SZ] defined in \url{include/linux/sched.h}. This is an array of pointers to task\_struct of size PIDHASH\_SZ\footnote{This value is currently hardcoded to [4096/4], but should be dynamic and should be set to [NR\_TASKS/4]}. This hashed pids avoid sequential scanning of the process list and thus, improves performance. The \textit{hash\_pid} function adds the new task to the hash table using process pid as key and pid\_fashfn as hashing function. |
635 |
|
|
636 |
|
\begin{verbatim} |
637 |
|
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1)) |
638 |
|
\end{verbatim} |
639 |
|
|
640 |
|
The nr\_threads value (total number of processes) is incremented. This value should not exceed max\_threads limit. And the irq lock is returned will re-enables the process pre-emption. |
641 |
|
|
642 |
|
\begin{verbatim} |
643 |
|
|
644 |
|
wake_up_forked_process(p); |
645 |
|
++total_forks; |
646 |
|
if (clone_flags & CLONE_VFORK) |
647 |
|
wait_for_completion(&vfork); |
648 |
|
else |
649 |
|
set_need_resched(); |
650 |
|
|
651 |
|
\end{verbatim} |
652 |
|
The \textit{wake\_up\_forked\_process} adds the newly created process to the runqueue and activates it. In order to activate task, it is queued at the tail of the runqueue using enqueue\_task function and the priority bitmap of the task is also updated. Refer to \url{kernel/sched.c} for detail functions. The exclusive operations related to runqueues are performed within the \textit{rq\_lock} and \textit{rq\_unlcok} function block. These functions enable and disable interrupts(irqs) on local cpu [cpu corresponding to the runqueue, usually referred by using \textit{smp\_processor\_id()} macro.] in addition to using spin\_lock. |
653 |
|
|
654 |
|
% \subsection{ABI: Application binary interface} |
655 |
|
% TODO ABI |
656 |
|
|
657 |
|
\section{Destroying process} |
658 |
|
There are several reasons for tasks to terminate: |
659 |
|
|
660 |
|
\begin{enumerate} |
661 |
|
\item exit() system call or end of program. |
662 |
|
\item sending a signal with default disposition to die. |
663 |
|
\item forcing a task to die when kernel receives exception running on behalf of process. |
664 |
|
\end{enumerate} |
665 |
|
|
666 |
|
The sys\_exit function is defined in \url{kernel/exit.c} which calls function do\_exit(). The do\_exit function releases all the resources such as memory, open files, semaphores owned by the process. Following code explains the step by step process. |
667 |
|
|
668 |
|
\subsection{do\_exit function} |
669 |
|
\\ \par The code is explained below in parts. |
670 |
|
|
671 |
|
\begin{verbatim} |
672 |
|
|
673 |
|
struct task_struct *tsk = current; |
674 |
|
|
675 |
|
if (in_interrupt()) |
676 |
|
panic("Aiee, killing interrupt handler!"); |
677 |
|
if (!tsk->pid) |
678 |
|
panic("Attempted to kill the idle task!"); |
679 |
|
if (tsk->pid == 1) |
680 |
|
panic("Attempted to kill init!"); |
681 |
|
tsk->flags |= PF_EXITING; |
682 |
|
del_timer_sync(&tsk->real_timer); |
683 |
|
|
684 |
|
if (unlikely(preempt_get_count())) |
685 |
|
printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", |
686 |
|
current->comm, current->pid, |
687 |
|
preempt_get_count()); |
688 |
|
|
689 |
|
\end{verbatim} |
690 |
|
The \textit{"current"} task global variable always points to the current task running. The process can not be destroyed while executing an interrupt handler. The processes 0 (idle), 1 (init) can not be destroyed. The macro "unlikely" is GNU compiler version specific\footnote{defined in \url{include/linux/compiler.h}} and gets reduced to macro argument while the macro \textit{"preempt\_get\_count"} is SMP PRE-EMPTION specific and returns the preemption count. This value should be 0 while exiting the system call. |
691 |
|
|
692 |
|
\begin{verbatim} |
693 |
|
|
694 |
|
acct_process(code); |
695 |
|
__exit_mm(tsk); |
696 |
|
|
697 |
|
sem_exit(); |
698 |
|
__exit_files(tsk); |
699 |
|
__exit_fs(tsk); |
700 |
|
exit_namespace(tsk); |
701 |
|
exit_sighand(tsk); |
702 |
|
exit_thread(); |
703 |
|
|
704 |
|
if (current->leader) |
705 |
|
disassociate_ctty(1); |
706 |
|
|
707 |
|
put_exec_domain(tsk->thread_info->exec_domain); |
708 |
|
if (tsk->binfmt && tsk->binfmt->module) |
709 |
|
__MOD_DEC_USE_COUNT(tsk->binfmt->module); |
710 |
|
|
711 |
|
tsk->exit_code = code; |
712 |
|
exit_notify(); |
713 |
|
|
714 |
|
\end{verbatim} |
715 |
|
|
716 |
|
The code removes memory, files, filesystem resources. All these steps are exactly opposite to those performed while creating the process (only in reverse order). |
717 |
|
\par Before exiting a process, the file information changed by the process should be updated. These task of process accounting is performed by the "acct\_process" function \footnote{Refer to \url{kernel/acct.c} for detail accounting}. |
718 |
|
\par The \textit{exit\_files} and \textit{exit\_fs} clean up the file system information associated with the process. They close the files opened by the process, free the fd and fdset arrays and also clear the kernel memory using \textit{kem\_cache\_free}. |
719 |
|
% TODO details exit_namespace ,put_exec_domain |
720 |
|
\par The \textit{exit\_sighand} function in \url{kernel/signal.c} set the process signal structure to NULL and free its allocated memory. The signal queue is flushed at this point of time, hence no pending signals remain for the process to be deleted. |
721 |
|
\par The \textit{exit\_thread} function clears the I/O permission bitmap\footnote{The I/O permission bitmap is a part of Task State Segment.(TSS) It is used as a priviledge check for I/O instructions like IN, OUT. The bit map is 8KB in size for i386 architecture, one bit for each of the addresses of 64 KB.} for the process.Please refer to section ~\ref{sched:thread} for details about process thread. |
722 |
|
\par The \textit{exit\_notify} function indicates others that the current process is exiting. All process, group, session related properties are updated in this function. Following chekcs are performed to maintain proper parent child relationship. |
723 |
|
\begin{itemize} |
724 |
|
\item Re-parent all the children of the exiting process, by trying to give them to another thread in thread group, and if no such member exists, give it to the global child reaper process (ie "init process".) |
725 |
|
\item Check to see if any process groups have become orphan as a result of exiting. |
726 |
|
\item If process groups have any stopped jobs, send them a SIGHUP and then a SIGCONT. |
727 |
|
\end{itemize} |
728 |
|
\begin{verbatim} |
729 |
|
|
730 |
|
schedule(); |
731 |
|
BUG(); |
732 |
|
|
733 |
|
\end{verbatim} |
734 |
|
Finally, it calls the schedule() function and does not return. The function prototype in \url{include/linux/kernel.h} indicates it, too. Thus, a process deletion leads to rescheduling of all the processes. |
735 |
|
\begin{verbatim} |
736 |
|
NORET\_TYPE void do\_exit(long code) ATTRIB_NORET; |
737 |
|
/* # define NORET_TYPE /**/ |
738 |
|
# define ATTRIB_NORET __attribute__((noreturn)) |
739 |
|
*/ |
740 |
|
\end{verbatim} |
741 |
|
|