这张图按知识领域组织,说明每个领域由哪些练习覆盖、对应原书的哪一节。
按章节的顺序版本见 curriculum.md。
每个练习都可以用 ./lspling hint <exercise> 查看目标、书目出处和提示。
| 知识点 |
练习 |
书本出处 |
说明 |
| 直接用系统调用而不是 libc 封装 |
00_introduction/01_write_syscall |
第 1 章 System Calls、The C Library |
write(2) 的返回值、短写、EINTR 重试 |
| 头文件与特性测试宏 |
全部练习 |
第 1 章 Headers |
编译参数里固定了 _POSIX_C_SOURCE、_DEFAULT_SOURCE、_GNU_SOURCE |
| 运行期限制查询 |
00_introduction/09_sysconf_limits |
第 1 章 Getting Started with System Programming |
sysconf(_SC_OPEN_MAX) 等;-1 与 errno 的区分 |
| API 与 ABI 的区别 |
全部练习 |
第 1 章 APIs and ABIs |
练习只依赖源码级 API,不依赖二进制布局 |
| GNU C 扩展 |
11_gcc_extensions/* |
附录 A |
见下文第 13 节 |
| 知识点 |
练习 |
书本出处 |
说明 |
errno 与 strerror |
00_introduction/02_errno_strerror |
第 1 章 Error Handling |
失败后立刻读取 errno |
| errno 的保存与恢复 |
00_introduction/03_errno_saved |
第 1 章 Error Handling |
中间调用会破坏 errno,必须先存局部变量 |
| errno 分类与重试策略 |
00_introduction/08_errno_classification |
第 1 章 Error Handling 表 1-2 |
EINTR/EAGAIN 可重试,EACCES/EPERM 不可 |
| 检查返回值而不是只看 errno |
01_file_io/07_synchronized_io、03_advanced_file_io/09_posix_fadvise |
第 2 章 Synchronized I/O、第 4 章 posix_fadvise |
posix_fadvise/posix_fallocate 直接返回错误号 |
| 知识点 |
练习 |
书本出处 |
说明 |
| 文件描述符与标准 fd |
00_introduction/01_write_syscall |
第 2 章 File Descriptor |
0/1/2 与 STD*_FILENO |
open() 访问模式与 O_EXCL |
01_file_io/01_open_flags |
第 2 章 Opening Files、Flags for open |
原子创建、EEXIST |
creat() 与 O_TRUNC |
01_file_io/03_creat_and_truncate |
第 2 章 The creat() Function |
截断保留 inode |
文件模式与 umask |
01_file_io/02_umask_and_modes |
第 2 章 Permissions of New Files |
mode & ~umask |
| 读满整个缓冲区 |
01_file_io/04_read_all |
第 2 章 Reading All the Bytes |
短读循环、EOF |
| EINTR、EAGAIN、非阻塞 I/O |
01_file_io/05_eintr_and_eagain |
第 2 章 Nonblocking Reads |
fcntl(F_SETFL, O_NONBLOCK) |
| 追加模式的原子性 |
01_file_io/06_append_mode |
第 2 章 Append Mode |
O_APPEND 与多次 open |
fsync/fdatasync/O_SYNC |
01_file_io/07_synchronized_io |
第 2 章 Synchronized I/O |
数据落盘不等于 write 成功 |
lseek 与稀疏文件 |
01_file_io/08_lseek |
第 2 章 Seeking with lseek |
探测文件长度并恢复位置 |
pread/pwrite |
01_file_io/09_pread_pwrite |
第 2 章 Positional Reads and Writes |
不改变文件偏移 |
ftruncate/truncate |
01_file_io/10_ftruncate |
第 2 章 Truncating Files |
扩展部分补零 |
select/poll 多路复用 |
01_file_io/11_poll、01_file_io/12_select |
第 2 章 Multiplexed I/O |
描述符集合与就绪事件 |
O_CLOEXEC 与 FD_CLOEXEC |
01_file_io/13_cloexec |
第 2 章 Flags for open |
fcntl(F_GETFD/F_SETFD) |
| 知识点 |
练习 |
书本出处 |
说明 |
用户态缓冲与 fflush |
02_buffered_io/03_user_buffering |
第 3 章 User-Buffered I/O、Block Size |
小写入仍留在缓冲区 |
fopen 模式 |
02_buffered_io/01_stream_open_modes |
第 3 章 Opening Files and Modes |
"r"、"w"、"a" |
fdopen 与 fileno |
02_buffered_io/02_fdopen_and_fileno |
第 3 章 Opening a Stream via File Descriptor |
fclose 同时关闭描述符 |
字符 I/O 与 ungetc |
02_buffered_io/04_fgetc_fputc、02_buffered_io/05_ungetc |
第 3 章 Reading a Character at a Time |
EOF 是 int,不是 char |
| 行 I/O 与换行处理 |
02_buffered_io/06_fgets_lines |
第 3 章 Reading an Entire Line |
缺失换行意味着文件结束 |
| 二进制记录 I/O |
02_buffered_io/07_fread_fwrite |
第 3 章 Reading/Writing Binary Data |
fread 的 size 与 count 顺序 |
| 流定位 |
02_buffered_io/08_fseek_ftell |
第 3 章 Seeking a Stream |
fgetpos/fsetpos 保存位置 |
| 缓冲区控制 |
02_buffered_io/09_setvbuf_unbuffered、02_buffered_io/12_line_buffering |
第 3 章 Controlling the Buffering |
_IONBF、_IOLBF、_IOFBF |
| EOF 与错误状态 |
02_buffered_io/10_feof_ferror_clearerr |
第 3 章 Errors and End-of-File |
feof 只有读到末尾才置位 |
| 流与描述符混用 |
02_buffered_io/11_fileno_raw_mix |
第 3 章 Obtaining the Associated File Descriptor |
切换前必须 fflush |
| 流锁与解锁操作 |
02_buffered_io/13_stream_locking |
第 3 章 Thread Safety、Unlocked Stream Operations |
flockfile、getc_unlocked |
| 手工文件锁 |
02_buffered_io/14_manual_file_locking |
第 3 章 Manual File Locking |
flock 与 lockf 语义不同 |
| 知识点 |
练习 |
书本出处 |
说明 |
| 分散/聚集 I/O |
03_advanced_file_io/01_writev_readv |
第 4 章 Scatter/Gather I/O |
struct iovec 数组 |
epoll 基本用法 |
03_advanced_file_io/02_epoll_basic |
第 4 章 Event Poll |
epoll_create1、epoll_ctl、epoll_wait |
EPOLL_CTL_MOD/DEL 与错误码 |
03_advanced_file_io/03_epoll_ctl |
第 4 章 Controlling Epoll |
EEXIST、ENOENT |
| 边沿触发 |
03_advanced_file_io/04_epoll_edge_triggered |
第 4 章 Edge- Versus Level-Triggered |
EPOLLET 不重复通知 |
mmap 读文件 |
03_advanced_file_io/05_mmap_read |
第 4 章 mmap() |
按字节访问、munmap |
MAP_SHARED 写回文件 |
03_advanced_file_io/06_mmap_shared_write、03_advanced_file_io/11_mmap_private_vs_shared |
第 4 章 Mapping Files into Memory |
MAP_PRIVATE 与 MAP_SHARED 的差别 |
mprotect |
03_advanced_file_io/07_mprotect |
第 4 章 Changing the Protection of a Mapping |
页对齐要求与 EINVAL |
mremap |
03_advanced_file_io/08_mremap |
第 4 章 Resizing a Mapping |
旧尺寸参数与 MREMAP_MAYMOVE |
posix_fadvise |
03_advanced_file_io/09_posix_fadvise |
第 4 章 The posix_fadvise System Call |
顺序/随机/DONTNEED 建议 |
posix_fallocate |
03_advanced_file_io/10_posix_fallocate |
第 4 章 Advice for Normal File I/O |
预分配并检查返回的错误号 |
| 知识点 |
练习 |
书本出处 |
说明 |
| 进程、父进程、进程组、会话 |
00_introduction/06_process_ids |
第 1 章 Processes、第 5 章 The Process ID |
getpid、getppid、getpgrp、getsid |
fork 的返回值 |
04_process_management/02_fork_return_value |
第 5 章 The fork System Call |
父进程拿子 PID,子进程拿 0 |
| 子进程眼中的父进程 |
04_process_management/01_child_pid_and_ppid |
第 5 章 The Process Hierarchy |
用管道把结果带回父进程 |
exec 家族 |
04_process_management/03_exec_family |
第 5 章 The Exec Family of Calls |
成功不返回,失败要用 _exit(127) |
| 自定义环境 |
04_process_management/12_exec_environment |
第 5 章 The Exec Family of Calls |
execve 的 envp |
| 退出状态解码 |
04_process_management/04_exit_status_decoding |
第 5 章 Terminating a Process |
WIFEXITED、WEXITSTATUS、WIFSIGNALED |
exit 与 _exit |
04_process_management/07_exit_and_underscore_exit |
第 5 章 Terminating a Process |
前者刷 stdio,后者不刷 |
atexit 顺序 |
04_process_management/08_atexit_order |
第 5 章 atexit and on_exit |
后注册先执行 |
wait/waitpid/WNOHANG |
04_process_management/05_wait_and_waitpid |
第 5 章 Waiting for Terminated Child Processes |
阻塞与轮询 |
waitid 与僵尸进程 |
04_process_management/06_zombies_and_waitid |
第 5 章 Zombies |
WNOWAIT 与 reap |
| 真实/有效/保存 ID |
00_introduction/05_user_group_ids、04_process_management/09_real_effective_ids |
第 1 章 Users and Groups、第 5 章 Real, Effective, and Saved IDs |
getresuid、seteuid |
| 进程组与会话 |
04_process_management/10_process_groups、04_process_management/11_new_session |
第 5 章 Sessions and Process Groups |
setpgid(0,0)、setsid |
| 知识点 |
练习 |
书本出处 |
说明 |
| 主动让出处理器 |
05_advanced_processes/01_yielding |
第 6 章 Yielding the Processor |
sched_yield 的合理用法 |
| nice 值与优先级 |
05_advanced_processes/02_nice_values、05_advanced_processes/03_nice_a_child |
第 6 章 Process Priorities |
getpriority 的 -1 陷阱、非特权只能降优先级 |
| CPU 亲和性 |
05_advanced_processes/04_processor_affinity |
第 6 章 Processor Affinity |
cpu_set_t、sched_getaffinity/setaffinity |
| 调度策略与优先级范围 |
05_advanced_processes/05_scheduling_policies |
第 6 章 Linux Scheduling Policies |
sched_getscheduler、sched_get_priority_max |
| 轮转时间片 |
05_advanced_processes/06_round_robin_interval |
第 6 章 sched_rr_get_interval |
秒/纳秒到微秒的换算 |
| 资源限制读取 |
05_advanced_processes/07_getrlimit |
第 6 章 Resource Limits |
软/硬限制、RLIM_INFINITY |
| 资源限制设置 |
05_advanced_processes/08_setrlimit |
第 6 章 Setting and Retrieving Limits |
软限制不能超过硬限制 |
RLIMIT_FSIZE 与 SIGXFSZ |
05_advanced_processes/09_filesize_limit |
第 6 章 The Limits |
越界写入被信号终止 |
| 知识点 |
练习 |
书本出处 |
说明 |
| 创建与 join |
06_threading/01_create_and_join |
第 7 章 Creating Threads、Joining and Detaching |
只有 join 之后读结果才安全 |
| 线程标识 |
06_threading/02_thread_ids |
第 7 章 Thread IDs |
pthread_self、pthread_equal |
| 传参与返回值 |
06_threading/03_thread_arguments |
第 7 章 Creating Threads |
结构体入参、intptr_t 返回值 |
| 分离线程 |
06_threading/04_detached_threads |
第 7 章 Joining and Detaching Threads |
分离后 join 返回 EINVAL |
| 互斥量保护共享数据 |
06_threading/05_mutex_counter |
第 7 章 Mutexes |
检查每个 pthread 返回值 |
trylock 与非阻塞加锁 |
06_threading/06_trylock |
第 7 章 Deadlocks |
EBUSY 表示锁被占用 |
| 条件变量 |
06_threading/07_condition_variable |
第 7 章 Synchronization |
谓词循环 + pthread_cond_wait |
| 一次性初始化 |
06_threading/08_pthread_once |
第 7 章 The Pthread API |
pthread_once 只运行一次 |
| 线程专有数据 |
06_threading/09_thread_specific_data |
第 7 章 Further Study |
pthread_key_create/setspecific |
| 线程取消 |
06_threading/10_thread_cancellation |
第 7 章 Terminating Threads |
取消点与 PTHREAD_CANCELED |
| 知识点 |
练习 |
书本出处 |
说明 |
stat/fstat/lstat |
07_files_directories/01_stat_family |
第 8 章 The Stat Family |
文件被 unlink 后 fd 仍有效 |
| 权限设置 |
07_files_directories/02_permissions、00_introduction/04_permission_bits |
第 8 章 Permissions |
chmod/fchmod 与 rwx 解码 |
| 文件属主 |
07_files_directories/03_ownership |
第 8 章 Ownership |
非特权进程不能随意移交属主 |
| 扩展属性 |
07_files_directories/04_extended_attributes |
第 8 章 Extended Attributes |
user. 命名空间 |
| 工作目录 |
07_files_directories/05_working_directory |
第 8 章 The Current Working Directory |
getcwd 与 ERANGE |
| 目录的创建与删除 |
07_files_directories/06_creating_directories |
第 8 章 Creating/Removing Directories |
非空目录不能 rmdir |
| 遍历目录 |
07_files_directories/07_reading_a_directory |
第 8 章 Reading a Directory's Contents |
.、.. 与 readdir |
| 符号链接 |
07_files_directories/08_symbolic_links、00_introduction/10_hard_and_soft_links |
第 8 章 Symbolic Links |
readlink、悬空链接 |
| 硬链接与链接计数 |
07_files_directories/09_hard_links |
第 8 章 Hard Links |
st_nlink 的变化 |
| 复制与重命名 |
07_files_directories/10_copying_and_moving |
第 8 章 Copying and Moving Files |
手写复制循环、rename |
设备节点与 /dev |
07_files_directories/11_device_nodes |
第 8 章 Device Nodes、The Random Number Generator |
S_ISCHR、/dev/null、/dev/urandom |
| 带外数据 |
07_files_directories/12_out_of_band_data |
第 8 章 Out-of-Band Communication |
ioctl(FIONREAD) |
| 文件事件监控 |
07_files_directories/13_inotify |
第 8 章 Monitoring File Events |
inotify_add_watch 与事件掩码 |
| 文件类型判断 |
00_introduction/07_file_types |
第 1 章 Files and the Filesystem |
S_ISREG/S_ISDIR/S_ISLNK |
| 知识点 |
练习 |
书本出处 |
说明 |
| 进程地址空间 |
08_memory_management/01_address_space |
第 9 章 The Process Address Space、Memory Regions |
读 /proc/self/maps |
malloc/free |
08_memory_management/02_malloc_and_free |
第 9 章 Allocating Dynamic Memory |
一次性释放、free(NULL) 合法 |
calloc 清零保证 |
08_memory_management/03_calloc_zeroes |
第 9 章 Allocating Arrays |
复用内存块也必须清零 |
realloc 增长 |
08_memory_management/04_realloc_growth |
第 9 章 Resizing Allocations |
只初始化新增部分 |
| 释放后清空指针 |
08_memory_management/05_free_and_clear |
第 9 章 Freeing Dynamic Memory |
防止悬空指针 |
| 对齐分配 |
08_memory_management/06_alignment |
第 9 章 Alignment |
posix_memalign 的返回值约定 |
| 分配器统计 |
08_memory_management/07_allocator_queries |
第 9 章 Advanced Memory Allocation |
malloc_usable_size、malloc_trim |
数据段与 brk/sbrk |
08_memory_management/08_program_break |
第 9 章 Managing the Data Segment |
用完必须恢复 break |
| 匿名映射 |
08_memory_management/09_anonymous_mappings |
第 9 章 Anonymous Memory Mappings、/dev/zero |
MAP_ANONYMOUS 与 fd=-1 |
| 栈上分配与 VLA |
08_memory_management/10_stack_allocations |
第 9 章 Stack-Based Allocations、VLAs |
alloca、变长数组 |
| 内存操作函数 |
08_memory_management/11_memory_functions |
第 9 章 Manipulating Memory |
memset、memchr、memmove、memfrob |
| 锁定内存 |
08_memory_management/12_locking_memory |
第 9 章 Locking Memory、Is a Page in Physical Memory |
mlock、mincore |
| 知识点 |
练习 |
书本出处 |
说明 |
| 信号标识与不可捕获信号 |
09_signals/01_signal_identifiers |
第 10 章 Signal Identifiers |
SIGKILL/SIGSTOP 返回 EINVAL |
| 基本信号处理 |
09_signals/02_signal_handlers |
第 10 章 Basic Signal Management |
sigaction + raise |
siginfo_t 与 si_code |
09_signals/03_sigaction_with_info |
第 10 章 Advanced Signal Management |
SA_SIGINFO、SI_USER/SI_TKILL |
| 信号集 |
09_signals/04_signal_sets |
第 10 章 Signal Sets |
sigemptyset/sigfillset/sigismember |
| 阻塞与未决信号 |
09_signals/05_blocking_signals |
第 10 章 Blocking Signals、Retrieving Pending Signals |
sigprocmask、sigpending |
sigsuspend |
09_signals/06_sigsuspend |
第 10 章 Waiting for a Set of Signals |
原子替换掩码并睡眠 |
sigwait |
09_signals/07_sigwait |
第 10 章 Waiting for a Set of Signals |
同步收取未决信号 |
| 发送信号与存在性检查 |
09_signals/08_sending_signals |
第 10 章 Sending a Signal |
kill(pid, 0)、ESRCH |
| 信号错误码 |
09_signals/09_signal_permissions |
第 10 章 Permissions |
EINVAL 与 ESRCH |
| 处置的继承 |
09_signals/10_signal_inheritance |
第 10 章 Execution and Inheritance |
fork 继承 SIG_IGN |
| 带负载的信号 |
09_signals/11_sigqueue_payload |
第 10 章 Sending a Signal with a Payload |
sigqueue 与 sigval |
| 异步信号安全 |
09_signals/12_async_signal_safety |
第 10 章 Reentrancy |
处理函数里只调 write 这类安全函数 |
| 知识点 |
练习 |
书本出处 |
说明 |
| 时间类型与换算 |
10_time/01_time_types |
第 11 章 Time's Data Structures |
timeval、timespec、纳秒到微秒 |
| 分解日历时间 |
10_time/02_breaking_down_time |
第 11 章 Breaking Down Time |
gmtime_r、strftime、difftime、mktime |
| 格式化与解析 |
10_time/03_parsing_time |
第 11 章 Playing with Time |
strftime + strptime 往返 |
| 进程 CPU 时间 |
10_time/04_process_time、10_time/07_process_cpu_clock |
第 11 章 A Type for Process Time |
clock、times、CLOCK_PROCESS_CPUTIME_ID |
| 时钟选择 |
10_time/05_monotonic_clock |
第 11 章 POSIX Clocks |
单调时钟不会倒退 |
| 时钟精度 |
10_time/06_clock_resolution |
第 11 章 Time Source Resolution |
clock_getres |
| 睡眠与 EINTR 重试 |
10_time/08_sleeping |
第 11 章 Sleeping with Nanosecond Resolution |
nanosleep 的 remaining |
| 绝对睡眠 |
10_time/12_absolute_sleep |
第 11 章 An Advanced Approach to Sleep |
clock_nanosleep + TIMER_ABSTIME |
alarm |
10_time/09_alarm |
第 11 章 Simple Alarms |
alarm(0) 返回剩余秒数 |
| 间隔定时器 |
10_time/10_interval_timers |
第 11 章 Interval Timers |
setitimer/getitimer |
| POSIX 定时器 |
10_time/11_posix_timers |
第 11 章 Advanced Timers |
timer_create/settime/gettime/delete |
| 知识点 |
练习 |
书本出处 |
说明 |
always_inline |
11_gcc_extensions/01_inline_functions |
附录 A Inline Functions |
内联只是优化提示,语义不变 |
pure 与 const 属性 |
11_gcc_extensions/02_pure_and_const_functions |
附录 A Pure/Constant Functions |
只读内存 vs 完全不读内存 |
noreturn |
11_gcc_extensions/03_noreturn_functions |
附录 A Functions That Do Not Return |
函数必须真的不返回 |
malloc 与 warn_unused_result |
11_gcc_extensions/04_allocation_attributes |
附录 A Functions That Allocate Memory |
描述返回新内存、强制检查结果 |
__typeof__ 与语句表达式 |
11_gcc_extensions/05_typeof |
附录 A Getting the Type of an Expression |
类型泛型宏 |
packed 与 aligned |
11_gcc_extensions/06_packed_and_aligned |
附录 A Packing、Increasing Alignment |
去掉填充、提高对齐 |
offsetof/__alignof__ |
11_gcc_extensions/07_offsetof_and_alignof |
附录 A Offset of a Member、Alignment of a Type |
结构体布局的实际数字 |
| case 区间 |
11_gcc_extensions/08_case_ranges |
附录 A Case Ranges |
case 'a' ... 'z' |
| 分支预测提示 |
11_gcc_extensions/09_branch_annotation |
附录 A Branch Annotation |
__builtin_expect 不改变结果 |
void * 算术 |
11_gcc_extensions/10_void_pointer_arithmetic |
附录 A Void and Function Pointer Arithmetic |
按字节步进 |
| 返回地址 |
11_gcc_extensions/11_return_address |
附录 A Obtaining the Return Address |
__builtin_return_address |
deprecated/unused |
11_gcc_extensions/12_deprecated_and_unused |
附录 A Marking Functions as Deprecated/Used/Unused |
局部关闭弃用警告 |
| 技能 |
在哪里练习 |
| 阅读编译器诊断 |
每个练习;默认 -Werror 会把警告变成错误 |
| 用测试固定行为 |
每个练习的 main 里都有 LSPLING_CHECK* 断言 |
| 用管道而不是 sleep 同步进程 |
04_process_management/01_child_pid_and_ppid、06_threading/06_trylock |
用 errno 而不是猜测失败原因 |
00_introduction/02_errno_strerror 起,贯穿全项目 |
| 用 sanitizer 查内存问题 |
README 中的 CFLAGS="-fsanitize=address,undefined" 用法 |
| 保持代码与答案同步 |
tools/generate_exercises.py 与 --check 检查 |
在真实内核上验证 man 手册 |
docs/architecture.md 的测试设计约束一节 |
| 本书章节 |
练习目录 |
练习数 |
| 第 1 章 Introduction and Essential Concepts |
00_introduction |
10 |
| 第 2 章 File I/O |
01_file_io |
13 |
| 第 3 章 Buffered I/O |
02_buffered_io |
14 |
| 第 4 章 Advanced File I/O |
03_advanced_file_io |
11 |
| 第 5 章 Process Management |
04_process_management |
12 |
| 第 6 章 Advanced Process Management |
05_advanced_processes |
9 |
| 第 7 章 Threading |
06_threading |
10 |
| 第 8 章 File and Directory Management |
07_files_directories |
13 |
| 第 9 章 Memory Management |
08_memory_management |
12 |
| 第 10 章 Signals |
09_signals |
12 |
| 第 11 章 Time |
10_time |
12 |
| 附录 A GCC Extensions to the C Language |
11_gcc_extensions |
12 |
| 附录 B Bibliography |
未单独设练习 |
- |
书本中偏“概念与背景”的部分(I/O 调度器、页缓存与回写、虚拟文件系统、
协程与纤程、实时系统的理论、overcommit 与 OOM)没有对应的可执行练习,
它们在 docs/curriculum.md 的章节说明里被提及,建议直接阅读原书。