开始IO啦!hgame week4的两道IO都摆烂放弃了,打算之后再系统学IO,how2heap暂时告一段落了就IO走起 ps:先马马虎虎翻一遍,以后如果有需要再细看
基本结构体与全局变量 _IO_FILE 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 struct _IO_FILE { int _flags; #define _IO_file_flags _flags char * _IO_read_ptr; char * _IO_read_end; char * _IO_read_base; char * _IO_write_base; char * _IO_write_ptr; char * _IO_write_end; char * _IO_buf_base; char * _IO_buf_end; char *_IO_save_base; char *_IO_backup_base; char *_IO_save_end; struct _IO_marker *_markers ; struct _IO_FILE *_chain ; int _fileno;#if 0 int _blksize;#else int _flags2;#endif _IO_off_t _old_offset; #define __HAVE_COLUMN unsigned short _cur_column; signed char _vtable_offset; char _shortbuf[1 ]; _IO_lock_t *_lock;#ifdef _IO_USE_OLD_IO_FILE };struct _IO_FILE_complete { struct _IO_FILE _file ;#endif #if defined _G_IO_IO_FILE_VERSION && _G_IO_IO_FILE_VERSION == 0x20001 _IO_off64_t _offset;# if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T struct _IO_codecvt *_codecvt ; struct _IO_wide_data *_wide_data ; struct _IO_FILE *_freeres_list ; void *_freeres_buf;# else void *__pad1; void *__pad2; void *__pad3; void *__pad4;# endif size_t __pad5; int _mode; char _unused2[15 * sizeof (int ) - 4 * sizeof (void *) - sizeof (size_t )];#endif };
重要成员:
_flags:高位字为IO_MAGIC,剩余的部分是flag
_IO_read_ptr:input指针现在的位置
_IO_read_end:input缓冲区的结束地址
_IO_read_base:input缓冲区的基址
_IO_write_base:output缓冲区的基址
_IO_write_ptr:output指针现在的位置
_IO_write_end:output指针的结束地址
_IO_buf_base:缓冲区基址
_IO_buf_end:缓冲区结束地址
_chain:相当于fd指针,用于形成单链表串联所有的file stream
_fileno:与文件相关的文件描述符
_vtable_offset:存放虚表(virtual table)的偏移
_offset:存放当前文件的偏移 ps:在看fopen源码时注意到有的成员不属于_IO_FILE而属于_IO_FILE_complete,根据宏定义#ifdef _IO_USE_OLD_IO_FILE,如果没有定义_IO_USE_OLD_IO_FILE,那么_IO_FILE_complete之后的成员是属于_IO_FILE的(应该是为了兼容性考虑)
_IO_FILE_plus 1 2 3 4 5 6 7 struct _IO_FILE_plus { _IO_FILE file; const struct _IO_jump_t *vtable ; };
成员偏移:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 amd64: 0x0 :'_flags' ,0x8 :'_IO_read_ptr' ,0x10 :'_IO_read_end' ,0x18 :'_IO_read_base' ,0x20 :'_IO_write_base' ,0x28 :'_IO_write_ptr' ,0x30 :'_IO_write_end' ,0x38 :'_IO_buf_base' ,0x40 :'_IO_buf_end' ,0x48 :'_IO_save_base' ,0x50 :'_IO_backup_base' ,0x58 :'_IO_save_end' ,0x60 :'_markers' ,0x68 :'_chain' ,0x70 :'_fileno' ,0x74 :'_flags2' ,0x78 :'_old_offset' ,0x80 :'_cur_column' ,0x82 :'_vtable_offset' ,0x83 :'_shortbuf' ,0x88 :'_lock' ,0x90 :'_offset' ,0x98 :'_codecvt' ,0xa0 :'_wide_data' ,0xa8 :'_freeres_list' ,0xb0 :'_freeres_buf' ,0xb8 :'__pad5' ,0xc0 :'_mode' ,0xc4 :'_unused2' ,0xd8 :'vtable'
_IO_jump_t _IO_FILE_plus前一部分是_IO_FILE结构体,后一部分就是指向_IO_jump_t结构体的vtable指针,其实就是虚表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 struct _IO_jump_t { JUMP_FIELD(size_t , __dummy); JUMP_FIELD(size_t , __dummy2); JUMP_FIELD(_IO_finish_t, __finish); JUMP_FIELD(_IO_overflow_t, __overflow); JUMP_FIELD(_IO_underflow_t, __underflow); JUMP_FIELD(_IO_underflow_t, __uflow); JUMP_FIELD(_IO_pbackfail_t, __pbackfail); JUMP_FIELD(_IO_xsputn_t, __xsputn); JUMP_FIELD(_IO_xsgetn_t, __xsgetn); JUMP_FIELD(_IO_seekoff_t, __seekoff); JUMP_FIELD(_IO_seekpos_t, __seekpos); JUMP_FIELD(_IO_setbuf_t, __setbuf); JUMP_FIELD(_IO_sync_t, __sync); JUMP_FIELD(_IO_doallocate_t, __doallocate); JUMP_FIELD(_IO_read_t, __read); JUMP_FIELD(_IO_write_t, __write); JUMP_FIELD(_IO_seek_t, __seek); JUMP_FIELD(_IO_close_t, __close); JUMP_FIELD(_IO_stat_t, __stat); JUMP_FIELD(_IO_showmanyc_t, __showmanyc); JUMP_FIELD(_IO_imbue_t, __imbue);#if 0 get_column; set_column;#endif };
_IO_wide_data 为数据较多的流设置,根据宏
1 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
判断是否启用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 struct _IO_wide_data { wchar_t *_IO_read_ptr; wchar_t *_IO_read_end; wchar_t *_IO_read_base; wchar_t *_IO_write_base; wchar_t *_IO_write_ptr; wchar_t *_IO_write_end; wchar_t *_IO_buf_base; wchar_t *_IO_buf_end; wchar_t *_IO_save_base; wchar_t *_IO_backup_base; wchar_t *_IO_save_end; __mbstate_t _IO_state; __mbstate_t _IO_last_state; struct _IO_codecvt _codecvt ; wchar_t _shortbuf[1 ]; const struct _IO_jump_t *_wide_vtable ; };
_IO_file_jumps 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 const struct _IO_jump_t _IO_file_jumps = { JUMP_INIT_DUMMY, JUMP_INIT(finish, _IO_file_finish), JUMP_INIT(overflow, _IO_file_overflow), JUMP_INIT(underflow, _IO_file_underflow), JUMP_INIT(uflow, _IO_default_uflow), JUMP_INIT(pbackfail, _IO_default_pbackfail), JUMP_INIT(xsputn, _IO_file_xsputn), JUMP_INIT(xsgetn, _IO_file_xsgetn), JUMP_INIT(seekoff, _IO_new_file_seekoff), JUMP_INIT(seekpos, _IO_default_seekpos), JUMP_INIT(setbuf, _IO_new_file_setbuf), JUMP_INIT(sync, _IO_new_file_sync), JUMP_INIT(doallocate, _IO_file_doallocate), JUMP_INIT(read, _IO_file_read), JUMP_INIT(write, _IO_new_file_write), JUMP_INIT(seek, _IO_file_seek), JUMP_INIT(close, _IO_file_close), JUMP_INIT(stat, _IO_file_stat), JUMP_INIT(showmanyc, _IO_default_showmanyc), JUMP_INIT(imbue, _IO_default_imbue) };
其中的宏定义如下,实际上就是各个函数的跳转表:
1 2 JUMP_INIT(dummy, 0 ), JUMP_INIT (dummy2, 0 )#define JUMP_INIT(NAME,VALUE) VALUE
_IO_list_all _IO_list_all->_IO_2_1_stderr_->_IO_2_1_stdout_->_IO_2_1_stdin_
1 2 3 struct _IO_FILE_plus *_IO_list_all = &_IO_2_1_stderr_;
_IO_2_1_stderr_、_IO_2_1_stdout_和_IO_2_1_stdin_的定义其实在这(搜索的时候没找到)
珍爱生命,远离宏定义
1 2 3 4 5 DEF_STDFILE(_IO_2_1_stdin_, 0 , 0 , _IO_NO_WRITES); DEF_STDFILE(_IO_2_1_stdout_, 1 , &_IO_2_1_stdin_, _IO_NO_READS); DEF_STDFILE(_IO_2_1_stderr_, 2 , &_IO_2_1_stdout_, _IO_NO_READS+_IO_UNBUFFERED);
第一层宏定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T # define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \ static struct _IO_wide_data _IO_wide_data_##FD \ = { ._wide_vtable = &_IO_wfile_jumps }; \ struct _IO_FILE_plus NAME \ = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, &_IO_wide_data_##FD), \ &_IO_file_jumps}; # else # define DEF_STDFILE(NAME, FD, CHAIN, FLAGS) \ struct _IO_FILE_plus NAME \ = {FILEBUF_LITERAL(CHAIN, FLAGS, FD, NULL), \ &_IO_file_jumps}; # endif #endif
第一层解宏定义
1 2 3 struct _IO_FILE_plus _IO_2_1_stdin_ = {FILEBUF_LITERAL(0 , 8 , 0 , NULL ), &_IO_file_jumps};struct _IO_FILE_plus _IO_2_1_stdout_ = {FILEBUF_LITERAL(&_IO_2_1_stdin_, 4 , 1 , NULL ), &_IO_file_jumps};struct _IO_FILE_plus _IO_2_1_stderr_ = {FILEBUF_LITERAL(&_IO_2_1_stdout_, 4 +2 , 2 , NULL ), &_IO_file_jumps};
第二层宏定义
1 2 3 4 5 6 7 # define FILEBUF_LITERAL(CHAIN, FLAGS, FD, WDP) \ { _IO_MAGIC+_IO_LINKED+_IO_IS_FILEBUF+FLAGS, \ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (_IO_FILE *) CHAIN, FD, \ 0, _IO_pos_BAD, 0, 0, { 0 }, 0, _IO_pos_BAD, \ 0 }
_IO_list_all_stamp 记录_IO_list_all单链表更改的次数
1 2 3 4 static int _IO_list_all_stamp;
fopen 函数调用流程图:
stdio.h中的fopen实际上是_IO_new_fopen
1 2 3 4 extern _IO_FILE *_IO_new_fopen (const char *, const char *);# define fopen(fname, mode) _IO_new_fopen (fname, mode)
或者iofopen.c中也有
1 2 3 # define _IO_new_fopen fopen
_IO_new_fopen又调用了__fopen_internal
1 2 3 4 5 6 7 _IO_FILE * _IO_new_fopen (const char *filename, const char *mode) { return __fopen_internal (filename, mode, 1 ); }
__fopen_internal的流程如下:
malloc分配内存
调用_IO_no_init null初始化结构体数据
设置vtable为_IO_file_jumps
将_IO_FILE结构体链入_IO_list_all
打开文件1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 _IO_FILE * __fopen_internal (const char *filename, const char *mode, int is32) { struct locked_FILE { struct _IO_FILE_plus fp ;#ifdef _IO_MTSAFE_IO _IO_lock_t lock;#endif struct _IO_wide_data wd ; } *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE)); if (new_f == NULL ) return NULL ;#ifdef _IO_MTSAFE_IO new_f->fp.file._lock = &new_f->lock;#endif #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T _IO_no_init (&new_f->fp.file, 0 , 0 , &new_f->wd, &_IO_wfile_jumps);#else _IO_no_init (&new_f->fp.file, 1 , 0 , NULL , NULL );#endif _IO_JUMPS (&new_f->fp) = &_IO_file_jumps; _IO_file_init (&new_f->fp);#if !_IO_UNIFIED_JUMPTABLES new_f->fp.vtable = NULL ;#endif if (_IO_file_fopen ((_IO_FILE *) new_f, filename, mode, is32) != NULL ) return __fopen_maybe_mmap (&new_f->fp.file); _IO_un_link (&new_f->fp); free (new_f); return NULL ; }
_IO_no_init 调用了_IO_old_init,然后进行了一系列null初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 void _IO_no_init (_IO_FILE *fp, int flags, int orientation, struct _IO_wide_data *wd, const struct _IO_jump_t *jmp) { _IO_old_init (fp, flags); fp->_mode = orientation;#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T if (orientation >= 0 ) { fp->_wide_data = wd; fp->_wide_data->_IO_buf_base = NULL ; fp->_wide_data->_IO_buf_end = NULL ; fp->_wide_data->_IO_read_base = NULL ; fp->_wide_data->_IO_read_ptr = NULL ; fp->_wide_data->_IO_read_end = NULL ; fp->_wide_data->_IO_write_base = NULL ; fp->_wide_data->_IO_write_ptr = NULL ; fp->_wide_data->_IO_write_end = NULL ; fp->_wide_data->_IO_save_base = NULL ; fp->_wide_data->_IO_backup_base = NULL ; fp->_wide_data->_IO_save_end = NULL ; fp->_wide_data->_wide_vtable = jmp; } else fp->_wide_data = (struct _IO_wide_data *) -1L ;#endif fp->_freeres_list = NULL ; }
_IO_old_init 也是一系列null初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 void _IO_old_init (_IO_FILE *fp, int flags) { fp->_flags = _IO_MAGIC|flags; fp->_flags2 = 0 ; fp->_IO_buf_base = NULL ; fp->_IO_buf_end = NULL ; fp->_IO_read_base = NULL ; fp->_IO_read_ptr = NULL ; fp->_IO_read_end = NULL ; fp->_IO_write_base = NULL ; fp->_IO_write_ptr = NULL ; fp->_IO_write_end = NULL ; fp->_chain = NULL ; fp->_IO_save_base = NULL ; fp->_IO_backup_base = NULL ; fp->_IO_save_end = NULL ; fp->_markers = NULL ; fp->_cur_column = 0 ;#if _IO_JUMPS_OFFSET fp->_vtable_offset = 0 ;#endif #ifdef _IO_MTSAFE_IO if (fp->_lock != NULL ) _IO_lock_init (*fp->_lock);#endif }
_IO_file_init _IO_file_init也是一个宏,实际调用的函数是_IO_new_file_init
1 2 3 # define _IO_new_file_init _IO_file_init
_IO_new_file_init进行了一些初始化并调用了_IO_link_in
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void _IO_new_file_init (struct _IO_FILE_plus *fp) { fp->file._offset = _IO_pos_BAD; fp->file._IO_file_flags |= CLOSED_FILEBUF_FLAGS; _IO_link_in (fp); fp->file._fileno = -1 ; }
1 2 3 4 5 #define CLOSED_FILEBUF_FLAGS \ (_IO_IS_FILEBUF+_IO_NO_READS+_IO_NO_WRITES+_IO_TIED_PUT_GET)
_IO_link_in _IO_link_in将_IO_FILE_plus结构体链入_IO_list_all单链表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 void _IO_link_in (struct _IO_FILE_plus *fp) { if ((fp->file._flags & _IO_LINKED) == 0 ) { fp->file._flags |= _IO_LINKED;#ifdef _IO_MTSAFE_IO _IO_cleanup_region_start_noarg (flush_cleanup); _IO_lock_lock (list_all_lock); run_fp = (_IO_FILE *) fp; _IO_flockfile ((_IO_FILE *) fp);#endif fp->file._chain = (_IO_FILE *) _IO_list_all; _IO_list_all = fp; ++_IO_list_all_stamp;#ifdef _IO_MTSAFE_IO _IO_funlockfile ((_IO_FILE *) fp); run_fp = NULL ; _IO_lock_unlock (list_all_lock); _IO_cleanup_region_end (0 );#endif } }
_IO_file_fopen 这其实也是个宏定义,实际上调用的函数是_IO_new_file_fopen
1 2 3 # define _IO_new_file_fopen _IO_file_fopen
_IO_new_file_fopen的过程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 _IO_FILE * _IO_new_file_fopen (_IO_FILE *fp, const char *filename, const char *mode, int is32not64) { int oflags = 0 , omode; int read_write; int oprot = 0666 ; int i; _IO_FILE *result;#ifdef _LIBC const char *cs; const char *last_recognized;#endif if (_IO_file_is_open (fp)) return 0 ; switch (*mode) { case 'r' : omode = O_RDONLY; read_write = _IO_NO_WRITES; break ; case 'w' : omode = O_WRONLY; oflags = O_CREAT|O_TRUNC; read_write = _IO_NO_READS; break ; case 'a' : omode = O_WRONLY; oflags = O_CREAT|O_APPEND; read_write = _IO_NO_READS|_IO_IS_APPENDING; break ; default : __set_errno (EINVAL); return NULL ; }#ifdef _LIBC last_recognized = mode;#endif for (i = 1 ; i < 7 ; ++i) { switch (*++mode) { case '\0' : break ; case '+' : omode = O_RDWR; read_write &= _IO_IS_APPENDING;#ifdef _LIBC last_recognized = mode;#endif continue ; case 'x' : oflags |= O_EXCL;#ifdef _LIBC last_recognized = mode;#endif continue ; case 'b' :#ifdef _LIBC last_recognized = mode;#endif continue ; case 'm' : fp->_flags2 |= _IO_FLAGS2_MMAP; continue ; case 'c' : fp->_flags2 |= _IO_FLAGS2_NOTCANCEL; continue ; case 'e' :#ifdef O_CLOEXEC oflags |= O_CLOEXEC;#endif fp->_flags2 |= _IO_FLAGS2_CLOEXEC; continue ; default : continue ; } break ; } result = _IO_file_open (fp, filename, omode|oflags, oprot, read_write, is32not64); if (result != NULL ) {#ifndef __ASSUME_O_CLOEXEC if ((fp->_flags2 & _IO_FLAGS2_CLOEXEC) != 0 && __have_o_cloexec <= 0 ) { int fd = _IO_fileno (fp); if (__have_o_cloexec == 0 ) { int flags = __fcntl (fd, F_GETFD); __have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1 ; } if (__have_o_cloexec < 0 ) __fcntl (fd, F_SETFD, FD_CLOEXEC); }#endif cs = strstr (last_recognized + 1 , ",ccs=" ); if (cs != NULL ) { struct gconv_fcts fcts ; struct _IO_codecvt *cc ; char *endp = __strchrnul (cs + 5 , ',' ); char *ccs = malloc (endp - (cs + 5 ) + 3 ); if (ccs == NULL ) { int malloc_err = errno; (void ) _IO_file_close_it (fp); __set_errno (malloc_err); return NULL ; } *((char *) __mempcpy (ccs, cs + 5 , endp - (cs + 5 ))) = '\0' ; strip (ccs, ccs); if (__wcsmbs_named_conv (&fcts, ccs[2 ] == '\0' ? upstr (ccs, cs + 5 ) : ccs) != 0 ) { (void ) _IO_file_close_it (fp); free (ccs); __set_errno (EINVAL); return NULL ; } free (ccs); assert (fcts.towc_nsteps == 1 ); assert (fcts.tomb_nsteps == 1 ); fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end; fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base; memset (&fp->_wide_data->_IO_state, '\0' , sizeof (__mbstate_t )); memset (&fp->_wide_data->_IO_last_state, '\0' , sizeof (__mbstate_t )); cc = fp->_codecvt = &fp->_wide_data->_codecvt; *cc = __libio_codecvt; cc->__cd_in.__cd.__nsteps = fcts.towc_nsteps; cc->__cd_in.__cd.__steps = fcts.towc; cc->__cd_in.__cd.__data[0 ].__invocation_counter = 0 ; cc->__cd_in.__cd.__data[0 ].__internal_use = 1 ; cc->__cd_in.__cd.__data[0 ].__flags = __GCONV_IS_LAST; cc->__cd_in.__cd.__data[0 ].__statep = &result->_wide_data->_IO_state; cc->__cd_out.__cd.__nsteps = fcts.tomb_nsteps; cc->__cd_out.__cd.__steps = fcts.tomb; cc->__cd_out.__cd.__data[0 ].__invocation_counter = 0 ; cc->__cd_out.__cd.__data[0 ].__internal_use = 1 ; cc->__cd_out.__cd.__data[0 ].__flags = __GCONV_IS_LAST | __GCONV_TRANSLIT; cc->__cd_out.__cd.__data[0 ].__statep = &result->_wide_data->_IO_state; _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable; result->_mode = 1 ; } } return result; }
_IO_file_open 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 _IO_FILE * _IO_file_open (_IO_FILE *fp, const char *filename, int posix_mode, int prot, int read_write, int is32not64) { int fdesc;#ifdef _LIBC if (__glibc_unlikely (fp->_flags2 & _IO_FLAGS2_NOTCANCEL)) fdesc = open_not_cancel (filename, posix_mode | (is32not64 ? 0 : O_LARGEFILE), prot); else fdesc = open (filename, posix_mode | (is32not64 ? 0 : O_LARGEFILE), prot);#else fdesc = open (filename, posix_mode, prot);#endif if (fdesc < 0 ) return NULL ; fp->_fileno = fdesc; _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING); if ((read_write & (_IO_IS_APPENDING | _IO_NO_READS)) == (_IO_IS_APPENDING | _IO_NO_READS)) { _IO_off64_t new_pos = _IO_SYSSEEK (fp, 0 , _IO_seek_end); if (new_pos == _IO_pos_BAD && errno != ESPIPE) { close_not_cancel (fdesc); return NULL ; } } _IO_link_in ((struct _IO_FILE_plus *) fp); return fp; }
__fopen_maybe_mmap 当有_G_HAVE_MMAP定义时使用,根据读写模式决定操作方式?没看懂。最终返回_IO_FILE结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 _IO_FILE * __fopen_maybe_mmap (_IO_FILE *fp) {#ifdef _G_HAVE_MMAP if ((fp->_flags2 & _IO_FLAGS2_MMAP) && (fp->_flags & _IO_NO_WRITES)) { if (fp->_mode <= 0 ) _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_maybe_mmap; else _IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps_maybe_mmap; fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_maybe_mmap; }#endif return fp; }
_IO_un_link 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 void _IO_un_link (struct _IO_FILE_plus *fp) { if (fp->file._flags & _IO_LINKED) { struct _IO_FILE **f ;#ifdef _IO_MTSAFE_IO _IO_cleanup_region_start_noarg (flush_cleanup); _IO_lock_lock (list_all_lock); run_fp = (_IO_FILE *) fp; _IO_flockfile ((_IO_FILE *) fp);#endif if (_IO_list_all == NULL ) ; else if (fp == _IO_list_all) { _IO_list_all = (struct _IO_FILE_plus *) _IO_list_all->file._chain; ++_IO_list_all_stamp; } else for (f = &_IO_list_all->file._chain; *f; f = &(*f)->_chain) if (*f == (_IO_FILE *) fp) { *f = fp->file._chain; ++_IO_list_all_stamp; break ; } fp->file._flags &= ~_IO_LINKED;#ifdef _IO_MTSAFE_IO _IO_funlockfile ((_IO_FILE *) fp); run_fp = NULL ; _IO_lock_unlock (list_all_lock); _IO_cleanup_region_end (0 );#endif } }
fread 流程图如下:
执行fread函数时实际上执行的是_IO_fread函数,_IO_fread函数又调用了_IO_sgetn函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 _IO_size_t _IO_fread (void *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp) { _IO_size_t bytes_requested = size * count; _IO_size_t bytes_read; CHECK_FILE (fp, 0 ); if (bytes_requested == 0 ) return 0 ; _IO_acquire_lock (fp); bytes_read = _IO_sgetn (fp, (char *) buf, bytes_requested); _IO_release_lock (fp); return bytes_requested == bytes_read ? count : bytes_read / size; }
_IO_sgetn函数又调用了_IO_XSGETN函数,实际上就是跳转表中的__xsgetn函数
1 2 3 4 5 6 7 8 9 10 _IO_size_t _IO_sgetn (_IO_FILE *fp, void *data, _IO_size_t n) { return _IO_XSGETN (fp, data, n); }#define _IO_XSGETN(FP,DATA,N) JUMP2 (__xsgetn, FP, DATA, N)
_IO_file_xsgetn执行步骤如下:
如果缓冲区为空调用_IO_doallocbuf分配缓冲区
如果want<=have则读入want个字节并将want清零,否则执行以下步骤
如果还有字节剩余,则读入剩余have字节
如果存在backup则调用_IO_switch_to_main_get_area调用backup
如果缓冲区容量大于需求则调用__underflow向缓冲区中读入
将所有读写相关指针指向缓冲区基址
计算count,直接从文件中读取count字节
错误处理
调整文件偏移1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 _IO_size_t _IO_file_xsgetn (_IO_FILE *fp, void *data, _IO_size_t n) { _IO_size_t want, have; _IO_ssize_t count; char *s = data; want = n; if (fp->_IO_buf_base == NULL ) { if (fp->_IO_save_base != NULL ) { free (fp->_IO_save_base); fp->_flags &= ~_IO_IN_BACKUP; } _IO_doallocbuf (fp); } while (want > 0 ) { have = fp->_IO_read_end - fp->_IO_read_ptr; if (want <= have) { memcpy (s, fp->_IO_read_ptr, want); fp->_IO_read_ptr += want; want = 0 ; } else { if (have > 0 ) {#ifdef _LIBC s = __mempcpy (s, fp->_IO_read_ptr, have);#else memcpy (s, fp->_IO_read_ptr, have); s += have;#endif want -= have; fp->_IO_read_ptr += have; } if (_IO_in_backup (fp)) { _IO_switch_to_main_get_area (fp); continue ; } if (fp->_IO_buf_base && want < (size_t ) (fp->_IO_buf_end - fp->_IO_buf_base)) { if (__underflow (fp) == EOF) break ; continue ; } _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base); count = want; if (fp->_IO_buf_base) { _IO_size_t block_size = fp->_IO_buf_end - fp->_IO_buf_base; if (block_size >= 128 ) count -= want % block_size; } count = _IO_SYSREAD (fp, s, count); if (count <= 0 ) { if (count == 0 ) fp->_flags |= _IO_EOF_SEEN; else fp->_flags |= _IO_ERR_SEEN; break ; } s += count; want -= count; if (fp->_offset != _IO_pos_BAD) _IO_pos_adjust (fp->_offset, count); } } return n - want; }
_IO_doallocbuf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void _IO_doallocbuf (_IO_FILE *fp) { if (fp->_IO_buf_base) return ; if (!(fp->_flags & _IO_UNBUFFERED) || fp->_mode > 0 ) if (_IO_DOALLOCATE (fp) != EOF) return ; _IO_setb (fp, fp->_shortbuf, fp->_shortbuf+1 , 0 ); }
_IO_file_doallocate 主要过程就是malloc一块缓冲区然后调用_IO_setb设定缓冲区相关指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 int _IO_file_doallocate (_IO_FILE *fp) { _IO_size_t size; char *p; struct stat64 st ;#ifndef _LIBC if (__glibc_unlikely (_IO_cleanup_registration_needed != NULL )) (*_IO_cleanup_registration_needed) ();#endif size = _IO_BUFSIZ; if (fp->_fileno >= 0 && __builtin_expect (_IO_SYSSTAT (fp, &st), 0 ) >= 0 ) { if (S_ISCHR (st.st_mode)) { if (#ifdef DEV_TTY_P DEV_TTY_P (&st) ||#endif local_isatty (fp->_fileno)) fp->_flags |= _IO_LINE_BUF; }#if _IO_HAVE_ST_BLKSIZE if (st.st_blksize > 0 ) size = st.st_blksize;#endif } p = malloc (size); if (__glibc_unlikely (p == NULL )) return EOF; _IO_setb (fp, p, p + size, 1 ); return 1 ; }
_IO_setb 设置缓冲区指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void _IO_setb (_IO_FILE *f, char *b, char *eb, int a) { if (f->_IO_buf_base && !(f->_flags & _IO_USER_BUF)) free (f->_IO_buf_base); f->_IO_buf_base = b; f->_IO_buf_end = eb; if (a) f->_flags &= ~_IO_USER_BUF; else f->_flags |= _IO_USER_BUF; }
_IO_switch_to_main_get_area 将缓冲区移至backup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 void _IO_switch_to_main_get_area (_IO_FILE *fp) { char *tmp; fp->_flags &= ~_IO_IN_BACKUP; tmp = fp->_IO_read_end; fp->_IO_read_end = fp->_IO_save_end; fp->_IO_save_end= tmp; tmp = fp->_IO_read_base; fp->_IO_read_base = fp->_IO_save_base; fp->_IO_save_base = tmp; fp->_IO_read_ptr = fp->_IO_read_base; }
__underflow 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 int __underflow (_IO_FILE *fp) {#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T if (_IO_vtable_offset (fp) == 0 && _IO_fwide (fp, -1 ) != -1 ) return EOF;#endif if (fp->_mode == 0 ) _IO_fwide (fp, -1 ); if (_IO_in_put_mode (fp)) if (_IO_switch_to_get_mode (fp) == EOF) return EOF; if (fp->_IO_read_ptr < fp->_IO_read_end) return *(unsigned char *) fp->_IO_read_ptr; if (_IO_in_backup (fp)) { _IO_switch_to_main_get_area (fp); if (fp->_IO_read_ptr < fp->_IO_read_end) return *(unsigned char *) fp->_IO_read_ptr; } if (_IO_have_markers (fp)) { if (save_for_backup (fp, fp->_IO_read_end)) return EOF; } else if (_IO_have_backup (fp)) _IO_free_backup_area (fp); return _IO_UNDERFLOW (fp); }
_IO_new_file_underflow 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 int _IO_new_file_underflow (_IO_FILE *fp) { _IO_ssize_t count;#if 0 if (fp->_flags & _IO_EOF_SEEN) return (EOF);#endif if (fp->_flags & _IO_NO_READS) { fp->_flags |= _IO_ERR_SEEN; __set_errno (EBADF); return EOF; } if (fp->_IO_read_ptr < fp->_IO_read_end) return *(unsigned char *) fp->_IO_read_ptr; if (fp->_IO_buf_base == NULL ) { if (fp->_IO_save_base != NULL ) { free (fp->_IO_save_base); fp->_flags &= ~_IO_IN_BACKUP; } _IO_doallocbuf (fp); } if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED)) {#if 0 _IO_flush_all_linebuffered ();#else _IO_acquire_lock (_IO_stdout); if ((_IO_stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF)) == (_IO_LINKED | _IO_LINE_BUF)) _IO_OVERFLOW (_IO_stdout, EOF); _IO_release_lock (_IO_stdout);#endif } _IO_switch_to_get_mode (fp); 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); if (count <= 0 ) { if (count == 0 ) fp->_flags |= _IO_EOF_SEEN; else fp->_flags |= _IO_ERR_SEEN, count = 0 ; } fp->_IO_read_end += count; if (count == 0 ) { fp->_offset = _IO_pos_BAD; return EOF; } if (fp->_offset != _IO_pos_BAD) _IO_pos_adjust (fp->_offset, count); return *(unsigned char *) fp->_IO_read_ptr; }
其他输入函数 scanf scanf的函数调用栈如下,最终是使用跳转表中的_IO_new_file_underflow实现输入的:
1 2 3 4 5 6 read _IO_new_file_underflow->_IO_doallocbuf->_IO_file_doallocate __IO_default_uflow __uflow __vfscanf_internal __isoc99_scanf
gets 和scanf差不多
1 2 3 4 5 read _IO_new_file_underflow->_IO_doallocbuf->_IO_file_doallocate __IO_default_uflow __uflow gets
fwrite 函数调用流程:
执行fwrite函数实际上执行的是_IO_write函数,_IO_write又调用了_IO_sputn
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 _IO_size_t _IO_fwrite (const void *buf, _IO_size_t size, _IO_size_t count, _IO_FILE *fp) { _IO_size_t request = size * count; _IO_size_t written = 0 ; CHECK_FILE (fp, 0 ); if (request == 0 ) return 0 ; _IO_acquire_lock (fp); if (_IO_vtable_offset (fp) != 0 || _IO_fwide (fp, -1 ) == -1 ) written = _IO_sputn (fp, (const char *) buf, request); _IO_release_lock (fp); if (written == request || written == EOF) return count; else return written / size; }
_IO_sputn其实是调用跳转表中的_IO_file_xsputn(实际上是_IO_new_file_xsputn),步骤如下:
将目标数据拷贝至输出缓冲区
如果缓冲区还有空间则先吧数据拷贝进输出缓冲区
如果还有数据剩余则说明缓冲区未建立或者缓冲区已满,调用_IO_OVERFLOW建立或清空缓冲区
判断数据是否大块,是则先调用new_do_write输出小块数据,然后调用_IO_default_xsputn将剩余数据拷贝进缓冲区1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 _IO_size_t _IO_new_file_xsputn (_IO_FILE *f, const void *data, _IO_size_t n) { const char *s = (const char *) data; _IO_size_t to_do = n; int must_flush = 0 ; _IO_size_t count = 0 ; if (n <= 0 ) return 0 ; if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING)) { count = f->_IO_buf_end - f->_IO_write_ptr; if (count >= n) { const char *p; for (p = s + n; p > s; ) { if (*--p == '\n' ) { count = p - s + 1 ; must_flush = 1 ; break ; } } } } else if (f->_IO_write_end > f->_IO_write_ptr) count = f->_IO_write_end - f->_IO_write_ptr; if (count > 0 ) { if (count > to_do) count = to_do;#ifdef _LIBC f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);#else memcpy (f->_IO_write_ptr, s, count); f->_IO_write_ptr += count;#endif s += count; to_do -= count; } if (to_do + must_flush > 0 ) { _IO_size_t block_size, do_write; if (_IO_OVERFLOW (f, EOF) == EOF) return to_do == 0 ? EOF : n - to_do; block_size = f->_IO_buf_end - f->_IO_buf_base; do_write = to_do - (block_size >= 128 ? to_do % block_size : 0 ); if (do_write) { count = new_do_write (f, s, do_write); to_do -= count; if (count < do_write) return n - to_do; } if (to_do) to_do -= _IO_default_xsputn (f, s+do_write, to_do); } return n - to_do; }
_IO_new_file_overflow _IO_OVERFLOW实际上就是跳转表中的_IO_new_file_overflow
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 int _IO_new_file_overflow (_IO_FILE *f, int ch) { if (f->_flags & _IO_NO_WRITES) { f->_flags |= _IO_ERR_SEEN; __set_errno (EBADF); return EOF; } if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == NULL ) { if (f->_IO_write_base == NULL ) { _IO_doallocbuf (f); _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base); } if (__glibc_unlikely (_IO_in_backup (f))) { size_t nbackup = f->_IO_read_end - f->_IO_read_ptr; _IO_free_backup_area (f); f->_IO_read_base -= MIN (nbackup, f->_IO_read_base - f->_IO_buf_base); f->_IO_read_ptr = f->_IO_read_base; } if (f->_IO_read_ptr == f->_IO_buf_end) f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base; f->_IO_write_ptr = f->_IO_read_ptr; f->_IO_write_base = f->_IO_write_ptr; f->_IO_write_end = f->_IO_buf_end; f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end; f->_flags |= _IO_CURRENTLY_PUTTING; if (f->_mode <= 0 && f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED)) f->_IO_write_end = f->_IO_write_ptr; } if (ch == EOF) return _IO_do_write (f, f->_IO_write_base, f->_IO_write_ptr - f->_IO_write_base); if (f->_IO_write_ptr == f->_IO_buf_end ) if (_IO_do_flush (f) == EOF) return EOF; *f->_IO_write_ptr++ = ch; if ((f->_flags & _IO_UNBUFFERED) || ((f->_flags & _IO_LINE_BUF) && ch == '\n' )) if (_IO_do_write (f, f->_IO_write_base, f->_IO_write_ptr - f->_IO_write_base) == EOF) return EOF; return (unsigned char ) ch; }
_IO_new_do_write _IO_do_write实际上是_IO_new_do_write(宏定义),调用了new_do_write,_IO_file_xsputn后续步骤也调用了这个函数
1 2 3 4 5 6 7 8 int _IO_new_do_write (_IO_FILE *fp, const char *data, _IO_size_t to_do) { return (to_do == 0 || (_IO_size_t) new_do_write (fp, data, to_do) == to_do) ? 0 : EOF; }
new_do_write 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 static _IO_size_tnew_do_write (_IO_FILE *fp, const char *data, _IO_size_t to_do) { _IO_size_t count; if (fp->_flags & _IO_IS_APPENDING) fp->_offset = _IO_pos_BAD; else if (fp->_IO_read_end != fp->_IO_write_base) { _IO_off64_t new_pos = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1 ); if (new_pos == _IO_pos_BAD) return 0 ; fp->_offset = new_pos; } count = _IO_SYSWRITE (fp, data, to_do); if (fp->_cur_column && count) fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1 , data, count) + 1 ; _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base); fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base; fp->_IO_write_end = (fp->_mode <= 0 && (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED)) ? fp->_IO_buf_base : fp->_IO_buf_end); return count; }
_IO_new_file_write _IO_SYSWRITE实际上就是跳转表中的_IO_file_write(_IO_new_file_write),调用系统调用清空缓冲区
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 _IO_ssize_t _IO_new_file_write (_IO_FILE *f, const void *data, _IO_ssize_t n) { _IO_ssize_t to_do = n; while (to_do > 0 ) { _IO_ssize_t count = (__builtin_expect (f->_flags2 & _IO_FLAGS2_NOTCANCEL, 0 ) ? write_not_cancel (f->_fileno, data, to_do) : write (f->_fileno, data, to_do)); if (count < 0 ) { f->_flags |= _IO_ERR_SEEN; break ; } to_do -= count; data = (void *) ((char *) data + count); } n -= to_do; if (f->_offset >= 0 ) f->_offset += n; return n; }
_IO_default_xsputn 调用_IO_OVERFLOW清空缓冲区
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 _IO_size_t _IO_default_xsputn (_IO_FILE *f, const void *data, _IO_size_t n) { const char *s = (char *) data; _IO_size_t more = n; if (more <= 0 ) return 0 ; for (;;) { if (f->_IO_write_ptr < f->_IO_write_end) { _IO_size_t count = f->_IO_write_end - f->_IO_write_ptr; if (count > more) count = more; if (count > 20 ) {#ifdef _LIBC f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);#else memcpy (f->_IO_write_ptr, s, count); f->_IO_write_ptr += count;#endif s += count; } else if (count) { char *p = f->_IO_write_ptr; _IO_ssize_t i; for (i = count; --i >= 0 ; ) *p++ = *s++; f->_IO_write_ptr = p; } more -= count; } if (more == 0 || _IO_OVERFLOW (f, (unsigned char ) *s++) == EOF) break ; more--; } return n - more; }
注意一点 main函数返回的时候_IO_cleanup会调用_IO_flush_all_lockp函数最终调用系统函数write清空缓冲区之后讨论
fclose 函数调用流程图:
fclose实际上是_IO_new_fclose
1 2 3 # define _IO_new_fclose fclose
_IO_new_fclose函数的执行流程如下:
调用_IO_un_link将fp从_IO_list_all单链表中摘除
调用_IO_file_close_it关闭文件并释放缓冲区
调用_IO_FINISH(_IO_new_file_finish)确定_IO_FILE已从链表中取出且缓冲区已释放
如果fp不是标准输入、输出或错误,则释放fp结构体1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 int _IO_new_fclose (_IO_FILE *fp) { int status; CHECK_FILE(fp, EOF);#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1) if (_IO_vtable_offset (fp) != 0 ) return _IO_old_fclose (fp);#endif if (fp->_IO_file_flags & _IO_IS_FILEBUF) _IO_un_link ((struct _IO_FILE_plus *) fp); _IO_acquire_lock (fp); if (fp->_IO_file_flags & _IO_IS_FILEBUF) status = _IO_file_close_it (fp); else status = fp->_flags & _IO_ERR_SEEN ? -1 : 0 ; _IO_release_lock (fp); _IO_FINISH (fp); if (fp->_mode > 0 ) {#if _LIBC struct _IO_codecvt *cc = fp->_codecvt; __libc_lock_lock (__gconv_lock); __gconv_release_step (cc->__cd_in.__cd.__steps); __gconv_release_step (cc->__cd_out.__cd.__steps); __libc_lock_unlock (__gconv_lock);#endif } else { if (_IO_have_backup (fp)) _IO_free_backup_area (fp); } if (fp != _IO_stdin && fp != _IO_stdout && fp != _IO_stderr) { fp->_IO_file_flags = 0 ; free (fp); } return status; }
_IO_un_link 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 void _IO_un_link (struct _IO_FILE_plus *fp) { if (fp->file._flags & _IO_LINKED) { struct _IO_FILE **f ;#ifdef _IO_MTSAFE_IO _IO_cleanup_region_start_noarg (flush_cleanup); _IO_lock_lock (list_all_lock); run_fp = (_IO_FILE *) fp; _IO_flockfile ((_IO_FILE *) fp);#endif if (_IO_list_all == NULL ) ; else if (fp == _IO_list_all) { _IO_list_all = (struct _IO_FILE_plus *) _IO_list_all->file._chain; ++_IO_list_all_stamp; } else for (f = &_IO_list_all->file._chain; *f; f = &(*f)->_chain) if (*f == (_IO_FILE *) fp) { *f = fp->file._chain; ++_IO_list_all_stamp; break ; } fp->file._flags &= ~_IO_LINKED;#ifdef _IO_MTSAFE_IO _IO_funlockfile ((_IO_FILE *) fp); run_fp = NULL ; _IO_lock_unlock (list_all_lock); _IO_cleanup_region_end (0 );#endif } }
_IO_file_close_it 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 int _IO_new_file_close_it (_IO_FILE *fp) { int write_status; if (!_IO_file_is_open (fp)) return EOF; if ((fp->_flags & _IO_NO_WRITES) == 0 && (fp->_flags & _IO_CURRENTLY_PUTTING) != 0 ) write_status = _IO_do_flush (fp); else write_status = 0 ; _IO_unsave_markers (fp); int close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0 ? _IO_SYSCLOSE (fp) : 0 ); #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T if (fp->_mode > 0 ) { if (_IO_have_wbackup (fp)) _IO_free_wbackup_area (fp); _IO_wsetb (fp, NULL , NULL , 0 ); _IO_wsetg (fp, NULL , NULL , NULL ); _IO_wsetp (fp, NULL , NULL ); }#endif _IO_setb (fp, NULL , NULL , 0 ); _IO_setg (fp, NULL , NULL , NULL ); _IO_setp (fp, NULL , NULL ); _IO_un_link ((struct _IO_FILE_plus *) fp); fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS; fp->_fileno = -1 ; fp->_offset = _IO_pos_BAD; return close_status ? close_status : write_status; }
_IO_file_close 直接进行系统调用
1 2 3 4 5 6 7 int _IO_file_close (_IO_FILE *fp) { return close_not_cancel (fp->_fileno); }
_IO_setb 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 void _IO_setb (_IO_FILE *f, char *b, char *eb, int a) { if (f->_IO_buf_base && !(f->_flags & _IO_USER_BUF)) free (f->_IO_buf_base); f->_IO_buf_base = b; f->_IO_buf_end = eb; if (a) f->_flags &= ~_IO_USER_BUF; else f->_flags |= _IO_USER_BUF; }
_IO_new_file_finish 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void _IO_new_file_finish (_IO_FILE *fp, int dummy) { if (_IO_file_is_open (fp)) { _IO_do_flush (fp); if (!(fp->_flags & _IO_DELETE_DONT_CLOSE)) _IO_SYSCLOSE (fp); } _IO_default_finish (fp, 0 ); }
_IO_default_finish 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 void _IO_default_finish (_IO_FILE *fp, int dummy) { struct _IO_marker *mark ; if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF)) { free (fp->_IO_buf_base); fp->_IO_buf_base = fp->_IO_buf_end = NULL ; } for (mark = fp->_markers; mark != NULL ; mark = mark->_next) mark->_sbuf = NULL ; if (fp->_IO_save_base) { free (fp->_IO_save_base); fp->_IO_save_base = NULL ; } _IO_un_link ((struct _IO_FILE_plus *) fp);#ifdef _IO_MTSAFE_IO if (fp->_lock != NULL ) _IO_lock_fini (*fp->_lock);#endif }