0
#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).

kyb
  • 7,233
  • 5
  • 52
  • 105
  • 1
    Is stdout also non-blocking after your call? https://stackoverflow.com/q/23865898/1133144 – ioums Jul 07 '20 at 18:11
  • Yes. It sets non-block to both `stdout O_NONBLOCK is: 4 stdin O_NONBLOCK is: 4` – kyb Jul 07 '20 at 18:14
  • What compiler, version, compiler options are you using? What platform are you on? What implementation of C and C++ standard libraries are you using? I think, if this is specific to OSX, consider tagging it with OSX. I can't reproduce on linux with glibc, (on linux `O_NONBLOCK = 2048`). – KamilCuk Jul 07 '20 at 18:34
  • @KamilCuk, thank you for response, I added details about my system. – kyb Jul 08 '20 at 06:06
  • 1
    Your update doesn't really explain why you want `stdout` to be non-blocking. What would be the advantage of this? If attempting to output is generating an error code, then it sounds like you have an X-Y problem and should fix *that* instead. – Cody Gray - on strike Jul 08 '20 at 09:38

1 Answers1

2

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.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271