GPT
- https://github.com/ggerganov/llama.cpp
 - https://github.com/karpathy/llm.c
 - https://jyywiki.cn/OS/2024/labs/M3.md
 
AI
- https://microsoft.github.io/AI-For-Beginners/
 - https://github.com/Microsoft/AI-For-Beginners
 
第一个进程
Firmware 阶段
- CPU Reset 后,Firmware 代码开始执行
 - 加载操作系统 操作系统初始化阶段
 - 操作系统扫描系统中的硬件、初始化数据结构……
 - 加载第一个进程 (状态机) 操作系统执行阶段
 - 状态机在 CPU 上执行
 - 允许执行 syscall 进入操作系统代码
 
人工智能就能帮你实现
- 我希望用 QEMU 在给定的 Linux 内核完成初始化后,直接执行我自己编写的一个 hello 二进制文件。我应该怎么做?
 - 在这个过程中,发散出很多概念 → 知识体系的快速建立
 
fork()
pstree
#include <stdio.h>  
#include <unistd.h>  
  
int main() {
    pid_t x = fork();
    pid_t y = fork();
    printf("%d %d\n", x, y);
    return 0;
}
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <sys/wait.h>  
  
int main() {
    printf("main PID is %d\n", getpid());  
    pid_t pid; // 声明一个 pid_t 类型的变量,用于存储进程 ID  
    pid = fork();
  
    if (pid < 0) { 
        // fork() 失败  
        fprintf(stderr, "Fork Failed");  
        return 1;  
    }  
  
    if (pid == 0) { 
        // 子进程  
        printf("I am the child process. My PID is %d and my parent's PID is %d.\n", getpid(), getppid());  
    } else { 
        // 父进程  
        printf("I am the parent process. My PID is %d and my child's PID is %d.\n", getpid(), pid);  
        // 等待子进程结束  
        int status;  
        waitpid(pid, &status, 0);
    }  
  
    return 0;  
}
/*
main PID is 28049
I am the parent process. My PID is 28049 and my child's PID is 28055.
I am the child process. My PID is 28055 and my parent's PID is 28049.
*/
fork bomb
:(){:|:&};:
测验
#include <stdio.h>  
#include <unistd.h>  
  
int main() {
    for (int i = 0; i < 2; i++) {
        fork();
        printf("Hello\n");
    }
}
// ./a.out
// ./a.out | cat
// ./a.out | wc -l
execve (重置状态机)
int execve(const char *filename,
           char * const argv[], char * const envp[]);
将当前进程重置成一个可执行文件描述状态机的初始状态
int pid = fork();
if (pid == -1) {
    perror("fork"); goto fail;
} else if (pid == 0) {
    // Child
    execve(...);
    perror("execve"); goto fail;
} else {
    // Parent
    ...
}
实践
#include <stdio.h>  
#include <unistd.h>  
  
int main() {
    char *const argv[] = {"/bin/bash", "-c", "env", NULL};
    char *const envp[] = {"HELLO=WORLD", NULL};
    execve(argv[0], argv, envp);
    printf("hello\n");
}
strace ./a.out
_exit() 系统调用
void _exit(int status);
立即摧毁状态机,允许有一个返回值
除了 libc 为我们提供的 exit 函数之外,Linux 提供了两个系统调用:exit 和 exit_group,它们可以在 syscalls(2) 的手册中看到。同时,你也可以在这份手册中看到 Linux 肩负的 “历史包袱”。strace 可以查看应用程序是如何 “退出” 的。
Take-away Messages
因为 “程序 = 状态机”,操作系统上进程 (运行的程序) 管理的 API 很自然地就是状态机的管理。在 UNIX/Linux 世界中,以下三个系统调用创建了整个 “进程世界”,不论是我们常用的 IDE 和浏览器,还是编译时在后台调用的 gcc。其中,fork 对当前状态机状态进行完整复制,execve 将当前状态机状态重置为某个可执行文件描述的状态机,exit: 销毁当前状态机。在对这个概念有了绝对正确且绝对严谨的理解后,操作系统也就显得不那么神秘了。