/* Check for backup and repeat */ if (_IO_in_backup (fp)) // 处于backup模式 { _IO_switch_to_main_get_area (fp); continue; }
/* If we now want less than a buffer, underflow and repeat the copy. Otherwise, _IO_SYSREAD directly to the user buffer. */ if (fp->_IO_buf_base && want < (size_t) (fp->_IO_buf_end - fp->_IO_buf_base)) // 缓冲区存在且空间大于所需大小 { if (__underflow (fp) == EOF) // 调用__underflow,其会系统调用read从文件读取数据填充读缓冲区 break;
continue; }
/* These must be set before the sysread as we might longjmp out waiting for input. */ _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); // 此时是所需数据大小缓冲区大小,则设置好各个指针,准备直接系统调用read整块读取 _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
/* Try to maintain alignment: read a whole number of blocks. */ count = want; if (fp->_IO_buf_base) { size_t block_size = fp->_IO_buf_end - fp->_IO_buf_base; // 进行一些对齐优化 if (block_size >= 128) count -= want % block_size; }
if (fp->_IO_buf_base == NULL) // 缓冲区为空,分配缓冲区 { /* Maybe we already have a push back pointer. */ if (fp->_IO_save_base != NULL) // 此前处于backup模式,释放backup缓冲区 { free (fp->_IO_save_base); fp->_flags &= ~_IO_IN_BACKUP; } _IO_doallocbuf (fp); // 调用_IO_doallocbuf分配缓冲区 }
/* FIXME This can/should be moved to genops ?? */ if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED)) // 如果当前流是行缓冲或无缓冲输入,那么在输入前要刷新 stdout,防止命令行输出滞后 { /* We used to flush all line-buffered stream. This really isn't required by any standard. My recollection is that traditional Unix systems did this for stdout. stderr better not be line buffered. So we do just that here explicitly. --drepper */ _IO_acquire_lock (stdout);
/* This is very tricky. We have to adjust those pointers before we call _IO_SYSREAD () since we may longjump () out while waiting for input. Those pointers may be screwed up. H.J. */ fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base; fp->_IO_read_end = fp->_IO_buf_base; fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end = fp->_IO_buf_base;
count = _IO_SYSREAD (fp, fp->_IO_buf_base, fp->_IO_buf_end - fp->_IO_buf_base); // 调用_IO_SYSREAD从文件读取到缓冲区 if (count <= 0) { if (count == 0) // 遇到EOF fp->_flags |= _IO_EOF_SEEN; else// 遇到错误 fp->_flags |= _IO_ERR_SEEN, count = 0; } fp->_IO_read_end += count; // 根据填充数据量更新读缓冲区end指针 if (count == 0) // EOF时,防止其他错误,unset文件指针偏移 { /* If a stream is read to EOF, the calling application may switch active handles. As a result, our offset cache would no longer be valid, so unset it. */ fp->_offset = _IO_pos_BAD; return EOF; } if (fp->_offset != _IO_pos_BAD) _IO_pos_adjust (fp->_offset, count); // 调整文件指针偏移 return *(unsignedchar *) fp->_IO_read_ptr; // 返回填充到缓冲区的第一个字节 } libc_hidden_ver (_IO_new_file_underflow, _IO_file_underflow)