Look at the Linux 0.11 version of the implementation of the write, first it is defined in the standard header file Unistd.h
int write (int fildes, const char * buf, off_t count);
Next look at write.c.
/* * linux/lib/write.c * * (c) 1991 Linus Torvalds */#define __LIBRARY__#INCLUDE <unistd.h>// Defines the implementation of write _syscall3 (int,write,int,fd,const char *,buf,off_t,count)
Here's why you have a # define __LIBRARY__.
Since the Unistd.h has
#ifdef __library__/* Middle omitted */#define __NR_WRITE4/* Middle omitted *///has 3 parameters of the system call macro function # # _SYSCALL3 (Type,name,atype,a,btype,b, CTYPE,C) type name (Atype a,btype b,ctype c) {long __res; __asm__ volatile ("int $0x80": "=a" (__res): "0" (__nr_# #name) , "B" ((long) (a)), "C" ((long) (b)), "D" ((long) (c))); if (__res>=0) return (type) __res; Errno=-__res; return-1; } #endif/* __library__ */
be able to find that if there is no # define __LIBRARY__ before # include <unistd.h>, then the following _syscall3 (Int,write,int,fd,const Char *,buf,off_t, count) is not found.
This design is very graceful, without the need to call the system files by not including the # define __LIBRARY__, you can save unistd.h some useless definitions.
So write has the implementation, we found that there is __nr_# #name, in write it for __nr_# #write. It has defined # define # __nr_write4 above. 4 stands for what. Have the following definitions
Fn_ptr sys_call_table[] = {sys_setup, sys_exit, Sys_fork, Sys_read,sys_write, ...};
That is, write will call Sys_write,sys_write in the read_write.c file.
int sys_write (unsigned int fd,char * Buf,int count)//writes what the user process wants to write to the kernel's file page buffer {struct file * file;struct M_inode * inode;// Exception error handling if (Fd>=nr_open | | count <0 | |! ( FILE=CURRENT->FILP[FD]) return-einval;if (!count) return 0;//fetch the corresponding I node of the file, if the pipeline file, and is the write pipeline file mode. Then write a pipe operation Inode=file->f_inode;if (Inode->i_pipe) return (FILE->F_MODE&2)?Write_pipe (Inode,buf,count):-eio;//is assumed to be a character file. Then the write character device if (S_ISCHR (Inode->i_mode)) return Rw_char (Write,inode->i_zone[0],buf,count,&file->f_pos); If it is a block device file, then the block device write operation if (S_ISBLK (Inode->i_mode)) return Block_write (Inode->i_zone[0],&file->f_pos,buf, count), or//if it is a regular file, write the file if (S_isreg (Inode->i_mode)) return File_write (Inode,file,buf,count);p rintk ("(write) Inode->i_mode=%06o\n\r ", inode->i_mode); return-einval;}
Here's a look at the regular file write operation File_write, in FILE_DEV.C
Based on the I node and the file structure information. Writes user data to the specified device int file_write (struct m_inode * inode, struct file * filp, char * buf, int count) {off_t Pos;int block,c;struct Buffer_head * Bh;char * p;int i=0;/* * OK, append may isn't work when many processes is writing at the same time * and so W Hat. That's the leads to madness anyway. *///Assume that you want to add data to the file. The file read-write pointer is moved to the end of the file. Otherwise, the read-write pointer in the file is written to if (Filp->f_flags & o_append) pos = Inode->i_size;elsepos = filp->f_pos;// If the number of bytes I have written is less than the number of bytes that need to be written, then loop while (I<count) {//Create block number pos/block_size the corresponding logical block on the device if (!) block = Create_block (inode,pos/block_size))) Break;if (! ( Bh=bread (Inode->i_dev,block))) break;//find the offset value C of the file read-write pointer in the data block, and point P to the read-out position in the data block buffer. Set the buffer changed flag c = pos% Block_size;p = c + bh->b_data;bh->b_dirt = 1;//from start to write location to block total writable c = block_size-c bytes, if C is greater than the remaining number of bytes required to write C Ount-i, then//this time only need to write c = Count-ic = Block_size-c;if (C > count-i) c = count-i;//file read/write pointer forward the number of bytes to be written. If the current file read-write pointer position value exceeds the size of the file, then change the file//Size field in the I node, and set the I node changed flag pos + = c;if (pos > inode->i_size) {inode->i_size = pos;inode- >i_diRT = 1;} The number of bytes written to the byte count accumulated in this write C. Copy the C bytes from the user buffer buf into the fast buffer where p points to the beginning. Then release the buffer i + = C;while (c-->0) * (p++) = Get_fs_byte (buf++); Brelse (BH);} Change the file churn time to the current time Inode->i_mtime = current_time;//Assuming this operation is not joined at the end of the file, the file read-write pointer is adjusted to the current write position. and change the I-node churn time to the current time if (!) ( Filp->f_flags & o_append) {Filp->f_pos = Pos;inode->i_ctime = Current_time;} Return (I?I:-1);}
Summary:
We can wirte the disk, serial port and file in the user layer, but we make a distinction in the system call layer.
Write implementation in Linux 0.11