728x90

운영체제 동작 이해

핵심 키워드: USER MODE || KERNEL MODE, SYSTEM CALL

시작하실때 교수님의 말씀: 운영체제는 User,kenel 모드로 나누어져 있으며 kenel 모드엔 user가 접근하지 못한다.
또한 kenel 모드에서 user모드가 시작된다. user는 system의 기능이 사용하고 싶을 때에는 즉, 하드웨어를 사용하고 싶을 때 system call를 사용한다. control은 kenel딴으로 넘어가며 system call이 끝나면 결과 완료를 user에게 넘겨준다.


In this interlude, we discuss process creation in Unix systems.

Unix system

Unix presents one of the most intriguing ways to create a new process with a pair of system calls: fork() and exec().
Wait() → It can be used by a process wishing to wait for a process it has created to complete.


HOW TO CREATE AND CONTROL PROCESS
What interfaces should the OS present for process creation and controls?
How should these interfaces be designed to enable ease of use as well as utility?

The fork() system call

The fork() system call is used to create a new process.
Pid: Process identifier is used to name the process if one wants to do something with the process.

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

int main(int argc, char *argv[]){
    printf("hello world (pid:%d)\n", (int) getpid());
    int rc = fork();
    if(rc < 0){ //fork failed; exit
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if(rc == 0){ //child (new process)
        printf("hello, I am child (pid:%d)\n", (int) getpid());
    } else { // parent goes down this path (main)
        printf("hello, I am parent of %d (pid: %d)\n",
        rc, (int) getpid());
    }
    return 0;
}

실행결과 
prompt > ./p1
hello world (pid:29146)
hello, I am parent of 29147 (pid:29146)
hello, I am child (pid: 29147)
prompt >

prompt > ./p1
hello world (pid:29146)
hello, I am child (pid: 29147)
hello, I am parent of 29147 (pid:29146)
prompt >

That means that to the OS, it now looks like there are two copies of the program p1 running, and both are about to return from the fork() system call.

  1. When it first started running
    The process prints out a hello world message, including PID
    → The process calls the fork() system call
    The OS provides as a way to create a new process
  2. else or else if가 실행된다.

The process that is created is an (almost) exact copy of the calling process → the newly-created process (called the child) doesn't start running at main().

  • child process start fork() system call line next. -
    ●The newly-created process isn't an exact copy. Specifically, although it now has its own copy of the address space(i.e., its own private memory) its own registers, its own PC, and so forth, the value it returns to the caller of fork() is different.

여러개의 프로그램이 병렬적으로 존재시 어떤 프로그램을 실행시킬지는 Scheduler가 결정한다.


The CPU scheduler, a topic we'll discuss in great detail soon, determines which process runs at a given moment in time.
we cannot usually make strong assumptions about what it will choose to do, and hence which process will run first.
This nondeterminism, as it turns out, leads to some interestin problems, particularly in muti-threaded programs.


❔🤗 Q. Child process 와 Parent Process는 병렬적으로 실행된다. 하지만 반복문이 아닌데 두번이 실행되는 것이 이해가 되지 않는다.
일단 fork() 함수의 return 값을 알아본다. 그 후 다시 한번 fork()이후 instrution이 실행된다는 것을 알아두자.

fork() system call의 반환 값

fork() 함수가 실행된 후 child process가 생성되면 fork() 다음 instruction부터 시작된다.
fork() 실행 후 child, parent 두 개의 프로세스는 Hello 메세지를 출력한다.
이게 바로 반복문이 아니지만 두 개의 프로세스가 존재하여 두번 실행되는 현상이다.

단순히 두번 실행된다. 반복문은 없지만 이 프로세스가 두개라 두번이 실행된다.

Hello가 8번 실행되는데 이는 곧 프로세스 수를 가리킨다.
프로세스 수는 2^n이다. n은 fork() 수 다.

어떤 식으로 fork()가 진행되었는지 보여준다.

fork()가 어떤 방식으로 보여주는 gif이다.

이정도 설명이면 이해가 될 거다.


The wait() system call

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char *argv[]){
    printf("hello world (pid:%d)\n", (int) getpid());
    int rc = fork();
    if(rc < 0){ //fork failed; exit
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if(rc == 0){ //child (new process)
        printf("hello, I am child (pid:%d)\n", (int) getpid());
    } else { // parent goes down this path (main)
        int rc_wait = wait(NULL);
        printf("hello, I am parent of %d (rc_wait:%d) (pid: %d)\n",
         rc, rc_wait, (int) getpid());
    }
    return 0;
}

실행 결과
prompt> ./p2
hello world (pid:29266)
hello, I am child (pid:29267)
hello, I am parent of 29267 (wc:29267) (pid:29266)
prompt>

It is quite useful for a process to wait for another process to finish.
// wait()는 그렇게 어렵지 않는 내용이다.
Parent Process는 wait(NULL);로 인해서 child process가 끝날 때까지 기다리게 다음에 실행하게 된다.


The exec() System call

This systems call is useful when you want to run a program that is different from the calling program.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>

int main(int argc, char *argv[]){
    printf("hello world (pid:%d)\n", (int) getpid());
    int rc = fork();
    if(rc < 0){ // fork failed; exit
        fprintf(stderr, "fork failed\n");
        exit(1);
    } else if(rc == 0){ //child (new process)
        printf("hello, I am child (pid:%d)\n", (int) getpid());
        char *myargs[3];
        myargs[0] = strdup("wc"); // program: "wc" (word count) wc는 명령어
        myargs[1] = strdup("p3.c"); // argument: file to count  p3.c는 현재 프로그램
        myargs[2] = NULL; /* marks end of array execvp는 자신에게 주어지는 string 
                끝에 NULL로 존재해달라고 요구 */
        execvp(myargs[0], myargs); // runs word count // execvp = exec family.
        printf("this shouldn't print out");
    } else {
        int rc_wait = wait(NULL);
        printf("hello, I am parent of %d (rc_wait:%d) (pid:%d)\n",
                rc, rc_wait, (int) getpid());
    }
    return 0;
}
실행 결과
prompt> ./p3
hello world (pid:29383)
hello, I am child (pid:29384)
      29     107     1030    p3.c
hello, I am parent of 29384 (wc:29384) (pid:29383)
prompt>

Given the name of an executable, and some arguments, exec() loads code ( and static data) from that executable and overwrites its current code segment (and current static data) with it →
The heap and stack and other parts of the memory space of the program are re-initialized →
Then the OS simply runs that program, passing in any arguments as the argv of that process.

🕳Thus, exec() does not create a new process; rather, it transforms the currently running program into a different running program.

often you want to run a different program; exec() does just that.
In this example, the child process calls execvp() in order to run the program wc, which is the word counting program. In fact, it runs wc on the source file p3.c, thus telling us how many lines, words, and bytes are found in the file. ← 소스 코드 안에 다 적혀 있는 내용이다.


👀 출처 : Geeks for Geeks

GeeksforGeeks | A computer science portal for geeks

반응형

+ Recent posts