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: 销毁当前状态机。在对这个概念有了绝对正确且绝对严谨的理解后,操作系统也就显得不那么神秘了。