In the technical view, the pipe is a page in memory, but the process should operate it with the form of manipulating files. Thus it requires that the page in the memory has some file attributes, and the page attributes of the page should be reduced.
The file attributes of this page are shown as follows. Creating a pipe is equivalent to creating a file, such as the connection between filp[20] and file_table[64], and creation of the i node and the connection between file_table[64] and the i node need to be done in the process of creating the pipe. Ultimately, it makes the process know that it is operating the files with the form of the pipe without concerning the others.
The reducing of the page attributes is shown as follows. After all, the page of memory should be used as a file. For example, the process could not access the memory as it accesses the data in its own user space and this page could not be mapped to the linear address space of the process. Another example is that there are two processes operating the page; one is reading while another is writing. It could not trigger page fault protection caused by the writing access to the page that will duplicate the page, and it could not share with the pipe. Next we will show the specific process for creating the pipe.
Apply for an free entry in file_table[64] for pipe file. The created files are all used by the current process (one process) while the pipe file is naturally created for the two processes (the read pipe process and the write pipe process). The pipe in example 1 is created by a parent process (the write pipe process). The parent process prepares everything for the child process (the read pipe process) while creating the pipe. Once the child process is cre- ated, it naturally has the capability of operating the pipe.
First, the parent process applies for two free entries in file_table[64] and sets the cited number of the two free entries to be 1. It means that they are cited. The parent and child process could use each of them respectively, when operating pipe files. The code is as follows.
else if (pid > 0)//parent process writes data into the pipe {
close(fd[0]);
for(i = 0;i<10000;i++)
write(fd[1],str1,strlen(str1));
}
else { //child process reads data from the pipe close(fd[1]);
for(j = 0;j<20000;j++)
read(fd[0],,str2,strlen(str2));
}
return 0;
}
The two free entries that are applied in file_table[64] for creating the pipe file are shown in Figure 8.2.
Connect the table entries between filp[20] in the process task_struct and file_table[64].
We apply for two free entries in *filp[20] in the parent process task_struct. The two free entries connect with the two table entries applied for in file_table[64] previousely, respec- tively. Thus, there are two table entries in *filp[20], the file management structure of the current process, building the relationship with file_table[64]. When it creates a child pro- cess as a parent process, the two table entries in *filp[20] are naturally copied to its child process. It naturally makes the table entries build a relationship with the same pipe files in the file_table[64] structure. The specific code is as follows.
Figure 8.3 shows the effect after setting up the relationship between the current pro- cess and pipe files.
//code’s path:fs/pipe.c:
int sys_pipe(unsigned long * fildes) {
struct m_inode * inode;
struct file * f[2];
int fd[2];
int i,j;
j = 0;
for(i = 0;j<2 && i<NR_FILE;i++) // ready to apply for two free entries in file_table[64]
if (!file_table[i].f_count) //find out free entries
(f[j++] = i+file_table)->f_count++; //set every cited number to be 1 if (j = = 1)
f[0]->f_count = 0;
if (j<2) return -1;
……
}
//code path:fs/pipe.c:
int sys_pipe(unsigned long * fildes) {
……
if (j = = 1) f[0]->f_count = 0;
if (j<2) return -1;
j = 0;
for(i = 0;j<2 && i<NR_OPEN;i++) //ready to apply for two free entries in
//filp[20]
if (!current->filp[i]) { //find out out free entries
current->filp[fd[j] = i] = f[j]; //connect with the two free entries applied
//for in file_table[64] respectively
j++;
}
if (j = =1)
current->filp[fd[0]] = NULL;
if (j<2) {
f[0]->f_count = f[1]->f_count = 0;
return -1;
} ……
}
Create i node of the pipe file. The process should build a relationship between i node of the pipe file and file_table[64] if it wants to have the capability of operating the pipe file.
To achieve this, we should call function get_pipe_inode() and apply a i node in inode_
table[32] for the pipe file. The specific code is as follows.
Kernel code area Kernel data area
file_table[64]
Apply two free items in file_table[64]
kernel
0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF
ROM BIOS and VGA
Figure 8.2 Two free entries that are applied for in file_table[64] for creating the pipe file.
kernel
Kernel code area Kernel data area
Task_struct of parent process
The page that task_struct of parent process resides
file_table[64]
0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF
filp[20]
ROM BIOS andVGA
...
...
...
Figure 8.3 Build a relationship between current process and pipe files.
Due to the nature of the pipe being a page of memory, the system applies for an free page of memory and loads the address of the page into i node. It is worth noting that at the moment the field inode->i_size no longer carries the size of the file but the original address of the memory page. The specific code is as follows.
The pipe file is also a file, so it needs to have a i node. Thus, it should have cited count.
Linux 0.11 defaults that it should have two and only two processes to operate the pipe file.
One is a read process, and another is a write process. Thus, we set it to be 2 directly.
Then, let both the read pipe pointer and write pipe pointer point to the original position of the pipe (the free page) for the operation of the process of the read and write pipe. Then set the attribute of the i node to be “the type of pipe i node” to identify the
//code path:fs/pipe.c:
int sys_pipe(unsigned long * fildes) {
……
if (j = =1)
current->filp[fd[0]] = NULL;
if (j<2) {
f[0]->f_count = f[1]->f_count = 0;
return -1;
}
if (!(inode = get_pipe_inode())) { //create node i for the pipe current->filp[fd[0]] =
current->filp[fd[1]] = NULL;
f[0]->f_count = f[1]->f_count = 0;
return -1;
} ……
}
//code path:fs/inode.c:
struct m_inode * get_pipe_inode(void) {
struct m_inode * inode;
if (!(inode = get_empty_inode())) return NULL;
if (!(inode->i_size = get_free_page())) { //apply for the page to
//be the pipe
inode->i_count = 0;
return NULL;
}
inode->i_count = 2; /* sum of readers/writers */
……
}
particularity of i node. That means actually it is not i node stored in the file in the hard disk; it is only a page of memory. The specific code is as follows.
The process of the application for i node for the pipe file and setting process is shown in Figure 8.4.
Build a relationship between i node of the pipe file and file_table[64]. Now, we can build a relationship between i node of the pipe file and file_table[64] because the i node of the pipe file has been set up. The specific operation is shown as follows. Initialize the two free entries in file_table[64] and let them point to the i node of the pipe and let all of the file read and write pointers point to the original position of the pipe. Set the first free entry’s mode of file to read and the second to write. Thus, the parent process
0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF
Kernel code area Kernel data area
i node_table[32]
i node of pipe file
m_inode structure i_count
The end pointer of pipe The first pointer of pipe i_mode
i_nlinks
Data area i_zone[9]
ROM BIOS and VGA
Apply for free page (pipe file) kernel
Figure 8.4 Create i node for pipe file.
//code path:fs/inode.c:
struct m_inode * get_pipe_inode(void) {
……
if (!(inode->i_size = get_free_page())) { inode->i_count = 0;
return NULL;
}
inode->i_count = 2; /* sum of readers/writers */ //set the cited number to be 2 PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0; //PIPE_HEAD is write pipe pointer,PIPE_TAIL is
//read
//pipe pointer, set both of them
//to be 0
inode->i_pipe = 1; //set up the attribute of the
//pipe file
return inode;
}
has got the capability of operating the pipe file. The child process created by the parent process will also get the capability of operating the pipe file naturally. The specific code is as follows.
It is shown in Figure 8.5.
Return the pipe file handle to the user’s process. Now return the two handles of the pipe file to the user’s process, which is fd[2] in the code of example 1. This array has two entries, and each of them stores a handle. Thus, the child process will inherit the two file handles,
kernel
0x00000 0x9FFFF 0xFFFFF 0x3FFFFF 0x5FFFFF 0xFFFFFF
Kernel code area Kernel data area
inode_table[32] file_table[64]
i node of pipe file
ROM BIOS andVGA
Figure 8.5 Build a relationship between node i of pipe and file_table[64].
//code path:fs/pipe.c:
int sys_pipe(unsigned long * fildes) {
……
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[0]->f_inode = f[1]->f_inode = inode; //connect node i and table entry f[0]->f_pos = f[1]->f_pos = 0; //the file pointer return to 0 f[0]->f_mode = 1; /* read */ //set it to be read mode f[1]->f_mode = 2; /* write */ //set it to be written mode put_fs_long(fd[0],0+fildes);
put_fs_long(fd[1],1+fildes);
return 0;
}
and the parent and child processes can operate the pipe file through different file handles.
The specific code is as follows.
The result of returning the file handle to the user’s process is shown in Figure 8.6.