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 /* Even if the stream is set to user-locking, we still need to lock
14 * when all (lbf) writing streams are flushed. */
16 #define __MY_STDIO_THREADLOCK(__stream) \
17 __UCLIBC_IO_MUTEX_CONDITIONAL_LOCK((__stream)->__lock, \
18 (_stdio_user_locking != 2))
20 #define __MY_STDIO_THREADUNLOCK(__stream) \
21 __UCLIBC_IO_MUTEX_CONDITIONAL_UNLOCK((__stream)->__lock, \
22 (_stdio_user_locking != 2))
24 #if defined(__UCLIBC_HAS_THREADS__) && defined(__STDIO_BUFFERS)
25 void attribute_hidden
_stdio_openlist_dec_use(void)
27 __STDIO_THREADLOCK_OPENLIST_DEL
;
28 if ((_stdio_openlist_use_count
== 1) && (_stdio_openlist_del_count
> 0)) {
33 /* Grab the openlist add lock since we might change the head of the list. */
34 __STDIO_THREADLOCK_OPENLIST_ADD
;
35 for (stream
= _stdio_openlist
; stream
; stream
= n
) {
36 n
= stream
->__nextopen
;
37 if ((stream
->__modeflags
& (__FLAG_READONLY
|__FLAG_WRITEONLY
|__FLAG_FAILED_FREOPEN
))
38 == (__FLAG_READONLY
|__FLAG_WRITEONLY
)
39 ) { /* The file was closed and should be removed from the list. */
45 __STDIO_STREAM_FREE_FILE(stream
);
50 __STDIO_THREADUNLOCK_OPENLIST_ADD
;
51 _stdio_openlist_del_count
= 0; /* Should be clean now. */
53 --_stdio_openlist_use_count
;
54 __STDIO_THREADUNLOCK_OPENLIST_DEL
;
58 int fflush_unlocked(register FILE *stream
)
60 #ifdef __STDIO_BUFFERS
63 unsigned short bufmask
= __FLAG_LBF
;
66 if ((stream
!= NULL
) && (stream
!= (FILE *) &_stdio_openlist
)) {
67 __STDIO_STREAM_VALIDATE(stream
); /* debugging only */
71 if (stream
== (FILE *) &_stdio_openlist
) { /* Flush all lbf streams. */
76 if (!stream
) { /* Flush all (lbf) writing streams. */
78 __STDIO_OPENLIST_INC_USE
;
80 __STDIO_THREADLOCK_OPENLIST_ADD
;
81 stream
= _stdio_openlist
;
82 __STDIO_THREADUNLOCK_OPENLIST_ADD
;
85 /* We only care about currently writing streams and do not want to
86 * block trying to obtain mutexes on non-writing streams. */
87 if (__STDIO_STREAM_IS_WRITING(stream
)) { /* ONLY IF ATOMIC!!! */
88 __MY_STDIO_THREADLOCK(stream
);
89 /* Need to check again once we have the lock. */
90 if (!(((stream
->__modeflags
| bufmask
)
91 ^ (__FLAG_WRITING
|__FLAG_LBF
)
92 ) & (__FLAG_WRITING
|__MASK_BUFMODE
))
94 if (!__STDIO_COMMIT_WRITE_BUFFER(stream
)) {
95 __STDIO_STREAM_DISABLE_PUTC(stream
);
96 __STDIO_STREAM_CLEAR_WRITING(stream
);
101 __MY_STDIO_THREADUNLOCK(stream
);
103 stream
= stream
->__nextopen
;
106 __STDIO_OPENLIST_DEC_USE
;
108 } else if (__STDIO_STREAM_IS_WRITING(stream
)) {
109 if (!__STDIO_COMMIT_WRITE_BUFFER(stream
)) {
110 __STDIO_STREAM_DISABLE_PUTC(stream
);
111 __STDIO_STREAM_CLEAR_WRITING(stream
);
117 else if (stream
->__modeflags
& (__MASK_READING
|__FLAG_READONLY
)) {
118 /* ANSI/ISO says behavior in this case is undefined but also says you
119 * shouldn't flush a stream you were reading from. As usual, glibc
120 * caters to broken programs and simply ignores this. */
121 __UNDEFINED_OR_NONPORTABLE
;
122 __STDIO_STREAM_SET_ERROR(stream
);
129 if ((stream
!= NULL
) && (stream
!= (FILE *) &_stdio_openlist
)) {
130 __STDIO_STREAM_VALIDATE(stream
); /* debugging only */
136 #else /* __STDIO_BUFFERS --------------------------------------- */
140 #ifdef __STDIO_HAS_OPENLIST
141 && (stream
!= (FILE *) &_stdio_openlist
)
144 __STDIO_STREAM_VALIDATE(stream
); /* debugging only */
149 if (stream
&& (stream
->__modeflags
& (__MASK_READING
|__FLAG_READONLY
))) {
150 /* ANSI/ISO says behavior in this case is undefined but also says you
151 * shouldn't flush a stream you were reading from. As usual, glibc
152 * caters to broken programs and simply ignores this. */
153 __UNDEFINED_OR_NONPORTABLE
;
154 __STDIO_STREAM_SET_ERROR(stream
);
161 #endif /* __STDIO_BUFFERS */
163 libc_hidden_def(fflush_unlocked
)
165 #ifndef __UCLIBC_HAS_THREADS__
166 strong_alias(fflush_unlocked
,fflush
)
167 libc_hidden_def(fflush
)
170 #elif defined __UCLIBC_HAS_THREADS__
172 int fflush(register FILE *stream
)
175 __STDIO_AUTO_THREADLOCK_VAR
;
178 #ifdef __STDIO_HAS_OPENLIST
179 && (stream
!= (FILE *) &_stdio_openlist
)
183 __STDIO_AUTO_THREADLOCK(stream
);
185 retval
= fflush_unlocked(stream
);
187 __STDIO_AUTO_THREADUNLOCK(stream
);
189 retval
= fflush_unlocked(stream
);
194 libc_hidden_def(fflush
)