看了一下Linux 0.11版本号write的实现,首先它在标准头文件unistd.h中有定义

int write(int fildes, const char * buf, off_t count);

接下来看write.c

/*
* linux/lib/write.c
*
* (C) 1991 Linus Torvalds
*/ #define __LIBRARY__
#include <unistd.h> //定义write的实现
_syscall3(int,write,int,fd,const char *,buf,off_t,count)

这里说明一下为什么要有#define __LIBRARY__。

由于在unistd.h有

#ifdef __LIBRARY__

/*中间省略*/

#define __NR_write	4

/*中间省略*/

//有3个參数的系统调用宏函数
#define _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__ */

能够发现,若在#include <unistd.h>之前没有#define __LIBRARY__,则以下的_syscall3(int,write,int,fd,const char *,buf,off_t,count)是找不到的。

这样的设计非常优美,不须要系统调用的文件通过不包括#define __LIBRARY__,便能省去unistd.h中一些没用的定义。

这样write便拥有了实现,我们发现当中有__NR_##name,在write中它为__NR_##write。它在上面有定义#define __NR_write4。4代表什么。有以下的定义

fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, ... };

也就是所write会调用sys_write,sys_write在read_write.c文件里

int sys_write(unsigned int fd,char * buf,int count) //将用户进程要写的内容写入到内核的文件页面缓冲中
{
struct file * file;
struct m_inode * inode; //异常错误处理
if (fd>=NR_OPEN || count <0 || !(file=current->filp[fd]))
return -EINVAL;
if (!count)
return 0;
//取文件相应的i节点,若是管道文件,而且是写管道文件模式。则进行写管道操作
inode=file->f_inode;
if (inode->i_pipe)
return (file->f_mode&2)? write_pipe(inode,buf,count):-EIO;
//假设是字符型文件。则进行写字符设备
if (S_ISCHR(inode->i_mode))
return rw_char(WRITE,inode->i_zone[0],buf,count,&file->f_pos);
//假设是块设备文件,则进行块设备写操作
if (S_ISBLK(inode->i_mode))
return block_write(inode->i_zone[0],&file->f_pos,buf,count);
//假设是常规文件,则进行写文件
if (S_ISREG(inode->i_mode))
return file_write(inode,file,buf,count);
printk("(Write)inode->i_mode=%06o\n\r",inode->i_mode);
return -EINVAL;
}

这里看一看常规文件写操作file_write,在file_dev.c中

//依据i节点和文件结构信息。将用户数据写入指定设备
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 not work when many processes are writing at the same time
* but so what. That way leads to madness anyway.
*/
//假设是要向文件后加入数据。则将文件读写指针移到文件尾部。否则就将在文件读写指针出写入
if (filp->f_flags & O_APPEND)
pos = inode->i_size;
else
pos = filp->f_pos;
//若已经写入字节数i小于须要写入的字节数count,则循环
while (i<count) {
//创建数据块号pos/BLOCK_SIZE在设备上相应的逻辑块
if (!(block = create_block(inode,pos/BLOCK_SIZE)))
break;
if (!(bh=bread(inode->i_dev,block)))
break;
//求出文件读写指针在数据块中的偏移值c,将p指向读出数据块缓冲区中開始读取的位置。置该缓冲区已改动标志
c = pos % BLOCK_SIZE;
p = c + bh->b_data;
bh->b_dirt = 1;
//从開始读写位置到块末共可写入c = BLOCK_SIZE-c个字节,若c大于剩余还需写入的字节数count-i,则
//此次仅仅需再写入c = count-i
c = BLOCK_SIZE-c;
if (c > count-i) c = count-i;
//文件读写指针前移此次需写入的字节数。假设当前文件读写指针位置值超过了文件的大小,则改动i节点中文件
//大小字段,并置i节点已改动标志
pos += c;
if (pos > inode->i_size) {
inode->i_size = pos;
inode->i_dirt = 1;
}
//已写入字节计数累加此次写入的字节数c。从用户缓冲区buf中复制c个字节到快速缓冲区中p指向開始的位置处。
//然后释放该缓冲区
i += c;
while (c-->0)
*(p++) = get_fs_byte(buf++);
brelse(bh);
}
//更改文件改动时间为当前时间
inode->i_mtime = CURRENT_TIME;
//假设此次操作不是在文件尾部加入,则把文件读写指针调整到当前写位置。并更改i节点改动时间为当前时间
if (!(filp->f_flags & O_APPEND)) {
filp->f_pos = pos;
inode->i_ctime = CURRENT_TIME;
}
return (i? i:-1);
}

总结:

我们在用户层能够对磁盘、串口和文件通用wirte,但在系统调用层便进行了区分。

Linux 0.11中write实现的更多相关文章

  1. Linux 0.11下信号量的实现和应用

    Linux 011下信号量的实现和应用 生产者-消费者问题 实现信号量 信号量的代码实现 关于sem_wait和sem_post sem_wait和sem_post函数的代码实现 信号量的完整代码 实 ...

  2. 【从头到脚品读 Linux 0.11 源码】第一回 最开始的两行代码

    从这一篇开始,您就将跟着我一起进入这操作系统的梦幻之旅! 别担心,每一章的内容会非常的少,而且你也不要抱着很大的负担去学习,只需要像读小说一样,跟着我一章一章读下去就好. 话不多说,直奔主题.当你按下 ...

  3. Linux 0.11源码阅读笔记-总结

    总结 Linux 0.11主要包含文件管理和进程管理两个部分.进程管理包括内存管理.进程管理.进程间通信模块.文件管理包含磁盘文件系统,打开文件内存数据.磁盘文件系统包括空闲磁盘块管理,文件数据块的管 ...

  4. Linux 0.11源码阅读笔记-文件管理

    Linux 0.11源码阅读笔记-文件管理 文件系统 生磁盘 未安装文件系统的磁盘称之为生磁盘,生磁盘也可以作为文件读写,linux中一切皆文件. 磁盘分区 生磁盘可以被分区,分区中可以安装文件系统, ...

  5. Linux 0.11源码阅读笔记-中断过程

    Linux 0.11源码阅读笔记-中断过程 是什么中断 中断发生时,计算机会停止当前运行的程序,转而执行中断处理程序,然后再返回原被中断的程序继续运行.中断包括硬件中断和软件中断,硬中断是由外设自动产 ...

  6. Linux 0.11源码阅读笔记-总览

    Linux 0.11源码阅读笔记-总览 阅读源码的目的 加深对Linux操作系统的了解,了解Linux操作系统基本架构,熟悉进程管理.内存管理等主要模块知识. 通过阅读教复杂的代码,锻炼自己复杂项目代 ...

  7. Linux 0.11源码阅读笔记-块设备驱动程序

    块设备驱动程序 块设备驱动程序负责实现对块设备数据的读写功能.内核代码统一使用缓冲块间接和块设备(如磁盘)交换数据,缓冲区数据通过块设备驱动程序和块设备交换数据. 块设备的管理 块设备表 内核通过一张 ...

  8. 利用bochs调试Linux 0.11内核

    引导程序调试软件bochs,跟配套的linux0.11内核img下载地址分别是: http://sourceforge.net/projects/bochs/http://www.oldlinux.o ...

  9. Linux 0.11源码阅读笔记-文件IO流程

    文件IO流程 用户进程read.write在高速缓冲块上读写数据,高速缓冲块和块设备交换数据. 什么时机将磁盘块数据读到缓冲块? 什么时机将缓冲块数据刷到磁盘块? 函数调用关系 read/write( ...

随机推荐

  1. RabbitMQ从入门到精通

    RabbitMQ从入门到精通 学习了:http://blog.csdn.net/column/details/rabbitmq.html RabbitMQ是AMQP(advanced message ...

  2. 一种基于Qt的可伸缩的全异步C/S架构server实现(五) 单层无中心集群

    五.单层无中心集群 对40万用户规模以内的server.使用星形的无中心连接是较为简便的实现方式.分布在各个物理server上的服务进程共同工作.每一个进程承担若干连接.为了实现这个功能,须要解决几个 ...

  3. hdu 4717 The Moving Points(三分)

    http://acm.hdu.edu.cn/showproblem.php?pid=4717 大致题意:给出每一个点的坐标以及每一个点移动的速度和方向. 问在那一时刻点集中最远的距离在全部时刻的最远距 ...

  4. 在不同的浏览器下FORM及它的小伙伴们默认样式的CSS属性值是不全然一致

    我们一般在定义CSS样式的时候都须要定义去掉HTML标签默认样式的CSS,原因是在不同的浏览器以下它们的表现出来的默认样式不全然一致,我们要保证在不同的浏览器下它们能正常显示出我们想要达到的预期效果, ...

  5. NFS安装和配置

    ---------------------------------------------------------------------------------------------------- ...

  6. 0x25 广度优先搜索

    今天莫名不想说话. 结果发现效率挺高? poj3322 本来可以1a的..发现我宽搜写的是head<=tail而且初始是head=1,tail=2如果是多组数据简直就gg了.基础不牢固 这题虽然 ...

  7. 0x21 剪枝

    这一章真是心态崩,剪枝太玄学啦,特别是那个搜索顺序我靠真的... poj1011 枚举答案,搜索记录当前到第几根木棒. 剪枝:1.从大到小排序 2.排除等效,这个感觉还行,就是木棒按大小顺序进去,去除 ...

  8. 最好的PHP框架有哪些

    最好的PHP框架有哪些 首推 Laravel ,其次是 Yii,Laravel 的设计思想以及在工程实践上的支持,超过 ThinkPHP 好几个世代.如果说原生的 PHP 是火枪, ThinkPHP ...

  9. UESTC--1269--ZhangYu Speech(模拟)

    ZhangYu Speech Time Limit: 1000MS   Memory Limit: 65535KB   64bit IO Format: %lld & %llu Submit ...

  10. [jzoj 5662] 尺树寸泓 解题报告 (线段树+中序遍历)

    interlinkage: https://jzoj.net/senior/#contest/show/2703/1 description: solution: 发现$dfs$序不好维护 注意到这是 ...