summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2006-12-06 22:41:21 +0000
committerEric Andersen <andersen@codepoet.org>2006-12-06 22:41:21 +0000
commit99d6c367c4820a072dc4ada51561df17e2093778 (patch)
tree969945da0bce7248de98eefedaeb590f5cfdd85e /libc
parentaeba32a371882d602f6863320880f0c69c824b77 (diff)
stdio update from mjn3
Diffstat (limited to 'libc')
-rw-r--r--libc/stdio/_READ.c2
-rw-r--r--libc/stdio/_WRITE.c2
-rw-r--r--libc/stdio/_fopen.c21
-rw-r--r--libc/stdio/_stdio.c16
-rw-r--r--libc/stdio/_stdio.h74
-rw-r--r--libc/stdio/_vfprintf.c2
-rw-r--r--libc/stdio/fclose.c66
-rw-r--r--libc/stdio/fcloseall.c35
-rw-r--r--libc/stdio/fflush.c110
-rw-r--r--libc/stdio/flockfile.c2
-rw-r--r--libc/stdio/freopen.c15
-rw-r--r--libc/stdio/ftello.c5
-rw-r--r--libc/stdio/ftrylockfile.c2
-rw-r--r--libc/stdio/funlockfile.c2
-rw-r--r--libc/stdio/setvbuf.c4
-rw-r--r--libc/stdio/vdprintf.c4
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_stdio.h48
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;