diff options
author | Eric Andersen <andersen@codepoet.org> | 2006-12-06 22:41:21 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2006-12-06 22:41:21 +0000 |
commit | 99d6c367c4820a072dc4ada51561df17e2093778 (patch) | |
tree | 969945da0bce7248de98eefedaeb590f5cfdd85e /libc | |
parent | aeba32a371882d602f6863320880f0c69c824b77 (diff) |
stdio update from mjn3
Diffstat (limited to 'libc')
-rw-r--r-- | libc/stdio/_READ.c | 2 | ||||
-rw-r--r-- | libc/stdio/_WRITE.c | 2 | ||||
-rw-r--r-- | libc/stdio/_fopen.c | 21 | ||||
-rw-r--r-- | libc/stdio/_stdio.c | 16 | ||||
-rw-r--r-- | libc/stdio/_stdio.h | 74 | ||||
-rw-r--r-- | libc/stdio/_vfprintf.c | 2 | ||||
-rw-r--r-- | libc/stdio/fclose.c | 66 | ||||
-rw-r--r-- | libc/stdio/fcloseall.c | 35 | ||||
-rw-r--r-- | libc/stdio/fflush.c | 110 | ||||
-rw-r--r-- | libc/stdio/flockfile.c | 2 | ||||
-rw-r--r-- | libc/stdio/freopen.c | 15 | ||||
-rw-r--r-- | libc/stdio/ftello.c | 5 | ||||
-rw-r--r-- | libc/stdio/ftrylockfile.c | 2 | ||||
-rw-r--r-- | libc/stdio/funlockfile.c | 2 | ||||
-rw-r--r-- | libc/stdio/setvbuf.c | 4 | ||||
-rw-r--r-- | libc/stdio/vdprintf.c | 4 | ||||
-rw-r--r-- | libc/sysdeps/linux/common/bits/uClibc_stdio.h | 48 |
17 files changed, 323 insertions, 87 deletions
diff --git a/libc/stdio/_READ.c b/libc/stdio/_READ.c index 0c7febb3c..bafa8dffe 100644 --- a/libc/stdio/_READ.c +++ b/libc/stdio/_READ.c @@ -44,7 +44,7 @@ size_t attribute_hidden __stdio_READ(register FILE *stream, #warning EINTR? #endif /* RETRY: */ - if ((rv = __READ(stream, buf, bufsize)) <= 0) { + if ((rv = __READ(stream, (char *) buf, bufsize)) <= 0) { if (rv == 0) { __STDIO_STREAM_SET_EOF(stream); } else { diff --git a/libc/stdio/_WRITE.c b/libc/stdio/_WRITE.c index 2bd0977fd..83714bd4c 100644 --- a/libc/stdio/_WRITE.c +++ b/libc/stdio/_WRITE.c @@ -49,7 +49,7 @@ size_t attribute_hidden __stdio_WRITE(register FILE *stream, return bufsize; } stodo = (todo <= SSIZE_MAX) ? todo : SSIZE_MAX; - if ((rv = __WRITE(stream, buf, stodo)) >= 0) { + if ((rv = __WRITE(stream, (char *) buf, stodo)) >= 0) { #ifdef __UCLIBC_MJN3_ONLY__ #warning TODO: Make custom stream write return check optional. #endif diff --git a/libc/stdio/_fopen.c b/libc/stdio/_fopen.c index 02051eff9..5243e33f7 100644 --- a/libc/stdio/_fopen.c +++ b/libc/stdio/_fopen.c @@ -198,10 +198,23 @@ FILE attribute_hidden *_stdio_fopen(intptr_t fname_or_mode, #endif #ifdef __STDIO_HAS_OPENLIST - __STDIO_THREADLOCK_OPENLIST; - stream->__nextopen = _stdio_openlist; /* New files are inserted at */ - _stdio_openlist = stream; /* the head of the list. */ - __STDIO_THREADUNLOCK_OPENLIST; +#if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS) + if (!(stream->__modeflags & __FLAG_FREEFILE)) + { + /* An freopen call so the file was never removed from the list. */ + } + else +#endif + { + /* We have to lock the del mutex in case another thread wants to fclose() + * the last file. */ + __STDIO_THREADLOCK_OPENLIST_DEL; + __STDIO_THREADLOCK_OPENLIST_ADD; + stream->__nextopen = _stdio_openlist; /* New files are inserted at */ + _stdio_openlist = stream; /* the head of the list. */ + __STDIO_THREADUNLOCK_OPENLIST_ADD; + __STDIO_THREADUNLOCK_OPENLIST_DEL; + } #endif __STDIO_STREAM_VALIDATE(stream); diff --git a/libc/stdio/_stdio.c b/libc/stdio/_stdio.c index 6c96d8660..c406792d7 100644 --- a/libc/stdio/_stdio.c +++ b/libc/stdio/_stdio.c @@ -154,8 +154,12 @@ FILE *__stdout = _stdio_streams + 1; /* For putchar() macro. */ FILE *_stdio_openlist = _stdio_streams; # ifdef __UCLIBC_HAS_THREADS__ -pthread_mutex_t _stdio_openlist_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; -int _stdio_openlist_delflag = 0; +pthread_mutex_t _stdio_openlist_add_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +#ifdef __STDIO_BUFFERS +pthread_mutex_t _stdio_openlist_del_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +volatile int _stdio_openlist_use_count = 0; +int _stdio_openlist_del_count = 0; +#endif # endif #endif @@ -187,7 +191,11 @@ void attribute_hidden _stdio_term(void) * locked, then I suppose there is a chance that a pointer in the * chain might be corrupt due to a partial store. */ - __stdio_init_mutex(&_stdio_openlist_lock); + __stdio_init_mutex(&_stdio_openlist_add_lock); +#warning check +#ifdef __STDIO_BUFFERS + __stdio_init_mutex(&_stdio_openlist_del_lock); +#endif /* Next we need to worry about the streams themselves. If a stream * is currently locked, then it may be in an invalid state. So we @@ -195,7 +203,7 @@ void attribute_hidden _stdio_term(void) * Then we reinitialize the locks. */ for (ptr = _stdio_openlist ; ptr ; ptr = ptr->__nextopen ) { - if (__STDIO_ALWAYS_THREADTRYLOCK(ptr)) { + if (__STDIO_ALWAYS_THREADTRYLOCK_CANCEL_UNSAFE(ptr)) { /* The stream is already locked, so we don't want to touch it. * However, if we have custom streams, we can't just close it * or leave it locked since a custom stream may be stacked diff --git a/libc/stdio/_stdio.h b/libc/stdio/_stdio.h index 348f5ec5d..6647a6f0e 100644 --- a/libc/stdio/_stdio.h +++ b/libc/stdio/_stdio.h @@ -23,20 +23,76 @@ #ifdef __UCLIBC_HAS_THREADS__ #include <pthread.h> -#define __STDIO_THREADLOCK_OPENLIST \ - __pthread_mutex_lock(&_stdio_openlist_lock) +#define __STDIO_THREADLOCK_OPENLIST_ADD \ + do { \ + struct _pthread_cleanup_buffer __infunc_pthread_cleanup_buffer; \ + _pthread_cleanup_push_defer(&__infunc_pthread_cleanup_buffer, \ + __pthread_mutex_unlock, \ + &_stdio_openlist_add_lock); \ + __pthread_mutex_lock(&_stdio_openlist_add_lock); \ -#define __STDIO_THREADUNLOCK_OPENLIST \ - __pthread_mutex_unlock(&_stdio_openlist_lock) +#define __STDIO_THREADUNLOCK_OPENLIST_ADD \ + _pthread_cleanup_pop_restore(&__infunc_pthread_cleanup_buffer,1); \ + } while (0) -#define __STDIO_THREADTRYLOCK_OPENLIST \ - __pthread_mutex_trylock(&_stdio_openlist_lock) -#else +#ifdef __STDIO_BUFFERS -#define __STDIO_THREADLOCK_OPENLIST ((void)0) -#define __STDIO_THREADUNLOCK_OPENLIST ((void)0) +#define __STDIO_THREADLOCK_OPENLIST_DEL \ + do { \ + struct _pthread_cleanup_buffer __infunc_pthread_cleanup_buffer; \ + _pthread_cleanup_push_defer(&__infunc_pthread_cleanup_buffer, \ + __pthread_mutex_unlock, \ + &_stdio_openlist_del_lock); \ + __pthread_mutex_lock(&_stdio_openlist_del_lock); \ + +#define __STDIO_THREADUNLOCK_OPENLIST_DEL \ + _pthread_cleanup_pop_restore(&__infunc_pthread_cleanup_buffer,1); \ + } while (0) + +#define __STDIO_OPENLIST_INC_USE \ +do { \ + __STDIO_THREADLOCK_OPENLIST_DEL; \ + ++_stdio_openlist_use_count; \ + __STDIO_THREADUNLOCK_OPENLIST_DEL; \ +} while (0) + +extern void _stdio_openlist_dec_use(void); + +#define __STDIO_OPENLIST_DEC_USE \ + _stdio_openlist_dec_use() + +#define __STDIO_OPENLIST_INC_DEL_CNT \ +do { \ + __STDIO_THREADLOCK_OPENLIST_DEL; \ + ++_stdio_openlist_del_count; \ + __STDIO_THREADUNLOCK_OPENLIST_DEL; \ +} while (0) + +#define __STDIO_OPENLIST_DEC_DEL_CNT \ +do { \ + __STDIO_THREADLOCK_OPENLIST_DEL; \ + --_stdio_openlist_del_count; \ + __STDIO_THREADUNLOCK_OPENLIST_DEL; \ +} while (0) + +#endif + +#endif /* __UCLIBC_HAS_THREADS__ */ + +#ifndef __STDIO_THREADLOCK_OPENLIST_ADD +#define __STDIO_THREADLOCK_OPENLIST_ADD ((void)0) +#define __STDIO_THREADUNLOCK_OPENLIST_ADD ((void)0) +#endif +#ifndef __STDIO_THREADLOCK_OPENLIST_DEL +#define __STDIO_THREADLOCK_OPENLIST_DEL ((void)0) +#define __STDIO_THREADUNLOCK_OPENLIST_DEL ((void)0) +/* #define __STDIO_OPENLIST_USE_CNT() (0) */ +#define __STDIO_OPENLIST_INC_USE ((void)0) +#define __STDIO_OPENLIST_DEC_USE ((void)0) +#define __STDIO_OPENLIST_INC_DEL_CNT ((void)0) +#define __STDIO_OPENLIST_DEC_DEL_CNT ((void)0) #endif #define __UNDEFINED_OR_NONPORTABLE ((void)0) diff --git a/libc/stdio/_vfprintf.c b/libc/stdio/_vfprintf.c index f4bbb1c1e..3a5a0e92d 100644 --- a/libc/stdio/_vfprintf.c +++ b/libc/stdio/_vfprintf.c @@ -1234,7 +1234,7 @@ static size_t _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf } len = buflen; } - return r + OUTNSTR(fp, (const char *) buf, len); + return r + OUTNSTR(fp, (const unsigned char *) buf, len); } #endif /* __STDIO_PRINTF_FLOAT */ diff --git a/libc/stdio/fclose.c b/libc/stdio/fclose.c index 843599c0f..f3e181c8a 100644 --- a/libc/stdio/fclose.c +++ b/libc/stdio/fclose.c @@ -16,30 +16,36 @@ int fclose(register FILE *stream) int rv = 0; __STDIO_AUTO_THREADLOCK_VAR; - /* First, remove the file from the open file list. */ -#ifdef __STDIO_HAS_OPENLIST - { - register FILE *ptr; - - __STDIO_THREADLOCK_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; - - if (!ptr) { /* Did not find stream in the open file list! */ - return EOF; - } - } +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: dead code... but may want to simply check and not remove #endif +/* #ifdef __STDIO_HAS_OPENLIST */ +/* #if !defined(__UCLIBC_HAS_THREADS__) || !defined(__STDIO_BUFFERS) */ +/* /\* First, remove the file from the open file list. *\/ */ +/* { */ +/* register FILE *ptr; */ + +/* __STDIO_THREADLOCK_OPENLIST; */ +/* if ((ptr = _stdio_openlist) == stream) { */ +/* #warning does a mod!!! */ +/* _stdio_openlist = stream->__nextopen; */ +/* } else { */ +/* while (ptr) { */ +/* if (ptr->__nextopen == stream) { */ +/* ptr->__nextopen = stream->__nextopen; */ +/* break; */ +/* } */ +/* ptr = ptr->__nextopen; */ +/* } */ +/* } */ +/* __STDIO_THREADUNLOCK_OPENLIST; */ + +/* if (!ptr) { /\* Did not find stream in the open file list! *\/ */ +/* return EOF; */ +/* } */ +/* } */ +/* #endif */ +/* #endif */ __STDIO_AUTO_THREADLOCK(stream); @@ -62,6 +68,11 @@ int fclose(register FILE *stream) * 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); @@ -84,7 +95,16 @@ int fclose(register FILE *stream) __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; } diff --git a/libc/stdio/fcloseall.c b/libc/stdio/fcloseall.c index 7d2422562..d3cbb67f8 100644 --- a/libc/stdio/fcloseall.c +++ b/libc/stdio/fcloseall.c @@ -24,14 +24,39 @@ int fcloseall (void) #ifdef __STDIO_HAS_OPENLIST int retval = 0; + FILE *f; - __STDIO_THREADLOCK_OPENLIST; - while (_stdio_openlist) { - if (fclose(_stdio_openlist)) { - retval = EOF; + __STDIO_OPENLIST_INC_USE; + +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: should probably have a get_head() operation +#endif + __STDIO_THREADLOCK_OPENLIST_ADD; + f = _stdio_openlist; + __STDIO_THREADUNLOCK_OPENLIST_ADD; + + while (f) { +#ifdef __UCLIBC_MJN3_ONLY__ +#warning REMINDER: should probably have a get_next() operation +#endif + FILE *n = f->__nextopen; + __STDIO_AUTO_THREADLOCK_VAR; + + __STDIO_AUTO_THREADLOCK(f); + /* Only call fclose on the stream if it is not already closed. */ + if ((f->__modeflags & (__FLAG_READONLY|__FLAG_WRITEONLY)) + != (__FLAG_READONLY|__FLAG_WRITEONLY) + ) { + if (fclose(f)) { + retval = EOF; + } } + __STDIO_AUTO_THREADUNLOCK(f); + + f = n; } - __STDIO_THREADUNLOCK_OPENLIST; + + __STDIO_OPENLIST_DEC_USE; return retval; diff --git a/libc/stdio/fflush.c b/libc/stdio/fflush.c index c0f58d8af..84e2a26cc 100644 --- a/libc/stdio/fflush.c +++ b/libc/stdio/fflush.c @@ -18,20 +18,68 @@ libc_hidden_proto(fflush_unlocked) #ifdef __UCLIBC_HAS_THREADS__ /* Even if the stream is set to user-locking, we still need to lock * when all (lbf) writing streams are flushed. */ -#define MY_STDIO_THREADLOCK(STREAM) \ - if (_stdio_user_locking != 2) { \ - __STDIO_ALWAYS_THREADLOCK(STREAM); \ - } -#define MY_STDIO_THREADUNLOCK(STREAM) \ +#define __MY_STDIO_THREADLOCK(__stream) \ + do { \ + struct _pthread_cleanup_buffer __infunc_pthread_cleanup_buffer; \ if (_stdio_user_locking != 2) { \ - __STDIO_ALWAYS_THREADUNLOCK(STREAM); \ - } + _pthread_cleanup_push_defer(&__infunc_pthread_cleanup_buffer, \ + __pthread_mutex_unlock, \ + &(__stream)->__lock); \ + __pthread_mutex_lock(&(__stream)->__lock); \ + } \ + ((void)0) + +#define __MY_STDIO_THREADUNLOCK(__stream) \ + if (_stdio_user_locking != 2) { \ + _pthread_cleanup_pop_restore(&__infunc_pthread_cleanup_buffer,1);\ + } \ + } while (0) + #else -#define MY_STDIO_THREADLOCK(STREAM) ((void)0) -#define MY_STDIO_THREADUNLOCK(STREAM) ((void)0) +#define __MY_STDIO_THREADLOCK(STREAM) ((void)0) +#define __MY_STDIO_THREADUNLOCK(STREAM) ((void)0) #endif +#if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS) +void _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; +} +#endif int fflush_unlocked(register FILE *stream) { @@ -55,23 +103,39 @@ int fflush_unlocked(register FILE *stream) } if (!stream) { /* Flush all (lbf) writing streams. */ - __STDIO_THREADLOCK_OPENLIST; - for (stream = _stdio_openlist; stream ; stream = stream->__nextopen) { - MY_STDIO_THREADLOCK(stream); - if (!(((stream->__modeflags | bufmask) - ^ (__FLAG_WRITING|__FLAG_LBF) - ) & (__FLAG_WRITING|__MASK_BUFMODE)) - ) { - if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) { - __STDIO_STREAM_DISABLE_PUTC(stream); - __STDIO_STREAM_CLEAR_WRITING(stream); - } else { - retval = EOF; + + __STDIO_OPENLIST_INC_USE; + + __STDIO_THREADLOCK_OPENLIST_ADD; + stream = _stdio_openlist; + __STDIO_THREADUNLOCK_OPENLIST_ADD; + + while(stream) { + /* We only care about currently writing streams and do not want to + * block trying to obtain mutexes on non-writing streams. */ +#warning fix for nonatomic +#warning unnecessary check if no threads + if (__STDIO_STREAM_IS_WRITING(stream)) { /* ONLY IF ATOMIC!!! */ + __MY_STDIO_THREADLOCK(stream); + /* Need to check again once we have the lock. */ + if (!(((stream->__modeflags | bufmask) + ^ (__FLAG_WRITING|__FLAG_LBF) + ) & (__FLAG_WRITING|__MASK_BUFMODE)) + ) { + if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) { + __STDIO_STREAM_DISABLE_PUTC(stream); + __STDIO_STREAM_CLEAR_WRITING(stream); + } else { + retval = EOF; + } } + __MY_STDIO_THREADUNLOCK(stream); } - MY_STDIO_THREADUNLOCK(stream); + stream = stream->__nextopen; } - __STDIO_THREADUNLOCK_OPENLIST; + + __STDIO_OPENLIST_DEC_USE; + } else if (__STDIO_STREAM_IS_WRITING(stream)) { if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) { __STDIO_STREAM_DISABLE_PUTC(stream); diff --git a/libc/stdio/flockfile.c b/libc/stdio/flockfile.c index 0dcc7c266..3fad7118d 100644 --- a/libc/stdio/flockfile.c +++ b/libc/stdio/flockfile.c @@ -11,6 +11,6 @@ void flockfile(FILE *stream) { __STDIO_STREAM_VALIDATE(stream); - __STDIO_ALWAYS_THREADLOCK(stream); + __STDIO_ALWAYS_THREADLOCK_CANCEL_UNSAFE(stream); } diff --git a/libc/stdio/freopen.c b/libc/stdio/freopen.c index 7314807d3..942a67991 100644 --- a/libc/stdio/freopen.c +++ b/libc/stdio/freopen.c @@ -37,6 +37,8 @@ FILE *freopen(const char * __restrict filename, const char * __restrict mode, __STDIO_STREAM_VALIDATE(stream); + __STDIO_OPENLIST_INC_USE; /* Do not remove the file from the list. */ + /* First, flush and close, but don't deallocate, the stream. */ /* This also removes the stream for the open file list. */ dynmode = (stream->__modeflags & (__FLAG_FREEBUF|__FLAG_FREEFILE)); @@ -48,13 +50,26 @@ FILE *freopen(const char * __restrict filename, const char * __restrict mode, != (__FLAG_READONLY|__FLAG_WRITEONLY) ) { fclose(stream); /* Failures are ignored. */ + /* NOTE: fclose always does __STDIO_OPENLIST_INC_DEL_CNT. But we don't + * want to remove this FILE from the open list, even if the freopen fails. + * Consider the case of a failed freopen() on stdin. You probably still + * want to be able to call freopen() again. Similarly for other "malloc'd" + * streams. */ + __STDIO_OPENLIST_DEC_DEL_CNT; } fp = _stdio_fopen(((intptr_t) filename), mode, stream, FILEDES_ARG); + if (!fp) { + /* Don't remove stream from the open file list and (potentially) free it. + * See _stdio_openlist_dec_use() in fflush.c. */ + stream->__modeflags = __FLAG_READONLY|__FLAG_WRITEONLY|__FLAG_FAILED_FREOPEN; + } /* Reset the allocation flags. */ stream->__modeflags |= dynmode; + __STDIO_OPENLIST_DEC_USE; + __STDIO_AUTO_THREADUNLOCK(stream); return fp; diff --git a/libc/stdio/ftello.c b/libc/stdio/ftello.c index 4445471a4..bae1d877c 100644 --- a/libc/stdio/ftello.c +++ b/libc/stdio/ftello.c @@ -39,7 +39,10 @@ OFFSET_TYPE FTELL(register FILE *stream) __STDIO_STREAM_VALIDATE(stream); - if ((__SEEK(stream, &pos, SEEK_CUR) < 0) + if ((__SEEK(stream, &pos, + ((__STDIO_STREAM_IS_WRITING(stream) + && (stream->__modeflags & __FLAG_APPEND)) + ? SEEK_END : SEEK_CUR)) < 0) || (__stdio_adjust_position(stream, &pos) < 0)) { pos = -1; } diff --git a/libc/stdio/ftrylockfile.c b/libc/stdio/ftrylockfile.c index d85b8ff59..0d2e156af 100644 --- a/libc/stdio/ftrylockfile.c +++ b/libc/stdio/ftrylockfile.c @@ -15,5 +15,5 @@ int ftrylockfile(FILE *stream) { __STDIO_STREAM_VALIDATE(stream); - return __STDIO_ALWAYS_THREADTRYLOCK(stream); + return __STDIO_ALWAYS_THREADTRYLOCK_CANCEL_UNSAFE(stream); } diff --git a/libc/stdio/funlockfile.c b/libc/stdio/funlockfile.c index 048c093d5..2ddf09797 100644 --- a/libc/stdio/funlockfile.c +++ b/libc/stdio/funlockfile.c @@ -11,5 +11,5 @@ void funlockfile(FILE *stream) { __STDIO_STREAM_VALIDATE(stream); - __STDIO_ALWAYS_THREADUNLOCK(stream); + __STDIO_ALWAYS_THREADUNLOCK_CANCEL_UNSAFE(stream); } diff --git a/libc/stdio/setvbuf.c b/libc/stdio/setvbuf.c index c1566504a..6dbb532db 100644 --- a/libc/stdio/setvbuf.c +++ b/libc/stdio/setvbuf.c @@ -76,8 +76,8 @@ int setvbuf(register FILE * __restrict stream, register char * __restrict buf, } stream->__modeflags |= alloc_flag; - stream->__bufstart = buf; - stream->__bufend = buf + size; + stream->__bufstart = (unsigned char *) buf; + stream->__bufend = (unsigned char *) buf + size; __STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream); __STDIO_STREAM_DISABLE_GETC(stream); __STDIO_STREAM_DISABLE_PUTC(stream); diff --git a/libc/stdio/vdprintf.c b/libc/stdio/vdprintf.c index b26a925bc..0c29eb109 100644 --- a/libc/stdio/vdprintf.c +++ b/libc/stdio/vdprintf.c @@ -22,8 +22,8 @@ int vdprintf(int filedes, const char * __restrict format, va_list arg) #ifdef __STDIO_BUFFERS char buf[64]; /* TODO: provide _optional_ buffering? */ - f.__bufend = buf + sizeof(buf); - f.__bufstart = buf; + f.__bufend = (unsigned char *) buf + sizeof(buf); + f.__bufstart = (unsigned char *) buf; __STDIO_STREAM_DISABLE_GETC(&f); __STDIO_STREAM_DISABLE_PUTC(&f); __STDIO_STREAM_INIT_BUFREAD_BUFPOS(&f); diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h b/libc/sysdeps/linux/common/bits/uClibc_stdio.h index 5b6b35496..bd584692e 100644 --- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h +++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h @@ -148,24 +148,47 @@ #define __STDIO_AUTO_THREADLOCK_VAR int __infunc_user_locking #define __STDIO_AUTO_THREADLOCK(__stream) \ + do { \ + struct _pthread_cleanup_buffer __infunc_pthread_cleanup_buffer; \ if ((__infunc_user_locking = (__stream)->__user_locking) == 0) { \ + _pthread_cleanup_push_defer(&__infunc_pthread_cleanup_buffer, \ + __pthread_mutex_unlock, \ + &(__stream)->__lock); \ __pthread_mutex_lock(&(__stream)->__lock); \ - } + } \ + ((void)0) #define __STDIO_AUTO_THREADUNLOCK(__stream) \ if (__infunc_user_locking == 0) { \ - __pthread_mutex_unlock(&(__stream)->__lock); \ - } + _pthread_cleanup_pop_restore(&__infunc_pthread_cleanup_buffer,1);\ + } \ + } while (0) #define __STDIO_SET_USER_LOCKING(__stream) ((__stream)->__user_locking = 1) #define __STDIO_ALWAYS_THREADLOCK(__stream) \ + do { \ + struct _pthread_cleanup_buffer __infunc_pthread_cleanup_buffer; \ + _pthread_cleanup_push_defer(&__infunc_pthread_cleanup_buffer, \ + __pthread_mutex_unlock, \ + &(__stream)->__lock); \ + __pthread_mutex_lock(&(__stream)->__lock); \ + ((void)0) + +/* #define __STDIO_ALWAYS_THREADTRYLOCK(__stream) \ */ +/* __pthread_mutex_trylock(&(__stream)->__lock) */ + +#define __STDIO_ALWAYS_THREADUNLOCK(__stream) \ + _pthread_cleanup_pop_restore(&__infunc_pthread_cleanup_buffer,1); \ + } while (0) + +#define __STDIO_ALWAYS_THREADLOCK_CANCEL_UNSAFE(__stream) \ __pthread_mutex_lock(&(__stream)->__lock) -#define __STDIO_ALWAYS_THREADTRYLOCK(__stream) \ +#define __STDIO_ALWAYS_THREADTRYLOCK_CANCEL_UNSAFE(__stream) \ __pthread_mutex_trylock(&(__stream)->__lock) -#define __STDIO_ALWAYS_THREADUNLOCK(__stream) \ +#define __STDIO_ALWAYS_THREADUNLOCK_CANCEL_UNSAFE(__stream) \ __pthread_mutex_unlock(&(__stream)->__lock) #else /* __UCLIBC_HAS_THREADS__ */ @@ -178,9 +201,13 @@ #define __STDIO_SET_USER_LOCKING(__stream) ((void)0) #define __STDIO_ALWAYS_THREADLOCK(__stream) ((void)0) -#define __STDIO_ALWAYS_THREADTRYLOCK(__stream) (0) /* Always succeed. */ +/* #define __STDIO_ALWAYS_THREADTRYLOCK(__stream) (0) /\* Always succeed. *\/ */ #define __STDIO_ALWAYS_THREADUNLOCK(__stream) ((void)0) +#define __STDIO_ALWAYS_THREADLOCK_CANCEL_UNSAFE(__stream) ((void)0) +#define __STDIO_ALWAYS_THREADTRYLOCK_CANCEL_UNSAFE(__stream) (0) /* Ok? */ +#define __STDIO_ALWAYS_THREADUNLOCK_CANCEL_UNSAFE(__stream) ((void)0) + #endif /* __UCLIBC_HAS_THREADS__ */ /**********************************************************************/ @@ -343,6 +370,7 @@ struct __STDIO_FILE_STRUCT { #define __FLAG_FREEFILE 0x2000U #define __FLAG_FREEBUF 0x4000U #define __FLAG_LARGEFILE 0x8000U /* fixed! == 0_LARGEFILE for linux */ +#define __FLAG_FAILED_FREOPEN __FLAG_LARGEFILE /* Note: In no-buffer mode, it would be possible to pack the necessary * flags into one byte. Since we wouldn't be buffering and there would @@ -371,8 +399,12 @@ extern void _stdio_term(void) attribute_hidden; extern struct __STDIO_FILE_STRUCT *_stdio_openlist; #ifdef __UCLIBC_HAS_THREADS__ -extern pthread_mutex_t _stdio_openlist_lock; -extern int _stdio_openlist_delflag; +extern pthread_mutex_t _stdio_openlist_add_lock; +#ifdef __STDIO_BUFFERS +extern pthread_mutex_t _stdio_openlist_del_lock; +extern volatile int _stdio_openlist_use_count; /* _stdio_openlist_del_lock */ +extern int _stdio_openlist_del_count; /* _stdio_openlist_del_lock */ +#endif extern int _stdio_user_locking; /* #ifdef _LIBC */ extern void __stdio_init_mutex(pthread_mutex_t *m) attribute_hidden; |