11, Process creation
Linux process creation can be divided into two steps, the fork () and the Exec () function, fork () is responsible for creating a child process, and the parent process is only the PID ppid and some statistics, the EXEC () function is responsible for reading the executable file load address space run.
Fork () function prototype
pid_t fork (void); The child process returns 0, and the parent process returns the Pid,fork () function of the child process one time to create two returns.
Implementation of the fork () function
Fork () uses the technique of write-time copy (Copy-on-write), where the parent process and child processes have the same address space when the child process is created (these zones are set to read-only), and the parent process-related address space is copied only when the child process or parent process is writing the data. The parent-child process points to the same physical memory.
After fork () is whether the parent process executes first or the child process is indeterminate, the parent-child process created by the fork () function is a file table entry, and Linux implements the fork () function through the clone () system call.
Another way to create a child process is to call the Vfork () function, the difference between the vfork () and the fork () function is that the vfork () function does not copy the page table of the parent process, and the child process runs first in the address space of the parent process until the child process exits, and the parent process can continue to run. Another hidden danger of the vfork () function is that once a child process calls the Exec () function execution fails ....
Fork () Function Example:
[CPP]View Plaincopy
- #include <stdio.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <errno.h>
- int glob = 5;
- Char buf[] ="A write to stdout\n";
- int main (void)
- {
- int var;
- pid_t pid;
- var = 88;
- if (Write (Stdout_fileno,buf, (sizeof (BUF)-1))! = (sizeof (BUF)-1))
- printf ("Write error\n");
- printf ("before fork\n");
- if ((PID = fork ()) < 0)
- {
- printf ("fork error\n");
- }
- Else if (pid = = 0)
- {
- glob++;
- var++;
- }
- Else
- {
- Sleep (2);
- }
- printf ("pid =%d,glob =%d, var =%d\n", Getpid (), Glob,var);
- Exit (0);
- }
- The output is as follows:
- ./a.out
- A write to stdout
- Before fork
- PID = 430,glob = 7, var = 89
- PID = 429,glob = 6, var = 88
[CPP]View Plaincopy
- The Vfork () sample program is as follows:
- #include <stdio.h>
- #include <signal.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <errno.h>
- int glob = 5;
- Char buf[] ="A write to stdout\n";
- int main (void)
- {
- int var;
- pid_t pid;
- var = 88;
- if (Write (Stdout_fileno,buf, (sizeof (BUF)-1))! = (sizeof (BUF)-1))
- printf ("Write error\n");
- printf ("before fork\n");
- if (PID = Vfork ()) < 0)
- {
- printf ("fork error\n");
- }
- Else if (pid = = 0)
- {
- glob++;
- var++;
- //exit (0);
- }
- Else
- {
- Sleep (2);
- }
- printf ("pid =%d,glob =%d, var =%d\n", Getpid (), Glob,var);
- Exit (0);
- }
- The function output is as follows:
- ./a.out
- Before fork
- PID = 29039,glob = 7,var =89
- The child process adds 1 to the variable. The result changes the value of the variable in the parent process because the child process is the same as the parent process's address space.
The instance program for parent-child process communication is as follows:
[CPP]View Plaincopy
- #define Recovery_api_version 2.3.1
- Const char* binary = "/tmp/update_binary";
- int pipefd[2];
- pipe [PIPEFD];
- Const char** args = (const char**) malloc (sizeof (char*));
- Args[0]=binary;
- Args[1]=recovery_api_version;
- Char *temp = (char*) malloc (10);
- sprintf (temp,"%d", pipefd[1]);
- Args[2]=temp;
- args[3]= (char*) path;
- Args[4]=null;
- pid_t pid = fork ();
- if (PID = = 0)
- {
- Close (pipefd[1]);
- EXECV (binary, (char*const*) args));
- printf (Exec child process error);
- _exit (-1);
- }
- Close (pipefd[1]);
- Char buffer[1024];
- file* from_child = Fdopen (pipefd[0],"R");
- while (fgets (buffer,sizeof (buffer), from_child)!=null)
- Char*command = strtok (buffer,"\ n");
- Waitpid (pid,&status,0)
Fork () function system call
The entry point for the fork () function system call is the Sys_fork () function, and ultimately the do_fork () function that calls the kernel (the function is architecture-independent)
[CPP]View Plaincopy
- Asmlinkage int sysfork ()
- {
- return Do_fork (sigchld,regs.regs->arm_sp,®s,null,null)
- }
As can be known from the above code, the SIGCHLD signal is sent to notify the parent process when the child process ends.
The Do_fork () function calls the Copy_process () function primarily, the copy_process () function returns a new task_struct struct, and the copy_process () function calls the Dup_task_struct () function, The child created at this time
The process and the original parent process have only one parameter, that is, Task_struct->stack,stack is usually saved in a union with Thread_info,
Process Environment:
Take the main () function of C as an example: the main () function is prototyped as follows:
int main (int argc,int *argv[]);
C program's storage space layout
Body segment BSS segment initialization data segment stack heap
Add: Exec Family functions
[CPP]View Plaincopy
- extern Char **environ;
- int execl (const Char *path, const char *arg, ...);
- int EXECLP (const Char *file, const char *arg, ...);
- int execle (const Char *path, const char *arg, ..., char * const envp[]);
- int Execv (const Char *path, char *const argv[]);
- int EXECVP (const Char *file, char *const argv[]);
- int Execve (const Char *filename, char *const argv[], char *const envp[]);
- The sample program is as follows:
- Example
- #include <stdio.h>
- #include <unistd.h>
- int main ()
- {
- Execl ("/bin/ls","ls","-l", NULL);
- printf ("If execl execution fails, this will print out \ n");
- return 1;
- }
12, Kernel thread
12, Kernel thread
The kernel often needs to perform some operations in the background, kernel threads, which are standard processes running independently of kernel space, the difference between kernel threads and normal processes is that the kernel thread does not have a separate address space (in fact its mm pointer is set to NULL). They only run in kernel space, never switch to user space, kernel processes and normal processes can be scheduled, can be preempted, Linux does have some tasks to the kernel thread to do, such as Pdflush and ksoftirqd these tasks are obvious examples, Kernel threads can only be created by other kernel threads, and in general, kernel threads will always execute the functions that they get when they are created, unless the system restarts.
Creation of kernel Threads:
pid_t kernel_thread (int (*FN) (void *), void *arg, unsigned long flags)
Here's how to create a new kernel thread from an existing kernel thread:
struct task_struct *kthread_creat (int (*THREADFN) (void *data), void *data,const char namefmt[] ....);
The new thread will run the THREADFN function, pass the parameter to it as data, and the thread name NAMEFMT,
The newly created thread is in a non-operational state and is to be run by wake_up_process () or the following function
struct task_struct *kthread_run (int (*THREADFN) (void *data), void *data,const char namefmt[] ....)
Kernel thread exit:
The kernel thread starts running until the Do_exit () function is called, or the function int kthread_stop (struct task_struct *k) is called, and the argument passed to Kthread_stop is Kthread_creat () The address of the task_struct returned by the function
Instance:
Creating Threads
[CPP]View Plaincopy
- struct Task_struct *thread_task;
- int RC;
- Thread_task=kthread_create (Fsg_main_thread,common,"File-storage");
- if (Is_err (Thread_task))
- {
- rc = Ptr_err (thread_task);
- return err_ptr (RC);
- }
- Wake_up_process (Thread_task);
13, Process exit
Through the normal process end, through the signal, or through the call to the Exit function, regardless of how the process exits, the process ends with the help of the kernel function do_exit (in alps/kernel/kernel/ In exit.c), the process's resource reclamation is separated from the process descriptor collection, and the process descriptor is retracted after the wait () function of its parent process returns ~
Supplemental: UNIX Environment Process Exception exit situation
Below is a blog that references the following URLs: http://www.ibm.com/developerworks/cn/aix/library/1206_xiejd_unixexception/
Process exceptions can be broadly divided into two categories:
One: Sending a signal to the process causes the process to exit abnormally
Two: The code itself error causes the process to exit
First class: Sending a signal to a process causes the process to exit:
(1) Sending a signal to the process causes the process to exit, the process receives a signal may cause the process to exit and produce a coredump file, in the UNIX environment there are three ways to send the signal to the target process, causing the process to exit unexpectedly.
Mode one: Call function Kill () send signal, prototype is int kill (pid_t pid,int Sig)
The following code is the sample code:
[CPP]View Plaincopy
- 1 #include <sys/types.h>
- 2 #include <signal.h>
- 3
- 4 int main (int argc, char* argv[])
- 5 {
- 6 char* pid = argv[1];
- 7 int pid = atoi (PID);
- 8
- 9 Kill (PID, SIGSEGV);
- return 0;
- 11}
Mode two: Run the kill command to send a signal
Format is Kill Sigxxx PID
Mode three: Use the keyboard to send signals at the terminal
Using Control-c to send a SIGINT signal, using control-\ to send a sigquit signal, using control-z to send a SIGTSTP signal, how to prevent this kind of signal arrival cause signal exit? By calling the signal function to bind the signal handler to deal with the arrival of the signal void (*signal (int sig, void (*func))) (int)), insert the following code to achieve the shielding signal SIGINT effect (void) signal (S Igint, sig_ign);
Class II: Programming errors cause the process to exit abnormally
When the process performs an illegal operation, the computer throws a processor exception, which refers to the soft interrupts, which is the processor exception caused by the illegal operation of the process, which is a synchronous exception caused by the illegal operation of the process, such as memory protection exception, except 0 exception, missing pages exception, and so on. The system assigns exception handlers to each exception, and invokes the corresponding exception handler when there is an exception.
Example Analysis:
(1) Invalid memory Access instance
[CPP]View Plaincopy
- 1 #include <stdio.h>
- 2 int main ()
- 3 {
- 4 char* str = "Hello";
- 5 Str[0] = ' H ';
- 6 return 0;
- 7}
(2) Except 0 exceptions
[CPP]View Plaincopy
- 1 #include <stdio.h>
- 2
- 3 int main ()
- 4 {
- 5 int a = 1, b = 0, C;
- 6 printf ( "Start running\n");
- 7 C = A/b;
- 8 printf ( "About to quit\n");
- 9}
How to debug a problem with a process exception
(1) Analyze the cause of abnormal exit using Coredump file
[Linux] Process (iv)--creation of a process