1 /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
3 * GNU Library General Public License (LGPL) version 2 or later.
5 * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
13 #ifdef __UCLIBC_MJN3_ONLY__
14 #warning WISHLIST: Add option to test for undefined behavior of fflush.
15 #endif /* __UCLIBC_MJN3_ONLY__ */
17 /* Even if the stream is set to user-locking, we still need to lock
18 * when all (lbf) writing streams are flushed. */
20 #define __MY_STDIO_THREADLOCK(__stream) \
21 __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK((__stream)->__lock, \
22 (_stdio_user_locking != 2))
24 #define __MY_STDIO_THREADUNLOCK(__stream) \
25 __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK((__stream)->__lock, \
26 (_stdio_user_locking != 2))
28 #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS)
29 void attribute_hidden
_stdio_openlist_dec_use(void)
31 __STDIO_THREADLOCK_OPENLIST_DEL
;
32 if ((_stdio_openlist_use_count
== 1) && (_stdio_openlist_del_count
> 0)) {
37 #ifdef __UCLIBC_MJN3_ONLY__
38 #warning REMINDER: As an optimization, we could unlock after we move past the head.
40 /* Grab the openlist add lock since we might change the head of the list. */
41 __STDIO_THREADLOCK_OPENLIST_ADD
;
42 for (stream
= _stdio_openlist
; stream
; stream
= n
) {
43 n
= stream
->__nextopen
;
44 #ifdef __UCLIBC_MJN3_ONLY__
45 #warning REMINDER: fix for nonatomic
47 if ((stream
->__modeflags
& (__FLAG_READONLY
|__FLAG_WRITEONLY
|__FLAG_FAILED_FREOPEN
))
48 == (__FLAG_READONLY
|__FLAG_WRITEONLY
)
49 ) { /* The file was closed and should be removed from the list. */
55 __STDIO_STREAM_FREE_FILE(stream
);
60 __STDIO_THREADUNLOCK_OPENLIST_ADD
;
61 _stdio_openlist_del_count
= 0; /* Should be clean now. */
63 --_stdio_openlist_use_count
;
64 __STDIO_THREADUNLOCK_OPENLIST_DEL
;
68 int fflush_unlocked(register FILE *stream
)
70 #ifdef __STDIO_BUFFERS
73 #ifdef __UCLIBC_MJN3_ONLY__
74 #warning REMINDER: should probably define a modeflags type
76 unsigned short bufmask
= __FLAG_LBF
;
79 if ((stream
!= NULL
) && (stream
!= (FILE *) &_stdio_openlist
)) {
80 __STDIO_STREAM_VALIDATE(stream
); /* debugging only */
84 if (stream
== (FILE *) &_stdio_openlist
) { /* Flush all lbf streams. */
89 if (!stream
) { /* Flush all (lbf) writing streams. */
91 __STDIO_OPENLIST_INC_USE
;
93 __STDIO_THREADLOCK_OPENLIST_ADD
;
94 stream
= _stdio_openlist
;
95 __STDIO_THREADUNLOCK_OPENLIST_ADD
;
98 /* We only care about currently writing streams and do not want to
99 * block trying to obtain mutexes on non-writing streams. */
100 #warning fix for nonatomic
101 #warning unnecessary check if no threads
102 if (__STDIO_STREAM_IS_WRITING(stream
)) { /* ONLY IF ATOMIC!!! */
103 __MY_STDIO_THREADLOCK(stream
);
104 /* Need to check again once we have the lock. */
105 if (!(((stream
->__modeflags
| bufmask
)
106 ^ (__FLAG_WRITING
|__FLAG_LBF
)
107 ) & (__FLAG_WRITING
|__MASK_BUFMODE
))
109 if (!__STDIO_COMMIT_WRITE_BUFFER(stream
)) {
110 __STDIO_STREAM_DISABLE_PUTC(stream
);
111 __STDIO_STREAM_CLEAR_WRITING(stream
);
116 __MY_STDIO_THREADUNLOCK(stream
);
118 stream
= stream
->__nextopen
;
121 __STDIO_OPENLIST_DEC_USE
;
123 } else if (__STDIO_STREAM_IS_WRITING(stream
)) {
124 if (!__STDIO_COMMIT_WRITE_BUFFER(stream
)) {
125 __STDIO_STREAM_DISABLE_PUTC(stream
);
126 __STDIO_STREAM_CLEAR_WRITING(stream
);
132 else if (stream
->__modeflags
& (__MASK_READING
|__FLAG_READONLY
)) {
133 /* ANSI/ISO says behavior in this case is undefined but also says you
134 * shouldn't flush a stream you were reading from. As usual, glibc
135 * caters to broken programs and simply ignores this. */
136 __UNDEFINED_OR_NONPORTABLE
;
137 __STDIO_STREAM_SET_ERROR(stream
);
144 if ((stream
!= NULL
) && (stream
!= (FILE *) &_stdio_openlist
)) {
145 __STDIO_STREAM_VALIDATE(stream
); /* debugging only */
151 #else /* __STDIO_BUFFERS --------------------------------------- */
155 #ifdef __STDIO_HAS_OPENLIST
156 && (stream
!= (FILE *) &_stdio_openlist
)
159 __STDIO_STREAM_VALIDATE(stream
); /* debugging only */
164 if (stream
&& (stream
->__modeflags
& (__MASK_READING
|__FLAG_READONLY
))) {
165 /* ANSI/ISO says behavior in this case is undefined but also says you
166 * shouldn't flush a stream you were reading from. As usual, glibc
167 * caters to broken programs and simply ignores this. */
168 __UNDEFINED_OR_NONPORTABLE
;
169 __STDIO_STREAM_SET_ERROR(stream
);
176 #endif /* __STDIO_BUFFERS */
178 libc_hidden_def(fflush_unlocked
)
180 #ifndef __UCLIBC_HAS_THREADS__
181 strong_alias(fflush_unlocked
,fflush
)
182 libc_hidden_def(fflush
)
185 #elif defined __UCLIBC_HAS_THREADS__
187 int fflush(register FILE *stream
)
190 __STDIO_AUTO_THREADLOCK_VAR
;
193 #ifdef __STDIO_HAS_OPENLIST
194 && (stream
!= (FILE *) &_stdio_openlist
)
198 __STDIO_AUTO_THREADLOCK(stream
);
200 retval
= fflush_unlocked(stream
);
202 __STDIO_AUTO_THREADUNLOCK(stream
);
204 retval
= fflush_unlocked(stream
);
209 libc_hidden_def(fflush
)