当前位置:网站首页>[ostep] 02 virtualized CPU - process

[ostep] 02 virtualized CPU - process

2022-07-26 14:13:00 High power

process (process)

Process abstraction

Process is one of the most basic abstractions .

The informal definition of a process is very simple : It's the process It's a running program . The program itself has no life cycle , It's just some instructions on the disk ( Or maybe It's some static data ). It's the operating system that makes these bytes run , Let the program work .

The operating system decides when to make CPU Run instructions for where , By constantly switching the instructions of different programs in memory , Class abstracts the illusion of executing multiple processes at the same time .

It can be naturally associated with IO Interrupt mode , He did it in a way similar to callback , Make CPU Interrupt the currently running program , Close the interrupt , And press the breakpoint address on the stack , Open the interrupt , Jump to the memory space pointed by the interrupt vector , Service interruption will Save the current scene , Such as register status , After the service, we will Site recovery .

This save and restore is very much like the context switching of the operating system to the process .

In order to find out what we want to save and restore , You have to figure out what a process will use , Or say , In the abstraction of the operating system , What constitutes a process . Here is a noun to describe him —— The state of the machine (machine state).

Machine state includes main memory and register state , The main memory state is the main memory space used by the process , At the same time, the process will also use registers ( also PC And other special registers ).

Strategy (policy) And mechanism (mechanism), When implementing the operating system , Strategies and mechanisms will be divided into two modules . It can be understood in this way , Mechanisms are the details and components of strategies , For example, in the scheduling strategy of the program (scheduling policy) in , Context switching is called a mechanism , The strategy is to choose which process to switch context .

Describe the process

data structure

xv6 Of proc structure :

// the registers xv6 will save and restore$
// to stop and subsequently restart a process
struct context {
     
    int eip; 
    int esp; 
    int ebx; 
    int ecx; 
    int edx; 
    int esi;
    int edi; 
    int ebp;
};

// the different states a process can be in 
enum proc_state {
     UNUSED, EMBRYO, SLEEPING, RUNNABLE, RUNNING, ZOMBIE };

// the information xv6 tracks about each process 
// including its register context and state 
struct proc {
     
    char *mem;                  // Start of process memory
    uint sz;                    // Size of process memory
    char *kstack;               // Bottom of kernel stack ocessfor this process
    enum proc_state state;      // Process state 
    int pid;                    // Process ID
    struct proc *parent;        // Parent process
    void *chan;                 // If non-zero, sleeping on chan
    int killed;                 // If non-zero, have been killed
    struct file *ofile[NOFILE]; // Open files
    struct inode *cwd;          // Current directory 
    struct context context;     // Switch here to run process
    struct trapframe *tf;       // Trap frame for the // current interrupt
};

Process status

A process has many states , Mainly : function (running)、 be ready (ready) And blocking (blocked).

OS Some thread operations will be provided API, They will at least include these : establish (create)、 The destruction (destroy)、 wait for (wait)、 state (state) And other control interfaces (miscellaneous control).

Process creation

OS The code and static data will be loaded into the main memory space , But before that, you need to allocate the stack space of the process ( Runtime stack run time stack).

There are other initialization tasks , for example IO, stay UNIX in , Each process has three file handles by default , Used to input 、 Output and errors .

Finally, jump to the entry address of the process , Make CPU Start executing the next machine instructions .

system call example

fork

fork yes linux Next, the system call used to create the process .( Note that it's a process, not a thread )

This interface is a little strange , But it's very consistent fork The original meaning of —— Bifurcation , When it is called in a process , The current process and child processes will be connected from fork Call return , Only the return value of the child process is 0 , The parent process returns the process of the child process id( When Return value less than 0 When represents an error ).

The simplest encapsulation of the creation process is given below :

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int createThread(void(*callback)(void)) {
    
    fflush(stdout); fflush(stdin); fflush(stderr);
    int rc = fork();
    if (rc < 0) {
    
        exit(1);
    } else if (rc == 0) {
     
        callback(); exit(0);
    }
    return rc;
}

Because the buffer will be copied completely when the process is created , In order to avoid unnecessary things in the sub process buffer , We first refreshed it .

Then we call fork, The main process starts from fork Return without entering any of the following conditional branches , And the subprocess will enter the second conditional branch , call callback Post destruction .

The destruction of subprocesses here is very important , Otherwise, the subprocess will also start from createThread The function returns , Execute the logic of the main process , Unless it is necessary for us to do so , Otherwise, it's better to destroy him directly .

wait

wait Used to wait for a child process to end , The waiting subprocesses are called in turn in the order of creation , At the end of the subprocess , The parent process will be from wait The call returns .

One more waitpid, You can provide a specific pid To wait for , Check specifically man.

exec

exec Used to execute other programs , call exec after , The current process will load code and static data from a given executable , Overwrite your own code snippets and static data , The stack will also be reinitialized , At the same time, pass the parameters to the process , Start execution .

Example :

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "thread.h"

void thread() {
    
    execl("/bin/ls", "ls", "-al", NULL);
}

int main(int argc, char* argv[]) {
    
    createThread(thread);
    return 0;
}

exec Series of system calls :exec[v|l][p][e]

v, Indicates that the given parameter is in char* Give respectively ;

l, Represents the parameter list in char** give .

p, Said it would start from path Find programs and commands in variables , Don't give the full path .

e, Indicates the use of new environment variables .

Example :

char* args[] = {
    "ls", "-al", NULL};
char *env[] = {
    "AA=aa","BB=bb",NULL};

execv("/bin/ls", args);
execvp("ls", args);
execvpe("ls", args, env);

execl("/bin/ls", "ls", "-al", NULL);
execlp("ls", "ls", "-al", NULL);
execle("ls", "ls", "-al", NULL, env);

shell The implementation principle of is usually : First, through fork Create a subprocess , Then call in the subprocess exec To overwrite the current process , Finally through wait Wait for the subprocess to finish .

fork and exec Allow us to do some interesting work before creating another subprocess program , For example, redirect the output or input stream to a file :

$ wc ./thread.c > out

pipe

pipe It's a pipe , The structure is similar to queue , It can realize cross process communication ( Data sharing between processes is limited ).

c Prototype :

int pipe(int[2] fd);

return -1 Delegate error ,0 On behalf of success .

When the call returns ,fd The memory space pointed to will be written to two file handles in sequence ( Actually in memory ), One for reading , The other is used to write , And almost any standard can be used I/O Function to process .

for example work8.c:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "thread.h"

//  Pipe handle 
static int fd[2], readPipe, writePipe;

//  Subprocesses  1
void child1() {
    
    char buf[1024] = {
    0};
    printf("child1 in:");
    fflush(stdout);

    while (scanf("%s", buf) != -1) {
    
        //  from  stdin  read , write in  pipe
        write(writePipe, buf, sizeof(buf));
        memset(buf, 0, sizeof(buf));

        //  Give up  cpu, Let child process  2  Output 
        // ( This practice is not stable , Process synchronization lock should be realized through process shared memory , Not here )
        sleep(0);
        printf("child1 in: ");
        fflush(stdout);
    }
}

//  Subprocesses  2
void child2() {
    
    char buf[1024];
    while (read(readPipe, buf, sizeof(buf))) {
    
        printf("child2 out: ");
        printf(buf);
        printf("\n");
        fflush(stdout);
    }
}

int main() {
    
    //  Create pipes 
    if (pipe(fd) != -1) {
    
        readPipe = fd[0];
        writePipe = fd[1];
    } else {
    
        printf("error");
        exit(1);
    }

    //  Create a process 
    createThread(child1);
    createThread(child2);

    //  Main process daemon  1
    wait();

    return 0;
}

It will block when reading and writing , Opposite reading end , If there is no data, wait , Write side , If it has been written and not taken away by the reader , Is waiting for .

dup and dup2

Here are two more interesting functions dup and dup2

int dup (int oldfd)
int dup2 (int oldfd, int newfd)

shell A special syntax is allowed in , Of the subprocess to be run stdout Direct to a file ,

for example :

$ ls -alh > out.txt

Then let's take a look at out.txt:

ls The output of is directed to out.txt It's in .

$ cat out.txt
 Total usage  72K
drwxrwxr-x 2 devgaolihai devgaolihai 4.0K 12 month  31 18:21 .
drwxrwxr-x 6 devgaolihai devgaolihai 4.0K 12 month  31 17:58 ..
-rw-rw-r-- 1 devgaolihai devgaolihai  535 12 month  28 18:38 05_fork.c
-rwxrwxr-x 1 devgaolihai devgaolihai  17K 12 month  31 18:15 a.out
-rw-rw-r-- 1 devgaolihai devgaolihai  683 12 month  31 18:16 dup.c
-rw-rw-r-- 1 devgaolihai devgaolihai    0 12 month  31 18:21 out.txt
-rw-rw-r-- 1 devgaolihai devgaolihai  283 12 month  31 15:48 thread.h
-rw-rw-r-- 1 devgaolihai devgaolihai  314 12 month  29 22:19 threadTest.c
-rw-rw-r-- 1 devgaolihai devgaolihai  435 12 month  30 21:55 work1.c
-rw-rw-r-- 1 devgaolihai devgaolihai  372 12 month  31 17:35 work2.c
-rw-rw-r-- 1 devgaolihai devgaolihai  586 12 month  31 17:11 work3.c
-rw-rw-r-- 1 devgaolihai devgaolihai  884 12 month  31 17:29 work4.c
-rw-rw-r-- 1 devgaolihai devgaolihai  184 12 month  31 17:35 work7.c
-rw-rw-r-- 1 devgaolihai devgaolihai 1.2K 12 month  31 17:07 work8.c
-rwx------ 1 devgaolihai devgaolihai    9 12 month  31 18:15 work8_test.txt

This function can be done through dup2 Realization , Here's an example :

dup2 The file represented by the second parameter will be mapped to the file represented by the first parameter .

#include <fcntl.h>
#include <stdio.h>
#include "thread.h"

//  Subprocesses 
void child() {
    
    printf("child pro");
}

int main() {
    
    //  Is equivalent to  STDOUT_FILENO  become  target
    //  Later on  STDOUT_FILENO  The operation of all become right  target  The operation of 
    int target = open("./dup_out.txt", O_CREAT | O_TRUNC | O_RDWR, 0664);
    dup2(target, STDOUT_FILENO);
    createThread(child);

    return 0;
}

and dup Is another file handle of the file represented by the return parameter .

原网站

版权声明
本文为[High power]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/201/202207181735246655.html