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;
}
示例#2
0
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;
}