void attribute_hidden _stdio_openlist_dec_use(void) { __STDIO_THREADLOCK_OPENLIST_DEL; if ((_stdio_openlist_use_count == 1) && (_stdio_openlist_del_count > 0)) { FILE *p = NULL; FILE *n; FILE *stream; #ifdef __UCLIBC_MJN3_ONLY__ #warning REMINDER: As an optimization, we could unlock after we move past the head. #endif /* Grab the openlist add lock since we might change the head of the list. */ __STDIO_THREADLOCK_OPENLIST_ADD; for (stream = _stdio_openlist; stream; stream = n) { n = stream->__nextopen; #ifdef __UCLIBC_MJN3_ONLY__ #warning REMINDER: fix for nonatomic #endif if ((stream->__modeflags & (__FLAG_READONLY|__FLAG_WRITEONLY|__FLAG_FAILED_FREOPEN)) == (__FLAG_READONLY|__FLAG_WRITEONLY) ) { /* The file was closed and should be removed from the list. */ if (!p) { _stdio_openlist = n; } else { p->__nextopen = n; } __STDIO_STREAM_FREE_FILE(stream); } else { p = stream; } } __STDIO_THREADUNLOCK_OPENLIST_ADD; _stdio_openlist_del_count = 0; /* Should be clean now. */ } --_stdio_openlist_use_count; __STDIO_THREADUNLOCK_OPENLIST_DEL; }
int fclose(register FILE *stream) { int rv = 0; __STDIO_AUTO_THREADLOCK_VAR; #ifdef __STDIO_HAS_OPENLIST #if !defined(__UCLIBC_HAS_THREADS__) || !defined(__STDIO_BUFFERS) /* First, remove the file from the open file list. */ { FILE *ptr; __STDIO_THREADLOCK_OPENLIST_DEL; __STDIO_THREADLOCK_OPENLIST_ADD; ptr = _stdio_openlist; if ((ptr = _stdio_openlist) == stream) { _stdio_openlist = stream->__nextopen; } else { while (ptr) { if (ptr->__nextopen == stream) { ptr->__nextopen = stream->__nextopen; break; } ptr = ptr->__nextopen; } } __STDIO_THREADUNLOCK_OPENLIST_ADD; __STDIO_THREADUNLOCK_OPENLIST_DEL; } #endif #endif __STDIO_AUTO_THREADLOCK(stream); __STDIO_STREAM_VALIDATE(stream); #ifdef __STDIO_BUFFERS /* Write any pending buffered chars. */ if (__STDIO_STREAM_IS_WRITING(stream)) { rv = fflush_unlocked(stream); } #endif if (__CLOSE(stream) < 0) { /* Must close even if fflush failed. */ rv = EOF; } stream->__filedes = -1; /* We need a way for freopen to know that a file has been closed. * Since a file can't be both readonly and writeonly, that makes * an effective signal. It also has the benefit of disabling * transitions to either reading or writing. */ #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS) /* Before we mark the file as closed, make sure we increment the openlist use count * so it isn't freed under us while still cleaning up. */ __STDIO_OPENLIST_INC_USE; #endif stream->__modeflags &= (__FLAG_FREEBUF|__FLAG_FREEFILE); stream->__modeflags |= (__FLAG_READONLY|__FLAG_WRITEONLY); #ifndef NDEBUG __STDIO_STREAM_RESET_GCS(stream); /* Reinitialize everything (including putc since fflush could fail). */ __STDIO_STREAM_DISABLE_GETC(stream); __STDIO_STREAM_DISABLE_PUTC(stream); __STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream); # ifdef __UCLIBC_HAS_WCHAR__ stream->__ungot_width[0] = 0; # endif # ifdef __STDIO_MBSTATE __INIT_MBSTATE(&(stream->__state)); # endif #endif __STDIO_AUTO_THREADUNLOCK(stream); __STDIO_STREAM_FREE_BUFFER(stream); #ifdef __UCLIBC_MJN3_ONLY__ #warning REMINDER: inefficient - locks and unlocks twice and walks whole list #endif #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS) /* inefficient - locks/unlocks twice and walks whole list */ __STDIO_OPENLIST_INC_DEL_CNT; __STDIO_OPENLIST_DEC_USE; /* This with free the file if necessary. */ #else __STDIO_STREAM_FREE_FILE(stream); #endif return rv; }