-
Question: Please describe the process of printf in xv6, from invocation to printing char on the screen.
void printf(int fd, char *fmt, ...)
输入使一个 file descriptor,一个格式字符串和格式串中对应的变量。在
printf
函数中,逐个遍历fmt
格式串中的字符,如果不是 ‘%’ 就直接把这个字符用putc
函数输出;如果是 ‘%’ 就根据后一个字符来分析,对应输出后面对应的变量。再来看
putc(int fd, char c)
这个函数。static void putc(int fd, char c)
直接调用了
write(fd, &c, 1)
,是一个系统调用,对于文件的写操作。也就是说向 console 的输出是抽象为向文件的输出来实现的。而在 xv6 定义的 file 类里:struct file { enum { FD_NONE, FD_PIPE, FD_INODE } type; int ref; // reference count char readable; char writable; struct pipe *pipe; struct inode *ip; uint off; };
write
是系统调用,调用了sys_write
这个函数,这个函数又调用了filewrite
这个函数。而在filewrite
中,检查了当前传入的 fd 类型,做了一些锁相关的操作,然后调用了writei
这个函数(这时候传入的是当前 fd 对应的 inode)。在writei
函数中,检查 inode 类型,如果为T_DEV
类型,则说明当前文件并非传统意义的文件,而是一个 IO 设备抽象而来的。这时候根据当前 inode 里储存的 major 变量,去查devsw
这张表(major 作为偏移量),这张表中的每个元素是由两个方法组成(实现为函数指针),分别对应着硬件的读和写。具体在console.c
的consoleinit
函数中定义。调用这张表中的某一项的 write 方法即调用consolewrite
这个函数。consolewrite
中做了一些关于锁的操作然后调用了consputc
这个函数。consputc
中检查了删除键,如果不是删除键就调用uartputc
和cgaputc
这两个函数。其中cgaputc
即在屏幕上打印词谱
网友评论