注:本分類下文章大多整理自《深入分析linux內核源代碼》一書,另有參考其他一些資料如《linux內核完全剖析》、《linux c 編程一站式學習》等,只是爲了更好地理清系統編程和網絡編程中的一些概念性問題,並沒有深入地閱讀分析源碼,我也是草草翻過這本書,請有興趣的朋友自己參考相關資料。此書出版較早,分析的版本爲2.4.16,故出現的一些概念可能跟最新版本內核不同。
此書已經開源,閱讀地址 http://www.kerneltravel.net
當用戶進程通過系統調用剛進入內核的時候,CPU會自動在該進程的內核棧上壓入下圖所示的內容:
1、之所以把EIP的值設置成信號處理函數的地址,是因爲一旦進程返回用戶態,就要去執行信號處理程序,所以EIP要指向信號處理程序而不是原來應該執行的地址。
2、之所以要把frame從內核棧拷貝到用戶棧,是因爲進程從內核態返回用戶態會清理這次調用所用到的內核棧(類似函數調用),內核棧又太小,不能單純的在棧上保存另一個frame(想象一下嵌套信號處理),而我們需要EAX(系統調用返回值)、EIP這些信息以便執行完信號處理函數後能繼續執行程序,所以把它們拷貝到用戶態棧以保存起來。
1
2 |
(By default, the signal handler is invoked on the normal process stack. It is possible to arrange that the signal handler
uses an alternate stack; see sigaltstack(2) for a discussion of how to do this and when it might be useful.) |
1
2 3 4 5 6 7 8 9 10 |
struct ipc_perm
{ key_t key; /* 鍵 */ ushort uid; /* 對象擁有者對應進程的有效用戶識別號和有效組識別號 */ ushort gid; ushort cuid; /* 對象創建者對應進程的有效用戶識別號和有效組識別號 */ ushort cgid; ushort mode; /* 存取模式 */ ushort seq; /* 序列號 */ }; |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
(1)系統中每個信號量的數據結構(sem)
struct sem { int semval; /* 信號量的當前值 */ unsigned short semzcnt; /* # waiting for zero */ unsigned short semncnt; /* # waiting for increase */ int sempid; /*在信號量上最後一次操作的進程識別號*/ }; (2)系統中表示信號量集合(set)的數據結構(semid_ds) struct semid_ds { struct ipc_perm sem_perm; /* IPC 權限 */ long sem_otime; /* 最後一次對信號量操作(semop)的時間 */ long sem_ctime; /* 對這個結構最後一次修改的時間 */ struct sem *sem_base; /* 在信號量數組中指向第一個信號量的指針 */ struct sem_queue *sem_pending; /* 待處理的掛起操作*/ struct sem_queue **sem_pending_last; /* 最後一個掛起操作 */ struct sem_undo *undo; /* 在這個數組上的undo 請求 */ ushort sem_nsems; /* 在信號量數組上的信號量號 */ }; (3)系統中每一信號量集合的隊列結構(sem_queue) struct sem_queue { struct sem_queue *next; /* 隊列中下一個節點 */ struct sem_queue **prev; /* 隊列中前一個節點, *(q->prev) == q */ struct wait_queue *sleeper; /* 正在睡眠的進程 */ struct sem_undo *undo; /* undo 結構*/ int pid; /* 請求進程的進程識別號 */ int status; /* 操作的完成狀態 */ struct semid_ds *sma; /*有操作的信號量集合數組 */ struct sembuf *sops; /* 掛起操作的數組 */ int nsops; /* 操作的個數 */ }; |
1
2 3 4 5 6 |
struct sembuf
{ ushort sem_num; /* 在數組中信號量的索引值 */ short sem_op; /* 信號量操作值(正數、負數或0) */ short sem_flg; /* 操作標誌,爲IPC_NOWAIT 或SEM_UNDO*/ }; |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
(1)消息緩衝區(msgbuf)
/* msgsnd 和msgrcv 系統調用使用的消息緩衝區*/ struct msgbuf { long mtype; /* 消息的類型,必須爲正數 */ char mtext[1]; /* 消息正文 */ }; (2)消息結構(msg) struct msg { struct msg *msg_next; /* 隊列上的下一條消息 */ long msg_type; /*消息類型*/ char *msg_spot; /* 消息正文的地址 */ short msg_ts; /* 消息正文的大小 */ }; (3)消息隊列結構(msgid_ds) /* 在系統中的每一個消息隊列對應一個msgid_ds 結構 */ struct msgid_ds { struct ipc_perm msg_perm; struct msg *msg_first; /* 隊列上第一條消息,即鏈表頭*/ struct msg *msg_last; /* 隊列中的最後一條消息,即鏈表尾 */ time_t msg_stime; /* 發送給隊列的最後一條消息的時間 */ time_t msg_rtime; /* 從消息隊列接收到的最後一條消息的時間 */ time_t msg_ctime; /* 最後修改隊列的時間*/ ushort msg_cbytes; /*隊列上所有消息總的字節數 */ ushort msg_qnum; /*在當前隊列上消息的個數 */ ushort msg_qbytes; /* 隊列最大的字節數 */ ushort msg_lspid; /* 發送最後一條消息的進程的pid */ ushort msg_lrpid; /* 接收最後一條消息的進程的pid */ }; |
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* 在系統中 每一個共享內存段都有一個shmid_ds 數據結構. */
struct shmid_ds { struct ipc_perm shm_perm; /* 操作權限 */ int shm_segsz; /* 段的大小(以字節爲單位) */ time_t shm_atime; /* 最後一個進程附加到該段的時間 */ time_t shm_dtime; /* 最後一個進程離開該段的時間 */ time_t shm_ctime; /* 最後一次修改這個結構的時間 */ unsigned short shm_cpid; /*創建該段進程的 pid */ unsigned short shm_lpid; /* 在該段上操作的最後一個進程的pid */ short shm_nattch; /*當前附加到該段的進程的個數 */ /* 下面是私有的 */ unsigned short shm_npages; /*段的大小(以頁爲單位) */ unsigned long *shm_pages; /* 指向frames -> SHMMAX 的指針數組 */ struct vm_area_struct *attaches; /* 對共享段的描述 */ }; |
- 頂
- 10
- 踩
- 0