diff --git a/ChangeLog.txt b/ChangeLog.txt index 3c3bb2e3e6..4c4905aa03 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,6 +10,21 @@ * Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment */ +2016-04-05 21:24 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * src/rtl/gttone.c + ! use asm {} directive only in CLANG BCC builds - asm {} needs TASM + so using it breaks Harbour compilation with free BorlandC command + line tools which do not contain TASM. + + * src/rtl/hbsocket.c + * src/rtl/hbproces.c + * src/rtl/filesys.c + * src/rtl/hbcom.c + ! use poll() instead of select() in POSIX.1-2001 compliant *nix builds + It fixes the problem with file handles >= 1024 + Please make tests in different *nix builds. It affects sockets, pipes + and serial ports. + 2016-04-05 16:27 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * contrib/hbnetio/netiosrv.c * minor optimization diff --git a/src/rtl/filesys.c b/src/rtl/filesys.c index e2c6d92e51..fd088b2f59 100644 --- a/src/rtl/filesys.c +++ b/src/rtl/filesys.c @@ -111,6 +111,12 @@ #include #include #include + #if defined( _POSIX_C_SOURCE ) && _POSIX_C_SOURCE >= 200112L + /* use poll() instead of select() to avoid FD_SETSIZE (1024 in Linux) + file handle limit */ + #define HB_HAS_POLL + #include + #endif #endif #if ! defined( HB_OS_WIN ) # include @@ -1136,15 +1142,51 @@ HB_SIZE hb_fsPipeIsData( HB_FHANDLE hPipeHandle, HB_SIZE nBufferSize, } #elif defined( HB_OS_UNIX ) && ! defined( HB_OS_SYMBIAN ) { + int iResult; + +#if defined( HB_HAS_POLL ) + HB_MAXUINT timer = nTimeOut <= 0 ? 0 : hb_dateMilliSeconds(); + struct pollfd fds; + + fds.fd = hPipeHandle; + fds.events = POLLIN; + fds.revents = 0; + + for( ;; ) + { + int tout = nTimeOut < 0 || nTimeOut > 1000 ? 1000 : ( int ) nTimeOut; + iResult = poll( &fds, 1, tout ); + hb_fsSetIOError( iResult >= 0, 0 ); + if( iResult > 0 && ( fds.revents & POLLIN ) == 0 ) + iResult = 0; + if( ( ( iResult == 0 && ( nTimeOut < 0 || nTimeOut > 1000 ) ) || + ( iResult == -1 && nTimeOut != 0 && hb_fsOsError() == ( HB_ERRCODE ) EINTR ) ) && + hb_vmRequestQuery() == 0 ) + { + if( nTimeOut < 0 ) + continue; + else + { + HB_MAXUINT timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + nTimeOut -= timecurr - timer; + if( nTimeOut > 0 ) + continue; + } + } + } + break; + } +#else struct timeval tv; fd_set rfds; - int iResult; -#if ! defined( HB_HAS_SELECT_TIMER ) +# if ! defined( HB_HAS_SELECT_TIMER ) HB_MAXUINT timer = nTimeOut <= 0 ? 0 : hb_dateMilliSeconds(); -#else +# else tv.tv_sec = ( long ) nTimeOut / 1000; tv.tv_usec = ( long ) ( nTimeOut % 1000 ) * 1000; -#endif +# endif for( ;; ) { @@ -1153,13 +1195,13 @@ HB_SIZE hb_fsPipeIsData( HB_FHANDLE hPipeHandle, HB_SIZE nBufferSize, tv.tv_sec = 1; tv.tv_usec = 0; } -#if ! defined( HB_HAS_SELECT_TIMER ) +# if ! defined( HB_HAS_SELECT_TIMER ) else { tv.tv_sec = ( long ) nTimeOut / 1000; tv.tv_usec = ( long ) ( nTimeOut % 1000 ) * 1000; } -#endif +# endif FD_ZERO( &rfds ); FD_SET( hPipeHandle, &rfds ); @@ -1171,7 +1213,7 @@ HB_SIZE hb_fsPipeIsData( HB_FHANDLE hPipeHandle, HB_SIZE nBufferSize, hb_fsOsError() != ( HB_ERRCODE ) EINTR || hb_vmRequestQuery() != 0 ) break; -#if ! defined( HB_HAS_SELECT_TIMER ) +# if ! defined( HB_HAS_SELECT_TIMER ) else if( nTimeOut > 0 ) { HB_MAXUINT timecurr = hb_dateMilliSeconds(); @@ -1182,8 +1224,10 @@ HB_SIZE hb_fsPipeIsData( HB_FHANDLE hPipeHandle, HB_SIZE nBufferSize, timer = timecurr; } } -#endif +# endif } +#endif /* HB_HAS_POLL */ + if( iResult > 0 ) nToRead = nBufferSize; } @@ -1334,15 +1378,51 @@ HB_SIZE hb_fsPipeWrite( HB_FHANDLE hPipeHandle, const void * buffer, HB_SIZE nSi } #elif defined( HB_OS_UNIX ) && ! defined( HB_OS_SYMBIAN ) { + int iResult; + +#if defined( HB_HAS_POLL ) + HB_MAXUINT timer = nTimeOut <= 0 ? 0 : hb_dateMilliSeconds(); + struct pollfd fds; + + fds.fd = hPipeHandle; + fds.events = POLLOUT; + fds.revents = 0; + + for( ;; ) + { + int tout = nTimeOut < 0 || nTimeOut > 1000 ? 1000 : ( int ) nTimeOut; + iResult = poll( &fds, 1, tout ); + hb_fsSetIOError( iResult >= 0, 0 ); + if( iResult > 0 && ( fds.revents & POLLOUT ) == 0 ) + iResult = 0; + if( ( ( iResult == 0 && ( nTimeOut < 0 || nTimeOut > 1000 ) ) || + ( iResult == -1 && nTimeOut != 0 && hb_fsOsError() == ( HB_ERRCODE ) EINTR ) ) && + hb_vmRequestQuery() == 0 ) + { + if( nTimeOut < 0 ) + continue; + else + { + HB_MAXUINT timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + nTimeOut -= timecurr - timer; + if( nTimeOut > 0 ) + continue; + } + } + } + break; + } +#else struct timeval tv; fd_set wfds; - int iResult; -#if ! defined( HB_HAS_SELECT_TIMER ) +# if ! defined( HB_HAS_SELECT_TIMER ) HB_MAXUINT timer = nTimeOut <= 0 ? 0 : hb_dateMilliSeconds(); -#else +# else tv.tv_sec = ( long ) nTimeOut / 1000; tv.tv_usec = ( long ) ( nTimeOut % 1000 ) * 1000; -#endif +# endif for( ;; ) { @@ -1351,13 +1431,13 @@ HB_SIZE hb_fsPipeWrite( HB_FHANDLE hPipeHandle, const void * buffer, HB_SIZE nSi tv.tv_sec = 1; tv.tv_usec = 0; } -#if ! defined( HB_HAS_SELECT_TIMER ) +# if ! defined( HB_HAS_SELECT_TIMER ) else { tv.tv_sec = ( long ) nTimeOut / 1000; tv.tv_usec = ( long ) ( nTimeOut % 1000 ) * 1000; } -#endif +# endif FD_ZERO( &wfds ); FD_SET( hPipeHandle, &wfds ); @@ -1369,7 +1449,7 @@ HB_SIZE hb_fsPipeWrite( HB_FHANDLE hPipeHandle, const void * buffer, HB_SIZE nSi hb_fsOsError() != ( HB_ERRCODE ) EINTR || hb_vmRequestQuery() != 0 ) break; -#if ! defined( HB_HAS_SELECT_TIMER ) +# if ! defined( HB_HAS_SELECT_TIMER ) else if( nTimeOut > 0 ) { HB_MAXUINT timecurr = hb_dateMilliSeconds(); @@ -1380,8 +1460,10 @@ HB_SIZE hb_fsPipeWrite( HB_FHANDLE hPipeHandle, const void * buffer, HB_SIZE nSi timer = timecurr; } } -#endif +# endif } +#endif /* HB_HAS_POLL */ + if( iResult > 0 ) { int iFlags = -1; diff --git a/src/rtl/gttone.c b/src/rtl/gttone.c index 1d99494e1f..7db9642a25 100644 --- a/src/rtl/gttone.c +++ b/src/rtl/gttone.c @@ -83,7 +83,7 @@ static int hb_Inp9x( unsigned short int usPort ) HB_TRACE( HB_TR_DEBUG, ( "hb_Inp9x(%hu)", usPort ) ); - #if defined( __DMC__ ) + #if defined( __DMC__ ) || ( defined( __BORLANDC__ ) && ! defined( __clang__ ) ) _DX = usPort; __emit__(0xEC); /* ASM IN AL, DX */ @@ -121,7 +121,7 @@ static int hb_Outp9x( unsigned short int usPort, unsigned short int usVal ) { HB_TRACE( HB_TR_DEBUG, ( "hb_Outp9x(%hu, %hu)", usPort, usVal ) ); - #if defined( __DMC__ ) + #if defined( __DMC__ ) || ( defined( __BORLANDC__ ) && ! defined( __clang__ ) ) _DX = usPort; _AL = usVal; diff --git a/src/rtl/hbcom.c b/src/rtl/hbcom.c index 72641a6577..bc94f29a31 100644 --- a/src/rtl/hbcom.c +++ b/src/rtl/hbcom.c @@ -81,6 +81,12 @@ # if defined( HB_OS_UNIX ) # include # include +# if defined( _POSIX_C_SOURCE ) && _POSIX_C_SOURCE >= 200112L + /* use poll() instead of select() to avoid FD_SETSIZE (1024 in Linux) + file handle limit */ +# define HB_HAS_POLL +# include +# endif # endif # if defined( HB_OS_HPUX ) # include @@ -527,16 +533,53 @@ static void hb_comSetOsError( PHB_COM pCom, HB_BOOL fError ) #if defined( HB_OS_UNIX ) static int hb_comCanRead( PHB_COM pCom, HB_MAXINT timeout ) { - struct timeval tv; - fd_set rfds; int iResult; -#if ! defined( HB_HAS_SELECT_TIMER ) +#if defined( HB_HAS_POLL ) HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); + struct pollfd fds; + + fds.fd = pCom->fd; + fds.events = POLLIN; + fds.revents = 0; + + for( ;; ) + { + int tout = timeout < 0 || timeout > 1000 ? 1000 : ( int ) timeout; + iResult = poll( &fds, 1, tout ); + hb_comSetOsError( pCom, iResult == -1 ); + if( iResult > 0 && ( fds.revents & POLLIN ) == 0 ) + iResult = 0; + if( ( ( iResult == 0 && ( timeout < 0 || timeout > 1000 ) ) || + ( iResult == -1 && timeout != 0 && HB_COM_IS_EINTR() ) ) && + hb_vmRequestQuery() == 0 ) + { + if( timeout < 0 ) + continue; + else + { + HB_MAXUINT timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + timeout -= timecurr - timer; + if( timeout > 0 ) + continue; + } + } + } + break; + } + return iResult; #else + struct timeval tv; + fd_set rfds; + +# if ! defined( HB_HAS_SELECT_TIMER ) + HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); +# else tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( long ) ( timeout % 1000 ) * 1000; -#endif +# endif for( ;; ) { @@ -548,22 +591,24 @@ static int hb_comCanRead( PHB_COM pCom, HB_MAXINT timeout ) tv.tv_sec = 1; tv.tv_usec = 0; } -#if ! defined( HB_HAS_SELECT_TIMER ) +# if ! defined( HB_HAS_SELECT_TIMER ) else { tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( long ) ( timeout % 1000 ) * 1000; } -#endif +# endif iResult = select( ( int ) ( pCom->fd + 1 ), &rfds, NULL, NULL, &tv ); + if( iResult > 0 && ! FD_ISSET( pCom->fd, &rfds ) ) + iResult = 0; hb_comSetOsError( pCom, iResult == -1 ); - if( iResult == 0 && timeout < 0 ) + if( iResult == 0 && timeout < 0 && hb_vmRequestQuery() == 0 ) continue; if( iResult != -1 || timeout == 0 || ! HB_COM_IS_EINTR() || hb_vmRequestQuery() != 0 ) break; -#if ! defined( HB_HAS_SELECT_TIMER ) +# if ! defined( HB_HAS_SELECT_TIMER ) else if( timeout > 0 ) { HB_MAXUINT timecurr = hb_dateMilliSeconds(); @@ -574,25 +619,62 @@ static int hb_comCanRead( PHB_COM pCom, HB_MAXINT timeout ) timer = timecurr; } } -#endif +# endif } +#endif /* HB_HAS_POLL */ - return iResult < 0 ? -1 : - ( iResult > 0 && FD_ISSET( pCom->fd, &rfds ) ? 1 : 0 ); + return iResult; } static int hb_comCanWrite( PHB_COM pCom, HB_MAXINT timeout ) { - struct timeval tv; - fd_set wfds; int iResult; -#if ! defined( HB_HAS_SELECT_TIMER ) +#if defined( HB_HAS_POLL ) HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); + struct pollfd fds; + + fds.fd = pCom->fd; + fds.events = POLLOUT; + fds.revents = 0; + + for( ;; ) + { + int tout = timeout < 0 || timeout > 1000 ? 1000 : ( int ) timeout; + iResult = poll( &fds, 1, tout ); + hb_comSetOsError( pCom, iResult == -1 ); + if( iResult > 0 && ( fds.revents & POLLOUT ) == 0 ) + iResult = 0; + if( ( ( iResult == 0 && ( timeout < 0 || timeout > 1000 ) ) || + ( iResult == -1 && timeout != 0 && HB_COM_IS_EINTR() ) ) && + hb_vmRequestQuery() == 0 ) + { + if( timeout < 0 ) + continue; + else + { + HB_MAXUINT timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + timeout -= timecurr - timer; + if( timeout > 0 ) + continue; + } + } + } + break; + } + return iResult; #else + struct timeval tv; + fd_set wfds; + +# if ! defined( HB_HAS_SELECT_TIMER ) + HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); +# else tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( long ) ( timeout % 1000 ) * 1000; -#endif +# endif for( ;; ) { @@ -604,22 +686,24 @@ static int hb_comCanWrite( PHB_COM pCom, HB_MAXINT timeout ) tv.tv_sec = 1; tv.tv_usec = 0; } -#if ! defined( HB_HAS_SELECT_TIMER ) +# if ! defined( HB_HAS_SELECT_TIMER ) else { tv.tv_sec = ( long ) ( timeout / 1000 ); tv.tv_usec = ( long ) ( timeout % 1000 ) * 1000; } -#endif +# endif iResult = select( ( int ) ( pCom->fd + 1 ), NULL, &wfds, NULL, &tv ); + if( iResult > 0 && FD_ISSET( pCom->fd, &wfds ) ) + iResult = 0; hb_comSetOsError( pCom, iResult == -1 ); - if( iResult == 0 && timeout < 0 ) + if( iResult == 0 && timeout < 0 && hb_vmRequestQuery() == 0 ) continue; if( iResult != -1 || timeout == 0 || ! HB_COM_IS_EINTR() || hb_vmRequestQuery() != 0 ) break; -#if ! defined( HB_HAS_SELECT_TIMER ) +# if ! defined( HB_HAS_SELECT_TIMER ) else if( timeout > 0 ) { HB_MAXUINT timecurr = hb_dateMilliSeconds(); @@ -630,12 +714,12 @@ static int hb_comCanWrite( PHB_COM pCom, HB_MAXINT timeout ) timer = timecurr; } } -#endif +# endif break; } +#endif /* HB_HAS_POLL */ - return iResult < 0 ? -1 : - ( iResult > 0 && FD_ISSET( pCom->fd, &wfds ) ? 1 : 0 ); + return iResult; } #endif diff --git a/src/rtl/hbproces.c b/src/rtl/hbproces.c index 69f98f5526..4a6fe13583 100644 --- a/src/rtl/hbproces.c +++ b/src/rtl/hbproces.c @@ -58,6 +58,13 @@ # include # include # include +# include +# if defined( _POSIX_C_SOURCE ) && _POSIX_C_SOURCE >= 200112L + /* use poll() instead of select() to avoid FD_SETSIZE (1024 in Linux) + file handle limit */ +# define HB_HAS_POLL +# include +# endif #elif defined( HB_OS_OS2 ) # define INCL_DOSERRORS # define INCL_DOSPROCESS @@ -1456,11 +1463,6 @@ int hb_fsProcessRun( const char * pszFileName, #elif defined( HB_OS_UNIX ) && ! defined( HB_OS_SYMBIAN ) - fd_set rfds, wfds, *prfds, *pwfds; - HB_FHANDLE fdMax; - HB_SIZE ul; - int n; - if( nStdInLen == 0 && hStdin != FS_ERROR ) { hb_fsClose( hStdin ); @@ -1478,99 +1480,153 @@ int hb_fsProcessRun( const char * pszFileName, for( ;; ) { - fdMax = 0; - prfds = pwfds = NULL; - if( hStdout != FS_ERROR || hStderr != FS_ERROR ) + HB_BOOL fStdout, fStderr, fStdin; + HB_SIZE nLen; + int iResult; + +#if defined( HB_HAS_POLL ) { - FD_ZERO( &rfds ); + struct pollfd fds[ 3 ]; + nfds_t nfds = 0; + if( hStdout != FS_ERROR ) { - FD_SET( hStdout, &rfds ); - if( hStdout > fdMax ) - fdMax = hStdout; + fds[ nfds ].fd = hStdout; + fds[ nfds ].events |= POLLIN; + fds[ nfds++ ].revents = 0; } if( hStderr != FS_ERROR ) { - FD_SET( hStderr, &rfds ); - if( hStderr > fdMax ) - fdMax = hStderr; + fds[ nfds ].fd = hStderr; + fds[ nfds ].events |= POLLIN; + fds[ nfds++ ].revents = 0; } - prfds = &rfds; + if( hStdin != FS_ERROR ) + { + fds[ nfds ].fd = hStdin; + fds[ nfds ].events |= POLLOUT; + fds[ nfds++ ].revents = 0; + } + if( nfds == 0 ) + break; + + iResult = poll( fds, nfds, -1 ); + hb_fsSetIOError( iResult >= 0, 0 ); + if( iResult == -1 && hb_fsOsError() == ( HB_ERRCODE ) EINTR && + hb_vmRequestQuery() == 0 ) + continue; + else if( iResult <= 0 ) + break; + nfds = 0; + fStdout = hStdout != FS_ERROR && ( fds[ nfds++ ].revents & POLLIN ) != 0; + fStderr = hStderr != FS_ERROR && ( fds[ nfds++ ].revents & POLLIN ) != 0; + fStdin = hStdin != FS_ERROR && ( fds[ nfds++ ].revents & POLLOUT ) != 0; } - if( hStdin != FS_ERROR ) +#else { - FD_ZERO( &wfds ); - FD_SET( hStdin, &wfds ); - if( hStdin > fdMax ) - fdMax = hStdin; - pwfds = &wfds; - } - if( prfds == NULL && pwfds == NULL ) - break; + fd_set rfds, wfds, *prfds, *pwfds; + HB_FHANDLE fdMax; - n = select( fdMax + 1, prfds, pwfds, NULL, NULL ); - if( n > 0 ) + fdMax = 0; + prfds = pwfds = NULL; + if( hStdout != FS_ERROR || hStderr != FS_ERROR ) + { + FD_ZERO( &rfds ); + if( hStdout != FS_ERROR ) + { + FD_SET( hStdout, &rfds ); + if( hStdout > fdMax ) + fdMax = hStdout; + } + if( hStderr != FS_ERROR ) + { + FD_SET( hStderr, &rfds ); + if( hStderr > fdMax ) + fdMax = hStderr; + } + prfds = &rfds; + } + if( hStdin != FS_ERROR ) + { + FD_ZERO( &wfds ); + FD_SET( hStdin, &wfds ); + if( hStdin > fdMax ) + fdMax = hStdin; + pwfds = &wfds; + } + if( prfds == NULL && pwfds == NULL ) + break; + + iResult = select( fdMax + 1, prfds, pwfds, NULL, NULL ); + hb_fsSetIOError( iResult >= 0, 0 ); + if( iResult == -1 && hb_fsOsError() != ( HB_ERRCODE ) EINTR && + hb_vmRequestQuery() == 0 ) + continue; + else if( iResult <= 0 ) + break; + fStdout = hStdout != FS_ERROR && FD_ISSET( hStdout, &rfds ); + fStderr = hStderr != FS_ERROR && FD_ISSET( hStderr, &rfds ); + fStdin = hStdin != FS_ERROR && FD_ISSET( hStdin, &wfds ); + } +#endif /* HB_HAS_POLL */ + + if( fStdout ) { - if( hStdout != FS_ERROR && FD_ISSET( hStdout, &rfds ) ) + if( nOutBuf == nOutSize ) { - if( nOutBuf == nOutSize ) - { - if( nOutSize == 0 ) - nOutSize = HB_STD_BUFFER_SIZE; - else - nOutSize += nOutSize >> 1; - pOutBuf = ( char * ) hb_xrealloc( pOutBuf, nOutSize + 1 ); - } - ul = hb_fsReadLarge( hStdout, pOutBuf + nOutBuf, nOutSize - nOutBuf ); - if( ul == 0 ) - { - /* zero bytes read after positive Select() - * - writing process closed the pipe - */ - hb_fsClose( hStdout ); - hStdout = FS_ERROR; - } + if( nOutSize == 0 ) + nOutSize = HB_STD_BUFFER_SIZE; else - nOutBuf += ul; + nOutSize += nOutSize >> 1; + pOutBuf = ( char * ) hb_xrealloc( pOutBuf, nOutSize + 1 ); } - - if( hStderr != FS_ERROR && FD_ISSET( hStderr, &rfds ) ) + nLen = hb_fsReadLarge( hStdout, pOutBuf + nOutBuf, nOutSize - nOutBuf ); + if( nLen == 0 ) { - if( nErrBuf == nErrSize ) - { - if( nErrSize == 0 ) - nErrSize = HB_STD_BUFFER_SIZE; - else - nErrSize += nErrSize >> 1; - pErrBuf = ( char * ) hb_xrealloc( pErrBuf, nErrSize + 1 ); - } - ul = hb_fsReadLarge( hStderr, pErrBuf + nErrBuf, nErrSize - nErrBuf ); - if( ul == 0 ) - { - /* zero bytes read after positive Select() - * - writing process closed the pipe - */ - hb_fsClose( hStderr ); - hStderr = FS_ERROR; - } + /* zero bytes read after positive Select() + * - writing process closed the pipe + */ + hb_fsClose( hStdout ); + hStdout = FS_ERROR; + } + else + nOutBuf += nLen; + } + + if( fStderr ) + { + if( nErrBuf == nErrSize ) + { + if( nErrSize == 0 ) + nErrSize = HB_STD_BUFFER_SIZE; else - nErrBuf += ul; + nErrSize += nErrSize >> 1; + pErrBuf = ( char * ) hb_xrealloc( pErrBuf, nErrSize + 1 ); } - - if( hStdin != FS_ERROR && FD_ISSET( hStdin, &wfds ) ) + nLen = hb_fsReadLarge( hStderr, pErrBuf + nErrBuf, nErrSize - nErrBuf ); + if( nLen == 0 ) { - ul = hb_fsWriteLarge( hStdin, pStdInBuf, nStdInLen ); - pStdInBuf += ul; - nStdInLen -= ul; - if( nStdInLen == 0 ) - { - hb_fsClose( hStdin ); - hStdin = FS_ERROR; - } + /* zero bytes read after positive Select() + * - writing process closed the pipe + */ + hb_fsClose( hStderr ); + hStderr = FS_ERROR; + } + else + nErrBuf += nLen; + } + + if( fStdin ) + { + nLen = hb_fsWriteLarge( hStdin, pStdInBuf, nStdInLen ); + pStdInBuf += nLen; + nStdInLen -= nLen; + if( nStdInLen == 0 ) + { + hb_fsClose( hStdin ); + hStdin = FS_ERROR; } } - else - break; } if( hStdin != FS_ERROR ) diff --git a/src/rtl/hbsocket.c b/src/rtl/hbsocket.c index 89f5090444..81d5c7c743 100644 --- a/src/rtl/hbsocket.c +++ b/src/rtl/hbsocket.c @@ -81,6 +81,9 @@ platform supports gethostbyaddr function: #define HB_HAS_GETHOSTBYADDR + platform supports poll() function: + #define HB_HAS_POLL + platform uses sockaddr structure which contains sa_len member: #define HB_HAS_SOCKADDR_SA_LEN @@ -125,6 +128,9 @@ # define HB_HAS_ADDRINFO # define HB_HAS_NAMEINFO # define HB_HAS_GETHOSTBYADDR +# if defined( _POSIX_C_SOURCE ) && _POSIX_C_SOURCE >= 200112L +# define HB_HAS_POLL +# endif # endif # if ! defined( __WATCOMC__ ) && ! defined( HB_OS_BEOS ) && ! defined( HB_OS_MINIX ) # define HB_HAS_INET6 @@ -249,6 +255,9 @@ # if defined( HB_HAS_UNIX ) # include # endif +# if defined( HB_HAS_POLL ) +# include +# endif # include # if ! ( defined( HB_OS_LINUX ) && defined( __WATCOMC__ ) ) # include @@ -1483,13 +1492,50 @@ static int hb_socketTransType( int type, int *err ) static int hb_socketSelectRD( HB_SOCKET sd, HB_MAXINT timeout ) { +#if defined( HB_HAS_POLL ) + HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); + int iResult, iError, tout; + struct pollfd fds; + + fds.fd = sd; + fds.events = POLLIN; + fds.revents = 0; + + for( ;; ) + { + tout = timeout < 0 || timeout > 1000 ? 1000 : ( int ) timeout; + iResult = poll( &fds, 1, tout ); + iError = iResult >= 0 ? 0 : HB_SOCK_GETERROR(); + hb_socketSetOsError( iError ); + if( ( ( iResult == 0 && ( timeout < 0 || timeout > 1000 ) ) || + ( iResult == -1 && timeout != 0 && HB_SOCK_IS_EINTR( iError ) ) ) && + hb_vmRequestQuery() == 0 ) + { + if( timeout < 0 ) + continue; + else + { + HB_MAXUINT timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + timeout -= timecurr - timer; + if( timeout > 0 ) + continue; + } + } + } + break; + } + return iResult < 0 ? -1 : + ( iResult > 0 && ( fds.revents & POLLIN ) != 0 ? 1 : 0 ); +#else struct timeval tv, * ptv; fd_set rfds; int iResult, iError; -#if ! defined( HB_HAS_SELECT_TIMER ) +# if ! defined( HB_HAS_SELECT_TIMER ) HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); -#endif +# endif if( timeout >= 0 ) { @@ -1510,9 +1556,9 @@ static int hb_socketSelectRD( HB_SOCKET sd, HB_MAXINT timeout ) hb_socketSetOsError( iError ); if( iResult == -1 && timeout > 0 && HB_SOCK_IS_EINTR( iError ) && hb_vmRequestQuery() == 0 ) -#if defined( HB_HAS_SELECT_TIMER ) +# if defined( HB_HAS_SELECT_TIMER ) continue; -#else +# else { HB_MAXUINT timecurr = hb_dateMilliSeconds(); if( timecurr > timer ) @@ -1527,16 +1573,54 @@ static int hb_socketSelectRD( HB_SOCKET sd, HB_MAXINT timeout ) } } } -#endif +# endif break; } return iResult < 0 ? -1 : ( iResult > 0 && FD_ISSET( ( HB_SOCKET_T ) sd, &rfds ) ? 1 : 0 ); +#endif /* HB_HAS_POLL */ } static int hb_socketSelectWR( HB_SOCKET sd, HB_MAXINT timeout ) { +#if defined( HB_HAS_POLL ) + HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); + int iResult, iError, tout; + struct pollfd fds; + + fds.fd = sd; + fds.events = POLLOUT; + fds.revents = 0; + + for( ;; ) + { + tout = timeout < 0 || timeout > 1000 ? 1000 : ( int ) timeout; + iResult = poll( &fds, 1, tout ); + iError = iResult >= 0 ? 0 : HB_SOCK_GETERROR(); + hb_socketSetOsError( iError ); + if( ( ( iResult == 0 && ( timeout < 0 || timeout > 1000 ) ) || + ( iResult == -1 && timeout != 0 && HB_SOCK_IS_EINTR( iError ) ) ) && + hb_vmRequestQuery() == 0 ) + { + if( timeout < 0 ) + continue; + else + { + HB_MAXUINT timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + timeout -= timecurr - timer; + if( timeout > 0 ) + continue; + } + } + } + break; + } + return iResult < 0 ? -1 : + ( iResult > 0 && ( fds.revents & POLLOUT ) != 0 ? 1 : 0 ); +#else struct timeval tv, * ptv; fd_set wfds; int iResult, iError; @@ -1587,10 +1671,60 @@ static int hb_socketSelectWR( HB_SOCKET sd, HB_MAXINT timeout ) return iResult < 0 ? -1 : ( iResult > 0 && FD_ISSET( ( HB_SOCKET_T ) sd, &wfds ) ? 1 : 0 ); +#endif /* HB_HAS_POLL */ } static int hb_socketSelectWRE( HB_SOCKET sd, HB_MAXINT timeout ) { +#if defined( HB_HAS_POLL ) + HB_MAXUINT timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); + int iResult, iError, tout; + struct pollfd fds; + + fds.fd = sd; + fds.events = POLLOUT; + fds.revents = 0; + + for( ;; ) + { + tout = timeout < 0 || timeout > 1000 ? 1000 : ( int ) timeout; + iResult = poll( &fds, 1, tout ); + iError = iResult >= 0 ? 0 : HB_SOCK_GETERROR(); + hb_socketSetOsError( iError ); + if( ( ( iResult == 0 && ( timeout < 0 || timeout > 1000 ) ) || + ( iResult == -1 && timeout != 0 && HB_SOCK_IS_EINTR( iError ) ) ) && + hb_vmRequestQuery() == 0 ) + { + if( timeout < 0 ) + continue; + else + { + HB_MAXUINT timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + timeout -= timecurr - timer; + if( timeout > 0 ) + continue; + } + } + } + break; + } + if( iResult > 0 && ( fds.revents & POLLOUT ) != 0 ) + { + socklen_t len = sizeof( iError ); + if( getsockopt( sd, SOL_SOCKET, SO_ERROR, ( char * ) &iError, &len ) != 0 ) + { + iResult = -1; + iError = HB_SOCK_GETERROR(); + } + else if( iError != 0 ) + iResult = -1; + hb_socketSetOsError( iError ); + } + return iResult < 0 ? -1 : + ( iResult > 0 && ( fds.revents & POLLOUT ) != 0 ? 1 : 0 ); +#else struct timeval tv, * ptv; fd_set wfds, * pefds; @@ -1682,6 +1816,7 @@ static int hb_socketSelectWRE( HB_SOCKET sd, HB_MAXINT timeout ) return iResult < 0 ? -1 : ( iResult > 0 && FD_ISSET( ( HB_SOCKET_T ) sd, &wfds ) ? 1 : 0 ); +#endif /* HB_HAS_POLL */ } int hb_socketGetAddrFamily( const void * pSockAddr, unsigned len ) @@ -2782,11 +2917,149 @@ static HB_SOCKET s_socketSelectCallback( PHB_ITEM pItem ) return sd; } +#if defined( HB_HAS_POLL ) +static int s_socketPollCheck( HB_SOCKET sd, struct pollfd * pfds, nfds_t nfds ) +{ + nfds_t npos; + + for( npos = 0; npos < nfds; ++npos ) + { + if( pfds[ npos ].fd == sd ) + return ( int ) npos; + } + return -1; +} +#endif /* HB_HAS_POLL */ + int hb_socketSelect( PHB_ITEM pArrayRD, HB_BOOL fSetRD, PHB_ITEM pArrayWR, HB_BOOL fSetWR, PHB_ITEM pArrayEX, HB_BOOL fSetEX, HB_MAXINT timeout, HB_SOCKET_FUNC pFunc ) { +#if defined( HB_HAS_POLL ) + HB_SOCKET sd; + HB_SIZE nLen, nPos, ul; + int iResult, iError, tout, iPos, i; + HB_MAXUINT timer; + PHB_ITEM pItemSets[ 3 ]; + HB_BOOL pSet[ 3 ]; + int pEvents[ 3 ]; + struct pollfd * pfds = NULL; + nfds_t nfds = 0, ncnt = 0; + + if( pFunc == NULL ) + pFunc = s_socketSelectCallback; + + pItemSets[ 0 ] = pArrayRD; + pItemSets[ 1 ] = pArrayWR; + pItemSets[ 2 ] = pArrayEX; + pSet[ 0 ] = fSetRD; + pSet[ 1 ] = fSetWR; + pSet[ 2 ] = fSetEX; + pEvents[ 0 ] = POLLIN; + pEvents[ 1 ] = POLLOUT; + pEvents[ 2 ] = POLLERR | POLLHUP | POLLNVAL; + + for( i = 0; i < 3; i++ ) + { + if( pItemSets[ i ] ) + ncnt += ( nfds_t ) hb_arrayLen( pItemSets[ i ] ); + } + + if( ncnt > 0 ) + pfds = ( struct pollfd * ) hb_xgrab( ncnt * sizeof( struct pollfd * ) ); + + for( i = 0; i < 3; i++ ) + { + nLen = pItemSets[ i ] ? hb_arrayLen( pItemSets[ i ] ) : 0; + for( ul = 1; ul <= nLen && nfds < ncnt; ul++ ) + { + sd = pFunc( hb_arrayGetItemPtr( pItemSets[ i ], ul ) ); + if( sd != HB_NO_SOCKET ) + { + iPos = s_socketPollCheck( sd, pfds, nfds ); + if( iPos < 0 ) + { + iPos = ( int ) nfds++; + pfds[ iPos ].fd = sd; + pfds[ iPos ].revents = 0; + } + if( i < 2 ) + pfds[ iPos ].events |= pEvents[ i ]; + } + } + } + + timer = timeout <= 0 ? 0 : hb_dateMilliSeconds(); + + if( hb_vmRequestQuery() == 0 ) + { + hb_vmUnlock(); + for( ;; ) + { + tout = timeout < 0 || timeout > 1000 ? 1000 : ( int ) timeout; + iResult = poll( pfds, nfds, tout ); + iError = iResult >= 0 ? 0 : HB_SOCK_GETERROR(); + hb_socketSetOsError( iError ); + if( ( ( iResult == 0 && ( timeout < 0 || timeout > 1000 ) ) || + ( iResult == -1 && timeout != 0 && HB_SOCK_IS_EINTR( iError ) ) ) && + hb_vmRequestQuery() == 0 ) + { + if( timeout < 0 ) + continue; + else + { + HB_MAXUINT timecurr = hb_dateMilliSeconds(); + if( timecurr > timer ) + { + timeout -= timecurr - timer; + if( timeout > 0 ) + continue; + } + } + } + break; + } + hb_vmLock(); + + for( i = 0; i < 3; i++ ) + { + if( pItemSets[ i ] && pSet[ i ] ) + { + nPos = 0; + if( iResult > 0 ) + { + nLen = hb_arrayLen( pItemSets[ i ] ); + for( ul = 1; ul <= nLen; ul++ ) + { + sd = pFunc( hb_arrayGetItemPtr( pItemSets[ i ], ul ) ); + if( sd != HB_NO_SOCKET ) + { + iPos = s_socketPollCheck( sd, pfds, nfds ); + if( iPos >= 0 && ( pfds[ iPos ].revents & pEvents[ i ] ) != 0 ) + { + if( ++nPos != ul ) + hb_itemCopy( hb_arrayGetItemPtr( pItemSets[ i ], nPos ), + hb_arrayGetItemPtr( pItemSets[ i ], ul ) ); + } + } + } + } + hb_arraySize( pItemSets[ i ], nPos ); + } + } + } + else + { + hb_socketSetError( HB_SOCKET_ERR_INVALIDHANDLE ); + iResult = -1; + } + + if( pfds ) + hb_xfree( pfds ); + + return iResult; +#else HB_SOCKET maxsd, sd; int i, ret; HB_SIZE nLen, nPos, ul; @@ -2877,6 +3150,7 @@ int hb_socketSelect( PHB_ITEM pArrayRD, HB_BOOL fSetRD, } return ret; +#endif /* HB_HAS_POLL */ }