struct iobuf {
void *io_base; // the base addr of buffer (used for Rd/Wr)
off_t io_offset; // current Rd/Wr position in buffer, will have been incremented by the amount transferred
size_t io_len; // the length of buffer (used for Rd/Wr)
size_t io_resid; // current resident length need to Rd/Wr, will have been decremented by the amount transferred.
};
// user/libs/file.c
//这是用户态程序可以使用的“系统库函数”,从文件fd读取len个字节到base这个位置。
//当fd = 0的时候,表示从stdin读取
int read(int fd, void *base, size_t len) {
return sys_read(fd, base, len);
}
// user/libs/umain.c
int main(int argc, char *argv[]);
static int initfd(int fd2, const char *path, uint32_t open_flags) {
int fd1, ret;
if ((fd1 = open(path, open_flags)) < 0) {
return fd1;
}//我们希望文件描述符是fd2, 但是分配的fd1如果不等于fd2, 就需要做一些处理
if (fd1 != fd2) {
close(fd2);
ret = dup2(fd1, fd2);//通过sys_dup让两个文件描述符指向同一个文件
close(fd1);
}
return ret;
}
void umain(int argc, char *argv[]) {
int fd;
if ((fd = initfd(0, "stdin:", O_RDONLY)) < 0) {
warn("open <stdin> failed: %e.\n", fd);
}//0用于描述stdin,这里因为第一个被打开,所以stdin会分配到0
if ((fd = initfd(1, "stdout:", O_WRONLY)) < 0) {
warn("open <stdout> failed: %e.\n", fd);
}//1用于描述stdout
int ret = main(argc, argv); //真正的“用户程序”
exit(ret);
}
// kern/trap/trap.c
void interrupt_handler(struct trapframe *tf) {
intptr_t cause = (tf->cause << 1) >> 1;
switch (cause) {
/*...*/
case IRQ_S_TIMER:
clock_set_next_event();
if (++ticks % TICK_NUM == 0 && current) {
// print_ticks();
current->need_resched = 1;
}
run_timer_list();
//按理说用户程序看到的stdin是“只读”的
//但是,一个文件,只往外读,不往里写,是不是会导致数据"不守恒"?
//我们在这里就是把控制台输入的数据“写到”stdin里(实际上是写到一个缓冲区里)
//这里的cons_getc()并不一定能返回一个字符,可以认为是轮询
//如果cons_getc()返回0, 那么dev_stdin_write()函数什么都不做
dev_stdin_write(cons_getc());
break;
}
}
// kern/driver/console.c
#define CONSBUFSIZE 512
static struct {
uint8_t buf[CONSBUFSIZE];
uint32_t rpos;
uint32_t wpos; //控制台的输入缓冲区是一个队列
} cons;
/* *
* cons_intr - called by device interrupt routines to feed input
* characters into the circular console input buffer.
* */
void cons_intr(int (*proc)(void)) {
int c;
while ((c = (*proc)()) != -1) {
if (c != 0) {
cons.buf[cons.wpos++] = c;
if (cons.wpos == CONSBUFSIZE) {
cons.wpos = 0;
}
}
}
}
/* serial_proc_data - get data from serial port */
int serial_proc_data(void) {
int c = sbi_console_getchar();
if (c < 0) {
return -1;
}
if (c == 127) {
c = '\b';
}
return c;
}
/* serial_intr - try to feed input characters from serial port */
void serial_intr(void) {
cons_intr(serial_proc_data);
}
/* *
* cons_getc - return the next input character from console,
* or 0 if none waiting.
* */
int cons_getc(void) {
int c = 0;
bool intr_flag;
local_intr_save(intr_flag);
{
// poll for any pending input characters,
// so that this function works even when interrupts are disabled
// (e.g., when called from the kernel monitor).
serial_intr();
// grab the next character from the input buffer.
if (cons.rpos != cons.wpos) {
c = cons.buf[cons.rpos++];
if (cons.rpos == CONSBUFSIZE) {
cons.rpos = 0;
}
}
}
local_intr_restore(intr_flag);
return c;
}