@@ -308,6 +308,43 @@ private:
308
308
state_type __st_;
309
309
state_type __st_last_;
310
310
ios_base::openmode __om_;
311
+ // There have been no file operations yet, which allows setting unbuffered
312
+ // I/O mode.
313
+ static const ios_base::openmode __no_io_operations = ios_base::trunc;
314
+ // Unbuffered I/O mode has been requested.
315
+ static const ios_base::openmode __use_unbuffered_io = ios_base::ate;
316
+ // Used to track the currently used mode and track whether the output should
317
+ // be unbuffered.
318
+ // [filebuf.virtuals]/12
319
+ // If setbuf(0, 0) is called on a stream before any I/O has occurred on
320
+ // that stream, the stream becomes unbuffered. Otherwise the results are
321
+ // implementation-defined.
322
+ // This allows calling setbuf(0, 0)
323
+ // - before opening a file,
324
+ // - after opening a file, before
325
+ // - a read
326
+ // - a write
327
+ // - a seek.
328
+ // Note that opening a file with ios_base::ate does a seek operation.
329
+ // Normally underflow, overflow, and sync change this flag to ios_base::in,
330
+ // ios_base_out, or 0.
331
+ //
332
+ // The ios_base::trunc and ios_base::ate flags are not used in __cm_. They
333
+ // are used to track the state of the unbuffered request. For readability
334
+ // they have the aliases __no_io_operations and __use_unbuffered_io
335
+ // respectively.
336
+ //
337
+ // The __no_io_operations and __use_unbuffered_io flags are used in the
338
+ // following way:
339
+ // - __no_io_operations is set upon construction to indicate the unbuffered
340
+ // state can be set.
341
+ // - When requesting unbuffered output:
342
+ // - If the file is open it sets the mode.
343
+ // - Else places a request by adding the __use_unbuffered_io flag.
344
+ // - When a file is opened it checks whether both __no_io_operations and
345
+ // __use_unbuffered_io are set. If so switches to unbuffered mode.
346
+ // - All file I/O operations change the mode effectively clearing the
347
+ // __no_io_operations and __use_unbuffered_io flags.
311
348
ios_base::openmode __cm_;
312
349
bool __owns_eb_;
313
350
bool __owns_ib_;
@@ -327,7 +364,13 @@ private:
327
364
return nullptr ;
328
365
329
366
__om_ = __mode;
367
+ if (__cm_ == (__no_io_operations | __use_unbuffered_io)) {
368
+ std::setbuf (__file_, nullptr );
369
+ __cm_ = 0 ;
370
+ }
371
+
330
372
if (__mode & ios_base::ate) {
373
+ __cm_ = 0 ;
331
374
if (fseek (__file_, 0 , SEEK_END)) {
332
375
fclose (__file_);
333
376
__file_ = nullptr ;
@@ -337,6 +380,20 @@ private:
337
380
338
381
return this ;
339
382
}
383
+
384
+ // If the file is already open, switch to unbuffered mode. Otherwise, record
385
+ // the request to use unbuffered mode so that we use that mode when we
386
+ // eventually open the file.
387
+ _LIBCPP_HIDE_FROM_ABI void __request_unbuffered_mode (char_type* __s, streamsize __n) {
388
+ if (__cm_ == __no_io_operations && __s == nullptr && __n == 0 ) {
389
+ if (__file_) {
390
+ std::setbuf (__file_, nullptr );
391
+ __cm_ = 0 ;
392
+ } else {
393
+ __cm_ = __no_io_operations | __use_unbuffered_io;
394
+ }
395
+ }
396
+ }
340
397
};
341
398
342
399
template <class _CharT , class _Traits >
@@ -352,7 +409,7 @@ basic_filebuf<_CharT, _Traits>::basic_filebuf()
352
409
__st_(),
353
410
__st_last_(),
354
411
__om_(0 ),
355
- __cm_(0 ),
412
+ __cm_(__no_io_operations ),
356
413
__owns_eb_(false ),
357
414
__owns_ib_(false ),
358
415
__always_noconv_(false ) {
@@ -810,6 +867,7 @@ template <class _CharT, class _Traits>
810
867
basic_streambuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::setbuf (char_type* __s, streamsize __n) {
811
868
this ->setg (nullptr , nullptr , nullptr );
812
869
this ->setp (nullptr , nullptr );
870
+ __request_unbuffered_mode (__s, __n);
813
871
if (__owns_eb_)
814
872
delete[] __extbuf_;
815
873
if (__owns_ib_)
0 commit comments