Search code examples
c++stdoutiostreamnonblockingfcntl

Make std::cout do not fail with O_NONBLOCK or make stdin O_NONBLOCK keeping stdout blocking?


#include <iostream>
#include <unistd.h>
#include <fcntl.h>
using namespace std;

int main(){
        // Make stdin non-blocking
        fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);

        printf("stdout O_NONBLOCK is: %d\n", fcntl(STDOUT_FILENO, F_GETFL) & O_NONBLOCK);
        printf("stdin O_NONBLOCK is: %d\n",  fcntl(STDIN_FILENO , F_GETFL) & O_NONBLOCK);

        for(int i=0; i<16; i++){
            cout<<"  "<<"fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er "<<endl;
        }
        bool cerrfail=cerr.fail(), coutfail=cout.fail();
        flush(cout); flush(clog); flush(cerr);
        cout.clear(); cerr.clear(); clog.clear();
        cerr<<"\ncerr.fail():"<<cerrfail<<" cout.fail():"<<coutfail<<endl;
}

possible output:

Compiler G++ 9.3
MacOS Mojave 10.14.6

stdout O_NONBLOCK is: 4
stdin O_NONBLOCK is: 4
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo erouhep hv reough er 
  fgvbhln;j;jblhcbwnoi wiejnocje ocweo cewoj coj weoj cowejojewohewouspuweoche njwpihbeh wjo ero
cerr.fail():0 cout.fail():1

fails because of fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK);

Why? How to fix keeping stdin non-block?

update. Why? because setting stdin O_NONBLOCK also makes stdout O_NONBLOCK. And std::out receives some ASYNC error code (like ETRYAGAIN) in its internals.

I see two solutions:

  • make std::cout do not fail with O_NONBLOCK
  • make stdin O_NONBLOCK keeping stdout blocking?

update2. The issue appears on MacOS only. Does not on Linux amd64 and does not on Linux MIPS (Atheros).


Solution

  • Standard streams do not support non-blocking file descriptors, those are beyond the scope of the C++ standard.

    If you insist on using non-blocking file descriptors with standard streams, then you need to implement a stream buffer that can read/write non-blocking file descriptors. You can do that from scratch by deriving std::basic_streambuf and implementing its virtual functions or use excellent Boost.Iostreams to greatly reduce the amount and complexity of boilerplate code you'd otherwise have to write. And then replace the buffer of std::cout, std::cin and friends with your special stream buffer with a call to std::basic_ios<>::rdbuf.

    Even then, using std::istream and std::ostream interfaces you wouldn't be able to distinguish end-of-file from EAGAIN.


    You may like to elaborate what problem you are trying to solve because your current solution creates more problems.