summaryrefslogtreecommitdiff
path: root/libc/stdio/fflush.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/stdio/fflush.c')
-rw-r--r--libc/stdio/fflush.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/libc/stdio/fflush.c b/libc/stdio/fflush.c
new file mode 100644
index 000000000..6baa0ec82
--- /dev/null
+++ b/libc/stdio/fflush.c
@@ -0,0 +1,161 @@
+/* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
+ *
+ * GNU Library General Public License (LGPL) version 2 or later.
+ *
+ * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
+ */
+
+#include "_stdio.h"
+
+extern int __fflush_unlocked(register FILE *stream);
+
+#ifdef __DO_UNLOCKED
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning WISHLIST: Add option to test for undefined behavior of fflush.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+weak_alias(__fflush_unlocked,fflush_unlocked);
+#ifndef __UCLIBC_HAS_THREADS__
+weak_alias(__fflush_unlocked,fflush);
+#endif
+
+#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) \
+ if (_stdio_user_locking != 2) { \
+ __STDIO_ALWAYS_THREADUNLOCK(STREAM); \
+ }
+#else
+#define MY_STDIO_THREADLOCK(STREAM) ((void)0)
+#define MY_STDIO_THREADUNLOCK(STREAM) ((void)0)
+#endif
+
+
+int __fflush_unlocked(register FILE *stream)
+{
+#ifdef __STDIO_BUFFERS
+
+ int retval = 0;
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: should probably define a modeflags type
+#endif
+ unsigned short bufmask = __FLAG_LBF;
+
+#ifndef NDEBUG
+ if ((stream != NULL) && (stream != (FILE *) &_stdio_openlist)) {
+ __STDIO_STREAM_VALIDATE(stream); /* debugging only */
+ }
+#endif
+
+ if (stream == (FILE *) &_stdio_openlist) { /* Flush all lbf streams. */
+ stream = NULL;
+ bufmask = 0;
+ }
+
+ 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;
+ }
+ }
+ MY_STDIO_THREADUNLOCK(stream);
+ }
+ __STDIO_THREADUNLOCK_OPENLIST;
+ } else if (__STDIO_STREAM_IS_WRITING(stream)) {
+ if (!__STDIO_COMMIT_WRITE_BUFFER(stream)) {
+ __STDIO_STREAM_DISABLE_PUTC(stream);
+ __STDIO_STREAM_CLEAR_WRITING(stream);
+ } else {
+ retval = EOF;
+ }
+ }
+#if 0
+ else if (stream->__modeflags & (__MASK_READING|__FLAG_READONLY)) {
+ /* ANSI/ISO says behavior in this case is undefined but also says you
+ * shouldn't flush a stream you were reading from. As usual, glibc
+ * caters to broken programs and simply ignores this. */
+ __UNDEFINED_OR_NONPORTABLE;
+ __STDIO_STREAM_SET_ERROR(stream);
+ __set_errno(EBADF);
+ retval = EOF;
+ }
+#endif
+
+#ifndef NDEBUG
+ if ((stream != NULL) && (stream != (FILE *) &_stdio_openlist)) {
+ __STDIO_STREAM_VALIDATE(stream); /* debugging only */
+ }
+#endif
+
+ return retval;
+
+#else /* __STDIO_BUFFERS --------------------------------------- */
+
+#ifndef NDEBUG
+ if ((stream != NULL)
+#ifdef __STDIO_HAS_OPENLIST
+ && (stream != (FILE *) &_stdio_openlist)
+#endif
+ ) {
+ __STDIO_STREAM_VALIDATE(stream); /* debugging only */
+ }
+#endif
+
+#if 0
+ if (stream && (stream->__modeflags & (__MASK_READING|__FLAG_READONLY))) {
+ /* ANSI/ISO says behavior in this case is undefined but also says you
+ * shouldn't flush a stream you were reading from. As usual, glibc
+ * caters to broken programs and simply ignores this. */
+ __UNDEFINED_OR_NONPORTABLE;
+ __STDIO_STREAM_SET_ERROR(stream);
+ __set_errno(EBADF);
+ return EOF;
+ }
+#endif
+
+ return 0;
+#endif /* __STDIO_BUFFERS */
+}
+
+#elif defined __UCLIBC_HAS_THREADS__
+
+int fflush(register FILE *stream)
+{
+ int retval;
+ __STDIO_AUTO_THREADLOCK_VAR;
+
+ if (stream
+#ifdef __STDIO_HAS_OPENLIST
+ && (stream != (FILE *) &_stdio_openlist)
+#endif
+ ) {
+
+ __STDIO_AUTO_THREADLOCK(stream);
+
+ retval = __fflush_unlocked(stream);
+
+ __STDIO_AUTO_THREADUNLOCK(stream);
+ } else {
+ retval = __fflush_unlocked(stream);
+ }
+
+ return retval;
+}
+
+#endif