2025q1 Questions

2025-5-30

Traps 與 system calls 的差別?

System calls 是由 user program 要執行 privileged operations (e.g. I/O) 需切換到 kernel mode 的操作。
Traps 是 CPU 層面的 error 導致要切換到 kernel mode 的操作。

Signal 的運作原理 (e.g. SEGSIGV)?

Why exec() never returns (if successful)?

舉例來說,當行程 A forks B 時,如果 B 執行了 exec() 那麼行程 B 的 stack 和 address space 都會被 新的執行程式覆蓋,所以不會 return。

使用 watch command 輸出結果與直接執行的結果不一致

在研讀 OSTEP - Process API 時,有一段程式碼如下方。

#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 (original process)
        printf("hello, I am parent of %d (pid:%d)\n",
	       rc, (int) getpid());
    }
    return 0;
}

在使用 $ ./p1 去執行的結果如下:

hello world (pid:79862)
hello, I am parent of 79863 (pid:79862)
hello, I am child (pid:79863)

在使用 $ watch -n 1 ./p1 去執行的結果如下:

Every 1.0s: ./p1

hello world (pid:80079)
hello, I am parent of 80080 (pid:80079)
hello world (pid:80079)
hello, I am child (pid:80080)

為什麼會發生這樣的情況呢?

什麼是 process image?

Usage of execl()

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

int main(void) {
    int p1 = fork();
    if (p1 < 0) {
        fprintf(stderr, "fork failed\n");
        exit(EXIT_FAILURE);
    } else if (p1 == 0) {
        execl("/bin/ls", "", "-la", (char*) NULL); // why we need an extra "" as argument?
    } else {
        wait(NULL);
    }
    return EXIT_SUCCESS;
}

What are environment variables in UNIX?

Why doesn't this program run infinitely?

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

int main(void) {
    pid_t p_pid = getpid();
    printf("Parent PID: %d\n", p_pid);
    int fork_rc = fork();
    if (fork_rc < 0) {
        fprintf(stderr, "fork failed.");
        exit(EXIT_FAILURE);
    } else if (fork_rc == 0) {
        printf("Child PID: %d\n", (int) getpid());
        waitpid(p_pid, NULL, 0);
    } else {
        int wait_rc = waitpid(fork_rc, NULL, 0);
        printf("wait_rc: %d\n", wait_rc);
    }
    return EXIT_SUCCESS;
}

What is the pipe() system call?

  • pipe() creates a pipe, a unidirectional data channel that can be used for interprocess communication.
  • pipe() can connect stdout of one process to stdin of antoher process.

What happens when you use printf after closing stdout?

stack overflow

  • line buffer vs. block buffer
  • stderr is unbuffered
  • fflush(), fsync()
  • -1 Bad file descriptor

Why close unused fd?

pipe(2)
pipe(7)

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

int main(void) {
    int pipefd[2];
    char* buf;
    pid_t cpid1;
    pid_t cpid2;

    if (pipe(pipefd) == -1) {
        perror("pipe");
        exit(EXIT_FAILURE);
    }

    cpid1 = fork();
    if (cpid1 == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    } else if (cpid1 == 0) {
        close(pipefd[0]);
        char* str = "Hello my friend!\n";
        write(pipefd[1], str, strlen(str));
        close(pipefd[1]);
        exit(EXIT_SUCCESS);
    }

    cpid2 = fork();
    if (cpid2 == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    } else if (cpid2 == 0) {
        close(pipefd[1]);
        while (read(pipefd[0], &buf, 1) > 0)
            write(STDOUT_FILENO, &buf, 1);
        close(pipefd[0]);
        exit(EXIT_SUCCESS);
    } else {
        wait(NULL);
    }

    return EXIT_SUCCESS;
}

Procedure calls vs. system calls. Traps vs. trap handlers vs. trap instructions. What is "traped into the OS"?

ASIDE: WHY SYSTEM CALLS LOOK LIKE PROCEDURE CALLS
You may wonder why a call to a system call, such as open() or read(), looks exactly like a typical procedure call in C; that is, if it looks just like a procedure call, how does the system know it’s a system call, and do all the right stuff? The simple reason: it is a procedure call, but hidden inside that procedure call is the famous trap instruction. More specifically, when you call open() (for example), you are executing a procedure call into the C library. Therein, whether for open() or any of the other system calls provided, the library uses an agreed-upon calling convention with the kernel to put the arguments to open() in well-known locations (e.g., on the stack, or in specific registers), puts the system-call number into a well-known location as well (again, onto the stack or a register), and then executes the aforementioned trap instruction. The code in the library after the trap unpacks return values and returns control to the program that issued the system call. Thus, the parts of the C library that make system calls are hand-coded in assembly, as they need to carefully follow convention in order to process arguments and return values correctly, as well as execute the hardware-specific trap instruction. And now you know why you personally don’t have to write assembly code to trap into an OS; somebody has already written that assembly for you.

What are handlers?

What is fused multiply add (FMA)?

Select a repo