
printf도 시스템 콜인가요? 그건 표준 C 라이브러리. 라이브러리가 write 시스템 콜을 호출함.
pid_t fork(void):
fork)을 사용해야 한다.fork()를 하면 동일한 프로세스가 만들어짐.pid_t getpid(void): 자신의 (진짜) PID.pid_t getppid(void): 부모의 PID.fork 직후의 인스트럭션을 실행한다.fork하는 시점의 메모리 섹션을 그대로 복제하므로, 변수도 fork 시점의 값을 갖는다.exec family:
exec("vi")하면 vi를 실행하는 프로세스가 됨.fork를 날리죠. 그러면 탐색기 프로세스가 하나 더 만들어집니다. 근데 파워포인트를 실행해야하니 exec로 스스로를 교체.void exit(int status):
pid_t wait(int *wstatus): 부모 프로세스는 wait 시스템 콜을 통해 자식의 반환 값을 기다림.pid_t waitpid(pid_t pid, int* status, int options): 특정 자식을 기다림.void abort(void): 특정 프로세스와 그 부모까지 삭제.wait를 하지 않는다면?init 프로세스의 자식으로 만든다. init은 주기적으로 wait을 호출해 자식을 정리.
task_struct로 구현된다.shm_opensend, receive를 이용해서 프로세스간 메시지 교환을 할 수 있음.sigaction으로 어떤 시그널을 받았을 때 어떤 행동을 하라고 정의할 수 있음.fork 어떤 시그널은 복사가 되지만, 어떤 시그널은 안 됨.pipe[1]에 쓴 값을 pipe[0]에서 읽을 수 있음. 프로세스 하나에서만 쓰면 그냥 버퍼같겠지.pipe[1]에 값을 쓰면 부모가 pipe[0]에서 읽을 수 있다. 물론 그 반대도 가능.
fork해서 두 개의 스레드로 분리, 각 스레드의 결과는 join으로 병합.#pragma omp parallel 같은 디렉티브를 만나면 코어 개수만큼 스레드를 만들고 알아서 병렬 처리.fork와 exec는 싱글코어를 상정한 것.fork하면 어떻게 되나? 스레드도 다 복사되나?
A call to forkall() replicates in the child process all of the threads in the parent process.
A call to fork1() replicates only the calling thread in the child process. (…) In Solaris 10, a call to fork() is identical to a call to fork1(); only the calling thread is replicated in the child process. This is the POSIX-specified behavior for fork().
forkall: 부모의 모든 스레드를 자식으로 복사한다. (강의에서는 fork로 소개함.)fork, fork1: 호출한 스레드만 복사한다.exec는 멀티스레딩이어도 상관없죠. 어떤 스레드 하나가 exec하면 그냥 프로세스의 모든 스레드가 죽음.for (i = 0; i < 10; i++) {
- LOCK();
- sum_global = sum_global + i
- UNLOCK();
sum_tls = sum_tls + i;
}
+ LOCK();
+ sum_global = sum_tls;
+ UNLOCK();
errno 값을 다룰 때도 유용하다:
errno를 -1로 설정, 이어서 들어온 다른 스레드가 errno를 0으로 덮는 문제.errno를 TLS로 만들면 문제를 해결할 수 있음.task_struct로 구현됨.
task_struct.clone:
clone() creates a new process, in a manner similar to fork(2). (…) The main use of clone() is to implement threads: multiple threads of control in a program that run concurrently in a shared memory space.
task_struct를 만든다.task_struct를 만들 수 있다. 즉, 스레드를 만드는 것.
bool ready = false;
void wait(void) {
while (!ready) {
do_nothing();
}
}
void signal(void) {
ready = true;
}
ready 변수를 레지스터에서 읽도록 최적화하면 문제가 생김.volatile 키워드를 사용하면 매번 메모리에서 변수를 읽도록 개발자가 강제할 수 있다.in == out일 때 empty, (in + 1) % SIZE == out일 때 full.in과 out을 비롯한 공유 자원에 접근하는 임계 영역에 락을 걸어주면 해결.
00004AFE가 들어오면, 00004는 VPN, AFE는 오프셋.00004를 참조한다. 여기에 대응되는 PFN이 6이라고 한다면…46AFE. 이때 46은 PFN, AFE는 오프셋.


fork가 매우 쉬워짐:
fork를 하면 부모의 페이지를 복사하는 대신, 자식이 부모와 같은 페이지 프레임을 바라봄.

malloc도 CoW로 동작한다:
malloc을 하는 시점에는 아무 일이 일어나지 않음.jmp 0xc0000100처럼 커널 주소공간으로 점프하면 커널의 시스템 콜을 실행.
!R && !M: 최근에 참조도 안 됐고, 수정도 안 됐으므로 바로 교체 가능.!R && M: 참조는 안됐는데 교체 전에 파일에 쓰기가 되어야 함.R && !M: 수정은 안 됐는데 조만간 다시 참조될 가능성이 높음.R && M: 최근에 참조됐고, 수정도 일어났음.malloc으로 공간 할당받고 GPU 작업을 수행하는 상황을 생각해보자./proc이나 /tmp 디렉토리..exe, .jpg처럼 이름에 표시.#!/bin/sh하는 것.
rm이 없고 unlink가 있음.