Welcome
Example Code
C and C++
Argument Parsing
Create Subprocess
Create Thread
Is Subprocess Done
Non-Blocking File (Unix)
Mutex (Lock)
TCP Server
Wait For File (Unix)
Python
Non-Blocking Read

Monju System Architects



Code - C++ - Non-Blocking File (Unix)
Download: nonBlockingFile.cpp (the linked-to file is properly tabbed)
Requires: file.h
//  Copyright (c) 2007, Monju System Architects
//
//  Released under the Monju-Public copyright license:
//
//  Permission is hereby granted, free of charge, to any person or entity
//  obtaining a copy of this software and associated documentation files
//  (the "Software"), to deal in the Software without restriction,
//  including without limitation the rights to use, copy, modify, merge,
//  publish, distribute, sublicense, and/or sell copies and modifications
//  of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be
//  included in all copies or substantial portions of published, sold, or
//  ownership-transferred versions of the Software. The notices are not
//  required for binary-only releases or binary-only derivatives of the
//  Software, or documentation provided with binary-only releases and
//  binary-only derivatives.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
//  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
//  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
//  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.




//  NOTE:  YOU MUST run the following or your exe will exit when the other
//  side of a socket is closed and you are still reading from or writing
//  to it:
//
//  signal(SIGPIPE, SIG_IGN);  //  ignore SIGPIPE.
//
//  Another option is to use MSG_NOSIGNAL or SO_NOSIGPIPE, but these are
//  system dependant and outside the scope of this code.




//  NOTE:  Unix only.



//  INCLUDES.
#include <errno.h>
#ifdef _WIN32
    #include <Windows.h>
#else
    #include <fcntl.h>
    #include <unistd.h>
#endif

#include "public/file.h"



//  isNonBlockingFile()
bool isNonBlockingFile(FILE_TYPE theFile) {
    #ifdef _WIN32
        return true;
    #else
        return O_NONBLOCK & fcntl(theFile, F_GETFL, 0);
    #endif
}



//  readNonBlockingFile()
//
//  This assumes setNonBlocking() was already called on the passed in file descriptor.
void readNonBlockingFile(FILE_TYPE file, char* pBuffer, int* pInOutAmount) {
    #ifdef _WIN32
        throw("TODO: implement readNonBlocking() for windows.");
    #else

        //  DO THE READ.
        ssize_t amount = read(fileHandle, pBuffer, *pInOutAmount);

        //  HANDLE SUCCESSFUL READ.
        if (amount >= 0) {
            *pInOutAmount = amount;
            return;
        }

        //  HANDLE WOULD BLOCK AND TRY AGAIN.
        if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
            *pInOutAmount = 0;
            return;
        }

        //  HANDLE FAILURE.
        throw("readNonBlocking(): read() failed.");
    #endif
}



//  setBlockingFile()
void setBlockingFile(FILE_TYPE fileHandle) {
    #ifdef _WIN32
        fileHandle.m_isBlocking = true;
    #else
        int flags;
        #if defined(O_NONBLOCK)
            if (-1 == (flags = fcntl(fileHandle, F_GETFL, 0))) {
                flags = 0;
            }
            if(0 != fcntl(fileHandle, F_SETFL, flags & ~O_NONBLOCK)) {
                throw("fcntl() failed.");
            }
        #else
            flags = 0;
            if (0 != ioctl(fileHandle, FIOBIO, &flags)) {
                throw("ioctl() failed.");
            }
        #endif
    #endif
}



//  setNonBlockingFile()
void setNonBlockingFile(FILE_TYPE fileHandle) {
    #ifdef _WIN32
        fileHandle.m_isBlocking = false;
    #else
        int flags;
        #if defined(O_NONBLOCK)
            if (-1 == (flags = fcntl(fileHandle, F_GETFL, 0))) {
                flags = 0;
            }
            if(0 != fcntl(fileHandle, F_SETFL, flags | O_NONBLOCK)) {
                throw("fcntl() failed.");
            }
        #else
            flags = 1;
            if (0 != ioctl(fileHandle, FIOBIO, &flags)) {
                throw("ioctl() failed.");
            }
        #endif
    #endif
}



//  writeNonBlockingFile()
//
//  This assumes setNonBlocking() was already called on the passed in file descriptor.
void writeNonBlockingFile(FILE_TYPE fileHandle, const char* pBuffer, int* pInOutAmount) {
    #ifdef _WIN32
        throw("TODO: implement writeNonBlocking() for windows.");
    #else

        //  DO THE READ.
        ssize_t amount = write(fileHandle, pBuffer, *pInOutAmount);

        //  HANDLE SUCCESSFUL READ.
        if (amount >= 0) {
            *pInOutAmount = amount;
            return;
        }

        //  HANDLE WOULD BLOCK AND TRY AGAIN.
        if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
            *pInOutAmount = 0;
            return;
        }

        //  HANDLE FAILURE.
        throw("writeNonBlocking(): write() failed.");
    #endif
}