看了一下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. [Angular] Getting to Know the @Attribute Decorator in Angular

    So when you using input binding in Angular, it will always check for update. If you want to improve ...

  2. uva 10003 Cutting Sticks 【区间dp】

    题目:uva 10003 Cutting Sticks 题意:给出一根长度 l 的木棍,要截断从某些点,然后截断的花费是当前木棍的长度,求总的最小花费? 分析:典型的区间dp,事实上和石子归并是一样的 ...

  3. sqlite学习笔记6:更新表数据-update

    一 条件推断 在SQL中条件推断使用where,相当于其它变成语言中的if,基本使用方法如: SELECT column1, column2, columnN FROM table_name WHER ...

  4. hdu 2151

    就是一个dp,数组内存的步数, 数组没清空,wa了一次 #include<cstdio> #include<algorithm> #include<cstring> ...

  5. Codeforces Round #260 (Div. 1) 455 A. Boredom (DP)

    题目链接:http://codeforces.com/problemset/problem/455/A A. Boredom time limit per test 1 second memory l ...

  6. wikioi 1396 伸展树(两个模板)

    题目描写叙述 Description Tiger近期被公司升任为营业部经理.他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况. Tiger拿出了公司的账本,账本上记录了公司成立以来 ...

  7. idea 中web项目 用自带tomcat启动问题,

    严重: Exception sending context initialized event to listener instance of class com.zenointel.logserve ...

  8. java 中的静态(static)代码块

    类字面常量 final 静态域不会触发类的初始化操作 非 final static 静态域(以及构造器其实是一种隐式的静态方法) Class.forName():会自动的初始化: 使用 .class来 ...

  9. 剑指offer——02替换空格(Python3)

    思路:Python列表中实现字符串的替换,涉及到频繁的插入操作,在数据结构中线性表分为顺序表和链表,顺序表的适合频繁的查询,链表适合频繁的插入和删除.综上所述,本题使用链表来实现. 我们从字符串的后面 ...

  10. POJ 3628 01背包 OR 状压

    思路: 1.01背包 先找到所有奶牛身高和与B的差. 然后做一次01背包即可 01背包的容积和价格就是奶牛们身高. 最后差值一减输出结果就大功告成啦! 2. 搜索 这思路很明了吧... 搜索的确可以过 ...