ReactOS 0.4.16-dev-822-gbcedb53
fflush.cpp
Go to the documentation of this file.
1//
2// fflush.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines fflush() and related functions, which flush stdio streams.
7//
10
11
12
13static bool __cdecl is_stream_allocated(long const stream_flags) throw()
14{
15 return (stream_flags & _IOALLOCATED) != 0;
16}
17
18static bool __cdecl is_stream_flushable(long const stream_flags) throw()
19{
20 if ((stream_flags & (_IOREAD | _IOWRITE)) != _IOWRITE)
21 {
22 return false;
23 }
24
25 if ((stream_flags & (_IOBUFFER_CRT | _IOBUFFER_USER)) == 0)
26 {
27 return false;
28 }
29
30 return true;
31}
32
33static bool __cdecl is_stream_flushable_or_commitable(long const stream_flags) throw()
34{
35 if (is_stream_flushable(stream_flags))
36 {
37 return true;
38 }
39
40 if (stream_flags & _IOCOMMIT)
41 {
42 return true;
43 }
44
45 return false;
46}
47
48// Returns true if the common_flush_all function should attempt to flush the
49// stream; otherwise returns false. This function returns false for streams
50// that are not in use (not allocated) and for streams for which the flush
51// operation will be a no-op.
52//
53// In the case where this function determines that the flush would be a no-op,
54// it increments the flushed_stream_count. This allows common_flush_all to
55// keep track of the number of streams that it would have flushed.
58 _Inout_ int* const flushed_stream_count
59 ) throw()
60{
61 if (!stream.valid())
62 {
63 return false;
64 }
65
66 long const stream_flags = stream.get_flags();
67 if (!is_stream_allocated(stream_flags))
68 {
69 return false;
70 }
71
72 if (!is_stream_flushable_or_commitable(stream_flags))
73 {
74 ++*flushed_stream_count;
75 return false;
76 }
77
78 return true;
79}
80
81
82
83// Internal implementation of the "flush all" functionality. If the
84// flush_read_mode_streams argument is false, only write mode streams are
85// flushed and the return value is zero on success, EOF on failure.
86//
87// If the flush_read_mode_streams argument is true, this function flushes
88// all streams regardless of mode and returns the number of streams that it
89// flushed.
90//
91// Note that in both cases, if we can determine that a call to fflush for a
92// particular stream would be a no-op, then we will not call fflush for that
93// stream. This allows us to avoid acquiring the stream lock unnecessarily,
94// which can help to avoid deadlock-like lock contention.
95//
96// Notably, by doing this, we can avoid attempting to acquire the stream lock
97// for most read mode streams. Attempting to acquire the stream lock for a
98// read mode stream can be problematic beause another thread may hold the lock
99// and be blocked on an I/O operation (e.g., a call to fread on stdin may block
100// until the user types input into the console).
101static int __cdecl common_flush_all(bool const flush_read_mode_streams) throw()
102{
103 int count = 0;
104 int error = 0;
105
106 __acrt_lock_and_call(__acrt_stdio_index_lock, [&]
107 {
110
111 for (__crt_stdio_stream_data** it = first_file; it != last_file; ++it)
112 {
113 __crt_stdio_stream const stream(*it);
114
115 // Before we acquire the stream lock, check to see if flushing the
116 // stream would be a no-op. If it would be, then skip this stream.
118 {
119 continue;
120 }
121
122 __acrt_lock_stream_and_call(stream.public_stream(), [&]
123 {
124 // Re-verify the state of the stream. Another thread may have
125 // closed the stream, reopened it into a different mode, or
126 // otherwise altered the state of the stream such that this
127 // flush would be a no-op.
128 if (!common_flush_all_should_try_to_flush_stream(stream, &count))
129 {
130 return;
131 }
132
133 if (!flush_read_mode_streams && !stream.has_all_of(_IOWRITE))
134 {
135 return;
136 }
137
138 if (_fflush_nolock(stream.public_stream()) != EOF)
139 {
140 ++count;
141 }
142 else
143 {
144 error = EOF;
145 }
146 });
147 }
148 });
149
150 return flush_read_mode_streams ? count : error;
151}
152
153
154
155// Flushes the buffer of the given stream. If the file is open for writing and
156// is buffered, the buffer is flushed. On success, returns 0. On failure (e.g.
157// if there is an error writing the buffer), returns EOF and sets errno.
158extern "C" int __cdecl fflush(FILE* const public_stream)
159{
160 __crt_stdio_stream const stream(public_stream);
161
162 // If the stream is null, flush all the streams:
163 if (!stream.valid())
164 {
165 return common_flush_all(false);
166 }
167
168 // Before acquiring the stream lock, inspect the stream to see if the flush
169 // is a no-op. If it will be a no-op then we can return without attempting
170 // to acquire the lock (this can help prevent locking conflicts; see the
171 // common_flush_all implementation for more information).
173 {
174 return 0;
175 }
176
177 return __acrt_lock_stream_and_call(stream.public_stream(), [&]
178 {
179 return _fflush_nolock(stream.public_stream());
180 });
181}
182
183
184
185static int __cdecl _fflush_nolock_internal(FILE* const public_stream, __crt_cached_ptd_host& ptd)
186{
187 __crt_stdio_stream const stream(public_stream);
188
189 // If the stream is null, flush all the streams.
190 if (!stream.valid())
191 {
192 return common_flush_all(false);
193 }
194
195 if (__acrt_stdio_flush_nolock(stream.public_stream(), ptd) != 0)
196 {
197 // If the flush fails, do not attempt to commit:
198 return EOF;
199 }
200
201 // Perform the lowio commit to ensure data is written to disk:
202 if (stream.has_all_of(_IOCOMMIT))
203 {
204 if (_commit(_fileno(public_stream)))
205 {
206 return EOF;
207 }
208 }
209
210 return 0;
211}
212
213extern "C" int __cdecl _fflush_nolock(FILE* const public_stream)
214{
215 __crt_cached_ptd_host ptd;
216 return _fflush_nolock_internal(public_stream, ptd);
217}
218
219// Flushes the buffer of the given stream. If the file is open for writing and
220// is buffered, the buffer is flushed. On success, returns 0. On failure (e.g.
221// if there is an error writing the buffer), returns EOF and sets errno.
222extern "C" int __cdecl __acrt_stdio_flush_nolock(FILE* const public_stream, __crt_cached_ptd_host& ptd)
223{
224 __crt_stdio_stream const stream(public_stream);
225
226 if (!is_stream_flushable(stream.get_flags()))
227 {
228 return 0;
229 }
230
231 int const bytes_to_write = static_cast<int>(stream->_ptr - stream->_base);
232
234
235 if (bytes_to_write <= 0)
236 {
237 return 0;
238 }
239
240 int const bytes_written = _write_internal(_fileno(stream.public_stream()), stream->_base, bytes_to_write, ptd);
241 if (bytes_to_write != bytes_written)
242 {
243 stream.set_flags(_IOERROR);
244 return EOF;
245 }
246
247 // If this is a read/write file, clear _IOWRITE so that the next operation can
248 // be a read:
249 if (stream.has_all_of(_IOUPDATE))
250 {
251 stream.unset_flags(_IOWRITE);
252 }
253
254 return 0;
255}
256
257
258
259// Flushes the buffers for all output streams and clears all input buffers.
260// Returns the number of open streams.
261extern "C" int __cdecl _flushall()
262{
263 return common_flush_all(true);
264}
#define __cdecl
Definition: accygwin.h:79
@ __acrt_stdio_index_lock
int __cdecl _write_internal(_In_ int _FileHandle, _In_reads_bytes_(_MaxCharCount) void const *_Buf, _In_ unsigned int _MaxCharCount, _Inout_ __crt_cached_ptd_host &_Ptd)
@ _IOBUFFER_CRT
@ _IOBUFFER_USER
void __cdecl __acrt_stdio_reset_buffer(__crt_stdio_stream const stream)
auto __acrt_lock_stream_and_call(FILE *const stream, Action &&action) -> decltype(action())
int _nstream
__crt_stdio_stream_data ** __piob
_In_ size_t const _In_ int _In_ bool const _In_ unsigned const _In_ __acrt_rounding_mode const _Inout_ __crt_cached_ptd_host & ptd
Definition: cvt.cpp:355
static bool __cdecl common_flush_all_should_try_to_flush_stream(_In_ __crt_stdio_stream const stream, _Inout_ int *const flushed_stream_count)
Definition: fflush.cpp:56
static bool __cdecl is_stream_flushable(long const stream_flags)
Definition: fflush.cpp:18
int __cdecl _fflush_nolock(FILE *const public_stream)
Definition: fflush.cpp:213
int __cdecl __acrt_stdio_flush_nolock(FILE *const public_stream, __crt_cached_ptd_host &ptd)
Definition: fflush.cpp:222
static bool __cdecl is_stream_allocated(long const stream_flags)
Definition: fflush.cpp:13
static int __cdecl _fflush_nolock_internal(FILE *const public_stream, __crt_cached_ptd_host &ptd)
Definition: fflush.cpp:185
int __cdecl fflush(FILE *const public_stream)
Definition: fflush.cpp:158
static bool __cdecl is_stream_flushable_or_commitable(long const stream_flags)
Definition: fflush.cpp:33
static int __cdecl common_flush_all(bool const flush_read_mode_streams)
Definition: fflush.cpp:101
int __cdecl _flushall()
Definition: fflush.cpp:261
GLuint GLuint GLsizei count
Definition: gl.h:1545
_Check_return_ _CRTIMP int __cdecl _fileno(_In_ FILE *_File)
#define EOF
Definition: stdio.h:24
#define _IOREAD
Definition: stdio.h:124
if(dx< 0)
Definition: linetemp.h:194
static struct file_entry * first_file
Definition: makefsdata.c:165
static struct file_entry * last_file
Definition: makefsdata.c:166
#define error(str)
Definition: mkdosfs.c:1605
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
_Check_return_opt_ _CRTIMP int __cdecl _commit(_In_ int _FileHandle)
#define _IOCOMMIT
Definition: msvcrt.h:69
Definition: parse.h:23