-
Notifications
You must be signed in to change notification settings - Fork 509
/
pipe.c
executable file
·153 lines (145 loc) · 5.06 KB
/
pipe.c
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* passed
* linux/fs/pipe.c
*
* (C) 1991 Linus Torvalds
*/
#include <set_seg.h>
#include <signal.h>// 信号头文件。定义信号符号常量,信号结构以及信号操作函数原型。
#include <linux/sched.h>// 调度程序头文件,定义了任务结构task_struct、初始任务0 的数据,
// 还有一些有关描述符参数设置和获取的嵌入式汇编函数宏语句。
#include <linux/mm.h> /* 使用其中的get_free_page */
// 内存管理头文件。含有页面大小定义和一些页面释放函数原型。
#include <asm/segment.h>// 段操作头文件。定义了有关段寄存器操作的嵌入式汇编函数。
//// 管道读操作函数。
// 参数inode 是管道对应的i 节点,buf 是数据缓冲区指针,count 是读取的字节数。
int read_pipe(struct m_inode * inode, char * buf, int count)
{
int chars, size, read = 0;
// 若欲读取的字节计数值count 大于0,则循环执行以下操作。
while (count>0) {
// 若当前管道中没有数据(size=0),则唤醒等待该节点的进程,如果已没有写管道者,则返回已读
// 字节数,退出。否则在该i 节点上睡眠,等待信息。
while (!(size=PIPE_SIZE(*inode))) {
wake_up(&inode->i_wait);
if (inode->i_count != 2) /* are there any writers? */
return read;
sleep_on(&inode->i_wait);
}
// 取管道尾到缓冲区末端的字节数chars。如果其大于还需要读取的字节数count,则令其等于count。
// 如果chars 大于当前管道中含有数据的长度size,则令其等于size。
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);
// 将管道中的数据复制到用户缓冲区中。对于管道i 节点,其i_size 字段中是管道缓冲块指针。
while (chars-->0)
put_fs_byte(((char *)inode->i_size)[size++],buf++);
}
// 唤醒等待该管道i 节点的进程,并返回读取的字节数。
wake_up(&inode->i_wait);
return read;
}
//// 管道写操作函数。
// 参数inode 是管道对应的i 节点,buf 是数据缓冲区指针,count 是将写入管道的字节数。
int write_pipe(struct m_inode * inode, char * buf, int count)
{
int chars, size, written = 0;
// 若将写入的字节计数值count 还大于0,则循环执行以下操作。
while (count>0) {
// 若当前管道中没有已经满了(size=0),则唤醒等待该节点的进程,如果已没有读管道者,则向进程
// 发送SIGPIPE 信号,并返回已写入的字节数并退出。若写入0 字节,则返回-1。否则在该i 节点上
// 睡眠,等待管道腾出空间。
while (!(size=(PAGE_SIZE-1)-PIPE_SIZE(*inode))) {
wake_up(&inode->i_wait);
if (inode->i_count != 2) { /* no readers */
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 指向管道数据头部,调整当前管道数据头部指针(前移chars 字节)。
size = PIPE_HEAD(*inode);
PIPE_HEAD(*inode) += chars;
PIPE_HEAD(*inode) &= (PAGE_SIZE-1);
// 从用户缓冲区复制chars 个字节到管道中。对于管道i 节点,其i_size 字段中是管道缓冲块指针。
while (chars-->0)
((char *)inode->i_size)[size++]=get_fs_byte(buf++);
}
// 唤醒等待该i 节点的进程,返回已写入的字节数,退出。
wake_up(&inode->i_wait);
return written;
}
//// 创建管道系统调用函数。
// 在fildes 所指的数组中创建一对文件句柄(描述符)。这对文件句柄指向一管道i 节点。fildes[0]
// 用于读管道中数据,fildes[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 && i<NR_FILE;i++)
if (!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 && i<NR_OPEN;i++)
if (!current->filp[i]) {
current->filp[ fd[j]=i ] = f[j];
j++;
}
// 如果只有一个空闲文件句柄,则释放该句柄。
if (j==1)
current->filp[fd[0]]=NULL;
// 如果没有找到两个空闲句柄,则释放上面获取的两个文件结构项(复位引用计数值),并返回-1。
if (j<2) {
f[0]->f_count=f[1]->f_count=0;
return -1;
}
// 申请管道i 节点,并为管道分配缓冲区(1 页内存)。如果不成功,则相应释放两个文件句柄和文
// 件结构项,并返回-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;
}
// 初始化两个文件结构,都指向同一个i 节点,读写指针都置零。第1 个文件结构的文件模式置为读,
// 第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 */
// 将文件句柄数组复制到对应的用户数组中,并返回0,退出。
put_fs_long(fd[0],0+fildes);
put_fs_long(fd[1],1+fildes);
return 0;
}