* 該檔案中的兩個函式read_pipe和write_pipe是上層函式
* read和write的底層實現
* linux/fs/pipe.c
* (c) 1991 linus torvalds
#include
#include
// 記憶體管理標頭檔案。含有頁面大小定義和一些頁面釋放函式原型
#include /* for get_free_page */
#include
/* pipe類似於佇列,向pipe的尾部寫入資料,從pipe的頭部讀取資料 */
/* 管道讀操作函式 */
/* 引數inode 是管道對應的i 節點,buf 是資料緩衝區指標,count 是讀取的位元組數 */
* read_pipe()函式用於讀取管道中的資料,如果管道中沒有資料的話,
* 喚醒寫管道程序,自己睡眠,如果讀到資料,並把資料傳到使用者緩衝區,
* 當把管道中所有的資料都取走後,也要喚醒等待寫管道的程序,並返回
* 已讀資料位元組數
int read_pipe(struct m_inode * inode, char * buf, int count)
int chars, size, read = 0;
while (count>0)
// 若當前管道中沒有資料(size=0),則喚醒等待該節點的程序
while (!(size=pipe_size(*inode)))
wake_up(&inode->i_wait);
// 如果已沒有寫管道者
if (inode->i_count != 2) /* are there any writers? */
return read; // 返回已讀位元組數
// 否則在該i 節點上睡眠,等待資訊
sleep_on(&inode->i_wait);
// 取管道尾到緩衝區末端的位元組數chars
chars = page_size-pipe_tail(*inode);
if (chars > count)
chars = count;
if (chars > size)
chars = size;
// 讀位元組計數減去此次可讀的位元組數chars,並累加已讀位元組數
count -= chars;
read += chars;
// 令size 指向管道尾部,調整當前管道尾指標(前移chars 位元組)
size = pipe_tail(*inode);
pipe_tail(*inode) += chars;
pipe_tail(*inode) &= (page_size-1);
// 將管道中的資料複製到使用者緩衝區中
while (chars-->0)
put_fs_byte(((char *)inode->i_size)[size++],buf++);
// 喚醒等待該管道i 節點的程序
wake_up(&inode->i_wait);
// 返回讀取的位元組數
return read;
* 函式read_pipe首先檢查管道中是否含有資料,沒有的話
* 喚醒等待程序。然後得到管道的尾指標,將尾指標位置向
* 前移動size個位元組,最後將資料複製到使用者程式區
* tail | | head
* write the data get the data
/* 想管道中寫入資料,引數inode是管道對應的i節點,buf是資料緩衝區 */
/* count是寫入管道的位元組數 */
int write_pipe(struct m_inode * inode, char * buf, int count)
int chars, size, written = 0;
while (count>0)
// 若當前管道中沒有已經滿了(size=0),則喚醒等待該節點的程序
while (!(size=(page_size-1)-pipe_size(*inode)))
wake_up(&inode->i_wait);
// 如果已沒有讀管道者
if (inode->i_count != 2) { /* no readers */
// 向程序傳送sigpipe訊號
current->signal |= (1<<(sigpipe-1));
// 並返回已寫入的位元組數並退出
return written?written:-1;
// 睡眠,等待管道騰出空間
sleep_on(&inode->i_wait);
// 取管道頭部到緩衝區末端空間位元組數chars。如果其大於還需要寫入的位元組數count,則令其等於
// count。如果chars 大於當前管道中空閒空間長度size,則令其等於size
chars = page_size-pipe_head(*inode);
if (chars > count)
chars = count;
if (chars > size)
chars = size;
// 寫入位元組計數減去此次可寫入的位元組數chars,並累加已寫位元組數到written
count -= chars;
written += chars;
// 令size 指向管道資料頭部,調整當前管道資料頭部指標
size = pipe_head(*inode);
pipe_head(*inode) += chars;
pipe_head(*inode) &= (page_size-1);
// 從使用者緩衝區複製chars 個位元組到管道中
while (chars-->0)
((char *)inode->i_size)[size++]=get_fs_byte(buf++);
// 喚醒等待該i 節點的程序,返回已寫入的位元組數,退出
wake_up(&inode->i_wait);
return written;
* 該函式首先是得到管道的長度,如果管道已滿的話,喚醒等待的程序
* 否則得到管道頭,移動管道頭指標,將資料從使用者區寫到管道中
/* 建立管道系統呼叫函式,fileds[2],fileds[0]用於讀管道中資料,fileds[1] */
/* 用於向管道中寫入資料,成功時返回0,出錯時返回-1 */
int sys_pipe(unsigned long * fildes)
struct m_inode * inode;
struct file * f[2];
int fd[2];
int i,j;
// 從系統檔案表中取兩個空閒項(引用計數字段為0 的項),並分別設定引用計數為1
j=0;
for(i=0;j<2 && iif (!file_table[i].f_count)
(f[j++]=i+file_table)->f_count++;
// 如果只有乙個空閒項,則釋放該項(引用計數復位)
if (j==1)
f[0]->f_count=0;
// 如果沒有找到兩個空閒項,則返回-1
if (j<2)
return -1;
// 針對上面取得的兩個檔案結構項,分別分配一檔案控制代碼,並使程序的檔案結構指標分別指向這兩個
// 檔案結構
j=0;
for(i=0;j<2 && iif (!current->filp[i])
current->filp[ fd[j]=i ] = f[j];
j++;
// 如果只有乙個空閒檔案控制代碼,則釋放該控制代碼
if (j==1)
current->filp[fd[0]]=null;
// 如果沒有找到兩個空閒控制代碼,則釋放上面獲取的兩個檔案結構項(復位引用計數值)
if (j<2) {
f[0]->f_count=f[1]->f_count=0;
return -1;
// 申請管道i 節點,並為管道分配緩衝區(1 頁記憶體)
if (!(inode=get_pipe_inode())) // 不成功 ?
// 相應釋放兩個檔案控制代碼和檔案結構項
current->filp[fd[0]] =
current->filp[fd[1]] = null;
f[0]->f_count = f[1]->f_count = 0;
return -1; // 返回值
// 初始化兩個檔案指標,將f[2]複製到fileds[2]中,將核心資料複製
// 到使用者資料中
f[0]->f_inode = f[1]->f_inode = inode;
f[0]->f_pos = f[1]->f_pos = 0;
f[0]->f_mode = 1; /* read */
f[1]->f_mode = 2; /* write */
put_fs_long(fd[0],0+fildes);
put_fs_long(fd[1],1+fildes);
// 返回成功0
return 0;
* 該函式實現的是系統呼叫。首先是查詢全域性的file_table來找到
* 兩個空閒項,如果成功的話,設定當前程序的檔案結構表項。申請
* i節點,將資料複製到結果中去
參考《linux核心完全注釋》和網上資料
Linux 0 11 核心筆記
1 任務0的堆疊問題 一直不明白schedule.c裡的task union的stack和user stack是什麼關係,head.s裡就設定了esp指向user stack,卻一直沒有用到task union,直到看到init task才明白,從進入保護模式到跳轉進使用者態都是用的user sta...
Linux0 11核心筆記( )
c語言 彙編知識 嵌入式彙編 x86處理器和程式設計的相關知識和 unix作業系統設計 linus在最初開發linux作業系統時參考了minix作業系統 作業系統 設計與實現 一種基於訊息傳遞在核心各模組之間進行通訊 資訊交換 重要的五個支柱 unix作業系統 分時作業系統 minix作業系統 gn...
Linux 0 11核心編譯問題
弄了好長時間,只是可以用linux 0.11我的linux實驗室環境,使用bochs模擬,進入linux 0.11 cd cd src linux make 這樣就編譯成image了 mkdir a mkdir a boot mcopy image a boot 將映象檔案拷貝到啟動軟盤 修改men...