前言
第0章 基礎知識1
0.1 一個Linux程序的誕生記1
0.2 程序的構成2
0.3 程序是如何“跑”的4
0.4 背景概念介紹5
0.4.1 係統調用5
0.4.2 C庫函數6
0.4.3 綫程安全7
0.4.4 原子性9
0.4.5 可重入函數9
0.4.6 阻塞與非阻塞11
0.4.7 同步與非同步11
第1章 文件I/O12
1.1 Linux中的文件12
1.1.1 文件、文件描述符和文件錶12
1.1.2 內核文件錶的實現13
1.2 打開文件14
1.2.1 open介紹14
1.2.2 更多選項15
1.2.3 open源碼跟蹤16
1.2.4 如何選擇文件描述符17
1.2.5 文件描述符fd與文件管理結構file18
1.3 creat簡介19
1.4 關閉文件19
1.4.1 close介紹19
1.4.2 close源碼跟蹤19
1.4.3 自定義files_operations21
1.4.4 遺忘close造成的問題22
1.4.5 如何查找文件資源泄漏25
1.5 文件偏移26
1.5.1 lseek簡介26
1.5.2 小心lseek的返迴值26
1.5.3 lseek源碼分析27
1.6 讀取文件29
1.6.1 read源碼跟蹤29
1.6.2 部分讀取30
1.7 寫入文件31
1.7.1 write源碼跟蹤31
1.7.2 追加寫的實現33
1.8 文件的原子讀寫33
1.9 文件描述符的復製34
1.10 文件數據的同步38
1.11 文件的元數據41
1.11.1 獲取文件的元數據41
1.11.2 內核如何維護文件的元數據42
1.11.3 權限位解析43
1.12 文件截斷45
1.12.1 truncate與ftruncate的簡單介紹45
1.12.2 文件截斷的內核實現45
1.12.3 為什麼需要文件截斷48
第2章 標準I/O庫50
2.1 stdin、stdout和stderr50
2.2 I/O緩存引齣的趣題51
2.3 fopen和open標誌位對比52
2.4 fdopen與fileno55
2.5 同時讀寫的痛苦56
2.6 ferror的返迴值57
2.7 clearerr的用途57
2.8 小心fgetc和getc60
2.9 注意fread和fwrite的返迴值60
2.10 創建臨時文件61
第3章 進程環境66
3.1 main是C程序的開始嗎66
3.2 “活雷鋒”exit70
3.3 atexit介紹75
3.3.1 使用atexit75
3.3.2 atexit的局限性76
3.3.3 atexit的實現機製77
3.4 小心使用環境變量78
3.5 使用動態庫80
3.5.1 動態庫與靜態庫80
3.5.2 編譯生成和使用動態庫80
3.5.3 程序的“平滑無縫”升級82
3.6 避免內存問題84
3.6.1 尷尬的realloc84
3.6.2 如何防止內存越界85
3.6.3 如何定位內存問題86
3.7 “長跳轉”longjmp90
3.7.1 setjmp與longjmp的使用90
3.7.2 “長跳轉”的實現機製91
3.7.3 “長跳轉”的陷阱93
第4章 進程控製:進程的一生96
4.1 進程ID96
4.2 進程的層次98
4.2.1 進程組99
4.2.2 會話102
4.3 進程的創建之fork()103
4.3.1 fork之後父子進程的內存關係104
4.3.2 fork之後父子進程與文件的關係107
4.3.3 文件描述符復製的內核實現110
4.4 進程的創建之vfork()115
4.5 daemon進程的創建117
4.6 進程的終止119
4.6.1 _exit函數119
4.6.2 exit函數120
4.6.3 return退齣122
4.7 等待子進程122
4.7.1 僵屍進程122
4.7.2 等待子進程之wait()124
4.7.3 等待子進程之waitpid()126
4.7.4 等待子進程之等待狀態值129
4.7.5 等待子進程之waitid()131
4.7.6 進程退齣和等待的內核實現133
4.8 exec傢族141
4.8.1 execve函數141
4.8.2 exec傢族142
4.8.3 execve係統調用的內核實現144
4.8.4 exec與信號151
4.8.5 執行exec之後進程繼承的屬性152
4.9 system函數152
4.9.1 system函數接口153
4.9.2 system函數與信號156
4.10 總結157
第5章 進程控製:狀態、調度和優先級158
5.1 進程的狀態158
5.1.1 進程狀態概述159
5.1.2 觀察進程狀態171
5.2 進程調度概述173
5.3 普通進程的優先級181
5.4 完全公平調度的實現186
5.4.1 時間片和虛擬運行時間186
5.4.2 周期性調度任務190
5.4.3 新進程的加入192
5.4.4 睡眠進程醒來198
5.4.5 喚醒搶占202
5.5 普通進程的組調度204
5.6 實時進程207
5.6.1 實時調度策略和優先級207
5.6.2 實時調度相關API211
5.6.3 限製實時進程運行時間213
5.7 CPU的親和力214
第6章 信號219
6.1 信號的完整生命周期219
6.2 信號的産生220
6.2.1 硬件異常220
6.2.2 終端相關的信號221
6.2.3 軟件事件相關的信號223
6.3 信號的默認處理函數224
6.4 信號的分類227
6.5 傳統信號的特點228
6.5.1 信號的ONESHOT特性230
6.5.2 信號執行時屏蔽自身的特性232
6.5.3 信號中斷係統調用的重啓特性233
6.6 信號的可靠性236
6.6.1 信號的可靠性實驗236
6.6.2 信號可靠性差異的根源240
6.7 信號的安裝243
6.8 信號的發送246
6.8.1 kill、tkill和tgkill246
6.8.2 raise函數247
6.8.3 sigqueue函數247
6.9 信號與綫程的關係253
6.9.1 綫程之間共享信號處理函數254
6.9.2 綫程有獨立的阻塞信號掩碼255
6.9.3 私有掛起信號和共享掛起信號257
6.9.4 緻命信號下,進程組全體退齣260
6.10 等待信號260
6.10.1 pause函數261
6.10.2 sigsuspend函數262
6.10.3 sigwait函數和sigwaitinfo函數263
6.11 通過文件描述符來獲取信號265
6.12 信號遞送的順序267
6.13 異步信號安全272
6.14 總結275
第7章 理解Linux綫程(1)276
7.1 綫程與進程276
7.2 進程ID和綫程ID281
7.3 pthread庫接口介紹284
7.4 綫程的創建和標識285
7.4.1 pthread_create函數285
7.4.2 綫程ID及進程地址空間布局286
7.4.3 綫程創建的默認屬性291
7.5 綫程的退齣292
7.6 綫程的連接與分離293
7.6.1 綫程的連接293
7.6.2 為什麼要連接退齣的綫程295
7.6.3 綫程的分離299
7.7 互斥量300
7.7.1 為什麼需要互斥量300
7.7.2 互斥量的接口304
7.7.3 臨界區的大小305
7.7.4 互斥量的性能306
7.7.5 互斥鎖的公平性310
7.7.6 互斥鎖的類型311
7.7.7 死鎖和活鎖314
7.8 讀寫鎖316
7.8.1 讀寫鎖的接口317
7.8.2 讀寫鎖的競爭策略318
7.8.3 讀寫鎖總結323
7.9 性能殺手:僞共享323
7.10 條件等待328
7.10.1 條件變量的創建和銷毀328
7.10.2 條件變量的使用329
第8章 理解Linux綫程(2)333
8.1 綫程取消333
8.1.1 函數取消接口333
8.1.2 綫程清理函數335
8.2 綫程局部存儲339
8.2.1 使用NPTL庫函數實現綫程局部存儲340
8.2.2 使用__thread關鍵字實現綫程局部存儲342
8.3 綫程與信號343
8.3.1 設置綫程的信號掩碼344
8.3.2 嚮綫程發送信號344
8.3.3 多綫程程序對信號的處理345
8.4 多綫程與fork()345
第9章 進程間通信:管道349
9.1 管道351
9.1.1 管道概述351
9.1.2 管道接口352
9.1.3 關閉未使用的管道文件描述符356
9.1.4 管道對應的內存區大小361
9.1.5 shell管道的實現361
9.1.6 與shell命令進行通信(popen)362
9.2 命名管道FIFO365
9.2.1 創建FIFO文件365
9.2.2 打開FIFO文件366
9.3 讀寫管道文件367
9.4 使用管道通信的示例372
第10章 進程間通信:System V IPC375
10.1 System V IPC概述375
10.1.1 標識符與IPC Key376
10.1.2 IPC的公共數據結構379
10.2 System V消息隊列383
10.2.1 創建或打開一個消息隊列383
10.2.2 發送消息385
10.2.3 接收消息388
10.2.4 控製消息隊列390
10.3 System V信號量391
10.3.1 信號量概述391
10.3.2 創建或打開信號量393
10.3.3 操作信號量395
10.3.4 信號量撤銷值399
10.3.5 控製信號量400
10.4 System V共享內存402
10.4.1 共享內存概述402
10.4.2 創建或打開共享內存403
10.4.3 使用共享內存405
10.4.4 分離共享內存407
10.4.5 控製共享內存408
第11章 進程間通信:POSIX IPC410
11.1 POSIX IPC概述411
11.1.1 IPC對象的名字411
11.1.2 創建或打開IPC對象413
11.1.3 關閉和刪除IPC對象414
11.1.4 其他414
11.2 POSIX消息隊列415
11.2.1 消息隊列的創建、打開、關閉及刪除415
11.2.2 消息隊列的屬性418
11.2.3 消息的發送和接收422
11.2.4 消息的通知423
11.2.5 I/O多路復用監控消息隊列427
11.3 POSIX信號量428
11.3.1 創建、打開、關閉和刪除有名信號量430
11.3.2 信號量的使用431
11.3.3 無名信號量的創建和銷毀432
11.3.4 信號量與futex433
11.4 內存映射mmap436
11.4.1 內存映射概述436
11.4.2 內存映射的相關接口438
11.4.3 共享文件映射439
11.4.4 私有文件映射455
11.4.5 共享匿名映射455
11.4.6 私有匿名映射456
11.5 POSIX共享內存456
11.5.1 共享內存的創建、使用和刪除457
11.5.2 共享內存與tmpfs458
第12章 網絡通信:連接的建立462
12.1 socket文件描述符462
12.2 綁定IP地址463
12.2.1 bind的使用464
12.2.2 bind的源碼分析465
12.3 客戶端連接過程468
12.3.1 connect的使用468
12.3.2 connect的源碼分析469
12.4 服務器端連接過程477
12.4.1 listen的使用477
12.4.2 listen的源碼分析478
12.4.3 accept的使用480
12.4.4 accept的源碼分析480
12.5 TCP三次握手的實現分析483
12.5.1 SYN包的發送483
12.5.2 接收SYN包,發送SYN+ACK包485
12.5.3 接收SYN+ACK數據包494
12.5.4 接收ACK數據包,完成三次握手499
第13章 網絡通信:數據報文的發送505
13.1 發送相關接口505
13.2 數據包從用戶空間到內核空間的流程506
13.3 UDP數據包的發送流程510
13.4 TCP數據包的發送流程517
13.5 IP數據包的發送流程527
13.5.1 ip_send_skb源碼分析528
13.5.2 ip_queue_xmit源碼分析531
13.6 底層模塊數據包的發送流程532
第14章 網絡通信:數據報文的接收536
14.1 係統調用接口536
14.2 數據包從內核空間到用戶空間的流程537
14.3 UDP數據包的接收流程540
14.4 TCP數據包的接收流程544
14.5 TCP套接字的三個接收隊列553
14.6 從網卡到套接字556
14.6.1 從硬中斷到軟中斷556
14.6.2 軟中斷處理557
14.6.3 傳遞給協議棧流程559
14.6.4 IP協議處理流程564
14.6.5 大師的錯誤?原始套接字的接收568
14.6.6 注冊傳輸層協議571
14.6.7 確定UDP套接字571
14.6.8 確定TCP套接字576
第15章 編寫安全無錯代碼582
15.1 不要用memcmp比較結構體582
15.2 有符號數和無符號數的移位區彆583
15.3 數組和指針584
15.4 再論數組首地址587
15.5 “神奇”的整數類型轉換588
15.6 小心volatile的原子性誤解589
15.7 有趣的問題:“x == x”何時為假?591
15.8 小心浮點陷阱593
15.8.1 浮點數的精度限製593
15.8.2 兩個特殊的浮點值593
15.9 Intel移位指令陷阱595
· · · · · · (
收起)