diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 9a80a74302..e05456c7d4 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,16 @@ 2008-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org) */ +2008-09-22 03:49 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/include/hbstack.h + * harbour/source/vm/estack.c + * harbour/source/vm/hvm.c + + added support for nested hb_vmUnlock()/hb_vmLock() calls + + * harbour/source/rtl/hbinet.c + * encapsulated all potentially slow inet functions inside + hb_vmUnlock()/hb_vmLock() calls + 2008-09-22 02:34 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) * harbour/include/hbvm.h * harbour/source/vm/hvm.c diff --git a/harbour/include/hbstack.h b/harbour/include/hbstack.h index 9613bdf45b..d362649fb1 100644 --- a/harbour/include/hbstack.h +++ b/harbour/include/hbstack.h @@ -161,7 +161,7 @@ typedef struct LONG lStatics; /* statics base for the current function call */ LONG lWithObject; /* stack offset to base current WITH OBJECT item */ LONG lRecoverBase; /* current SEQUENCE envelope offset or 0 if no SEQUENCE is active */ - USHORT uiActionRequest;/* Request for some action - stop processing of opcodes */ + USHORT uiActionRequest;/* request for some action - stop processing of opcodes */ USHORT uiQuitState; /* HVM is quiting */ HB_STACK_STATE state; /* first (default) stack state frame */ HB_STACKRDD rdd; /* RDD related data */ @@ -178,7 +178,8 @@ typedef struct HB_PRIVATE_STACK privates; /* private variables stack */ HB_SET_STRUCT set; #if defined( HB_MT_VM ) - PHB_DYN_HANDLES pDynH; /* Dynamic symbol handles */ + int iUnlocked; /* counter for nested hb_vmUnlock() calls */ + PHB_DYN_HANDLES pDynH; /* dynamic symbol handles */ int iDynH; /* number of dynamic symbol handles */ void * pStackLst; /* this stack entry in stack linked list */ HB_IOERRORS IOErrors; /* MT safe buffer for IO errors */ @@ -277,6 +278,8 @@ extern void hb_stackIsStackRef( void *, PHB_TSD_FUNC ); extern PHB_DYN_HANDLES hb_stackGetDynHandle( PHB_DYNS pDynSym ); extern BOOL hb_stackQuitState( void ); extern void hb_stackSetQuitState( USHORT uiState ); + extern int hb_stackUnlock( void ); + extern int hb_stackLock( void ); #endif #endif /* _HB_API_INTERNAL_ */ @@ -319,6 +322,8 @@ extern void hb_stackIsStackRef( void *, PHB_TSD_FUNC ); # define hb_stackListSet( p ) do { hb_stack.pStackLst = ( p ); } while ( 0 ) # define hb_stackQuitState( ) ( hb_stack.uiQuitState != 0 ) # define hb_stackSetQuitState( n ) do { hb_stack.uiQuitState = ( n ); } while( 0 ) +# define hb_stackUnlock() ( ++hb_stack.iUnlocked ) +# define hb_stackLock() ( --hb_stack.iUnlocked ) #endif #define hb_stackAllocItem( ) ( ( ++hb_stack.pPos == hb_stack.pEnd ? \ diff --git a/harbour/source/rtl/hbinet.c b/harbour/source/rtl/hbinet.c index 69d8c0165b..cf1b874358 100644 --- a/harbour/source/rtl/hbinet.c +++ b/harbour/source/rtl/hbinet.c @@ -63,6 +63,7 @@ #include "hbapi.h" #include "hbapiitm.h" #include "hbapierr.h" +#include "hbvm.h" /* Compile in Unix mode under Cygwin */ #ifdef HB_OS_UNIX_COMPATIBLE @@ -224,12 +225,14 @@ #ifdef HB_OS_LINUX #include -#define HB_INET_LINUX_INTERRUPT SIGUSR1+90 +/* #define HB_INET_LINUX_INTERRUPT SIGUSR1+90 */ +# ifdef HB_INET_LINUX_INTERRUPT static void hb_inetLinuxSigusrHandle( int sig ) { /* nothing to do */ HB_SYMBOL_UNUSED( sig ); } +# endif #endif /* JC1: we need it volatile to be minimally thread safe. */ @@ -251,48 +254,54 @@ static int hb_selectReadSocket( HB_SOCKET_STRUCT *Socket ) { fd_set set; struct timeval tv; + int iResult; + + hb_vmUnlock(); FD_ZERO( &set ); FD_SET(Socket->com, &set); if( Socket->timeout == -1 ) { - if( select( Socket->com + 1, &set, NULL, NULL, NULL ) < 0 ) - return 0; + iResult = select( Socket->com + 1, &set, NULL, NULL, NULL ); } else { tv.tv_sec = Socket->timeout/ 1000; tv.tv_usec = (Socket->timeout % 1000) * 1000; - if( select( Socket->com + 1, &set, NULL, NULL, &tv ) < 0 ) - return 0; + iResult = select( Socket->com + 1, &set, NULL, NULL, &tv ); } - return FD_ISSET( Socket->com, &set ); + hb_vmLock(); + + return iResult > 0 ? FD_ISSET( Socket->com, &set ) : 0; } static int hb_selectWriteSocket( HB_SOCKET_STRUCT *Socket ) { fd_set set; struct timeval tv; + int iResult; + + hb_vmUnlock(); FD_ZERO( &set ); FD_SET(Socket->com, &set); if( Socket->timeout == -1 ) { - if( select( Socket->com + 1, NULL, &set, NULL, NULL ) < 0 ) - return 0; + iResult = select( Socket->com + 1, NULL, &set, NULL, NULL ); } else { tv.tv_sec = Socket->timeout/ 1000; tv.tv_usec = (Socket->timeout % 1000) * 1000; - if( select( Socket->com + 1, NULL, &set, NULL, &tv ) < 0 ) - return 0; + iResult = select( Socket->com + 1, NULL, &set, NULL, &tv ); } - return FD_ISSET( Socket->com, &set ); + hb_vmLock(); + + return iResult > 0 ? FD_ISSET( Socket->com, &set ) : 0; } #if defined(HB_OS_WIN_32) @@ -300,6 +309,9 @@ static int hb_selectWriteExceptSocket( HB_SOCKET_STRUCT *Socket ) { fd_set set, eset; struct timeval tv; + int iResult; + + hb_vmUnlock(); FD_ZERO( &set ); FD_SET(Socket->com, &set); @@ -308,27 +320,23 @@ static int hb_selectWriteExceptSocket( HB_SOCKET_STRUCT *Socket ) if( Socket->timeout == -1 ) { - if( select( Socket->com + 1, NULL, &set, &eset, NULL ) < 0 ) - return 2; + iResult = select( Socket->com + 1, NULL, &set, &eset, NULL ) < 0 ) } else { tv.tv_sec = Socket->timeout/ 1000; tv.tv_usec = (Socket->timeout % 1000) * 1000; - if( select(Socket->com + 1, NULL, &set, &eset, &tv) < 0 ) - return 2; + iResult = select(Socket->com + 1, NULL, &set, &eset, &tv); } - if( FD_ISSET( Socket->com, &eset) ) - { + hb_vmLock(); + + if( iResult < 0 || FD_ISSET( Socket->com, &eset) ) return 2; - } - - if( FD_ISSET( Socket->com, &set ) ) - { + else if( FD_ISSET( Socket->com, &set ) ) return 1; - } - return 0; + else + return 0; } #endif @@ -339,6 +347,8 @@ static struct hostent * hb_getHosts( char * name, HB_SOCKET_STRUCT *Socket ) /* TOFIX: make it MT safe */ + hb_vmUnlock(); + /* let's see if name is an IP address; not necessary on Linux */ #if defined(HB_OS_WIN_32) || defined(HB_OS_OS2) ULONG ulAddr; @@ -373,6 +383,9 @@ static struct hostent * hb_getHosts( char * name, HB_SOCKET_STRUCT *Socket ) HB_SOCKET_SET_ERROR2( Socket, h_errno, (char *) hstrerror( h_errno ) ); #endif } + + hb_vmLock(); + return Host; } @@ -424,6 +437,8 @@ static int hb_socketConnect( HB_SOCKET_STRUCT *Socket ) #endif int iOpt = 1; + hb_vmUnlock(); + setsockopt( Socket->com, SOL_SOCKET, SO_KEEPALIVE, (const char *) &iOpt , sizeof( iOpt )); /* we'll be using a nonblocking function */ @@ -487,6 +502,8 @@ static int hb_socketConnect( HB_SOCKET_STRUCT *Socket ) hb_socketSetBlocking( Socket ); + hb_vmLock(); + return Socket->errorCode == 0; } @@ -532,7 +549,7 @@ HB_FUNC( HB_INETINIT ) #define HB_MKWORD( l, h ) ((WORD)(((BYTE)(l)) | (((WORD)((BYTE)(h))) << 8))) WSADATA wsadata; WSAStartup( HB_MKWORD(1,1), &wsadata ); - #elif defined( HB_OS_LINUX ) + #elif defined( HB_INET_LINUX_INTERRUPT ) signal( HB_INET_LINUX_INTERRUPT, hb_inetLinuxSigusrHandle ); #endif s_iSessions = 1; @@ -572,6 +589,8 @@ HB_FUNC( HB_INETCLOSE ) hb_errRT_BASE_SubstR( EG_ARG, 3012, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); else if( Socket->com != ( HB_SOCKET_T ) -1 ) { + hb_vmUnlock(); + #if defined( HB_OS_WIN_32 ) shutdown( Socket->com, SD_BOTH ); #elif defined(HB_OS_OS2) @@ -583,9 +602,11 @@ HB_FUNC( HB_INETCLOSE ) hb_retni( HB_INET_CLOSE( Socket->com ) ); Socket->com = ( HB_SOCKET_T ) -1; - #ifdef HB_OS_LINUX + #ifdef HB_INET_LINUX_INTERRUPT kill( 0, HB_INET_LINUX_INTERRUPT ); #endif + + hb_vmLock(); } else hb_retni( -1 ); @@ -913,6 +934,8 @@ static void s_inetRecvInternal( int iMode ) iMaxLen = iLen; } + hb_vmUnlock(); + iReceived = 0; iTimeElapsed = 0; HB_SOCKET_ZERO_ERROR( Socket ); @@ -934,6 +957,8 @@ static void s_inetRecvInternal( int iMode ) /* timed out; let's see if we have to run a cb routine */ iTimeElapsed += Socket->timeout; + hb_vmLock(); + /* if we have a caPeriodic, timeLimit is our REAL timeout */ if( Socket->caPeriodic ) { @@ -956,12 +981,16 @@ static void s_inetRecvInternal( int iMode ) hb_retni( iReceived ); return; } + + hb_vmUnlock(); } } while( iReceived < iMaxLen && iLen > 0 ); Socket->count = iReceived; + hb_vmLock(); + if( iLen == 0 ) { HB_SOCKET_SET_ERROR2( Socket, -2, "Connection closed" ); @@ -1030,6 +1059,8 @@ static void s_inetRecvPattern( const char *szPattern ) iMax = 0; } + hb_vmUnlock(); + HB_SOCKET_ZERO_ERROR( Socket ); Buffer = (char *) hb_xgrab( iBufferSize ); @@ -1053,9 +1084,15 @@ static void s_inetRecvPattern( const char *szPattern ) if( Socket->caPeriodic ) { + BOOL fResult; + + hb_vmLock(); hb_execFromArray( Socket->caPeriodic ); + fResult = hb_parl( -1 ); + hb_vmUnlock(); + /* do we continue? */ - if( hb_parl( -1 ) && + if( fResult && ( Socket->timelimit == -1 || iTimeElapsed < Socket->timelimit ) ) { continue; @@ -1083,6 +1120,8 @@ static void s_inetRecvPattern( const char *szPattern ) } while( iMax == 0 || iPos < iMax ); + hb_vmLock(); + if( iLen <= 0 ) { if( pResult ) @@ -1216,6 +1255,8 @@ HB_FUNC( HB_INETRECVENDBLOCK ) iBufferSize = pBufferSize ? hb_itemGetNI( pBufferSize ) : 80; iMax = pMaxSize ? hb_itemGetNI( pMaxSize ) : 0; + hb_vmUnlock(); + HB_SOCKET_ZERO_ERROR( Socket ); Buffer = (char *) hb_xgrab( iBufferSize ); @@ -1240,9 +1281,14 @@ HB_FUNC( HB_INETRECVENDBLOCK ) iTimeElapsed += Socket->timeout; if( Socket->caPeriodic ) { - hb_execFromArray( Socket->caPeriodic ); + BOOL fResult; - if( hb_parl( -1 ) && + hb_vmLock(); + hb_execFromArray( Socket->caPeriodic ); + fResult = hb_parl( -1 ); + hb_vmUnlock(); + + if( fResult && ( Socket->timelimit == -1 || iTimeElapsed < Socket->timelimit ) ) { continue; @@ -1259,12 +1305,12 @@ HB_FUNC( HB_INETRECVENDBLOCK ) for( protos = 0; protos < iprotos; protos++ ) { - if( cChar == Proto[protos][iprotosize[protos]-1] && iprotosize[protos] <= iPos ) + if( cChar == Proto[protos][iprotosize[protos] - 1] && iprotosize[protos] <= iPos ) { bProtoFound = 1; - for(iPosProto=0; iPosProto < (iprotosize[protos]-1); iPosProto++) + for( iPosProto = 0; iPosProto < ( iprotosize[protos] - 1 ); iPosProto++ ) { - if(Proto[protos][iPosProto] != Buffer[ (iPos-iprotosize[protos])+iPosProto+1 ]) + if( Proto[protos][iPosProto] != Buffer[ ( iPos - iprotosize[protos] ) + iPosProto + 1 ] ) { bProtoFound = 0; break; @@ -1277,21 +1323,18 @@ HB_FUNC( HB_INETRECVENDBLOCK ) } } } - - if(bProtoFound) - { + if( bProtoFound ) break; - } Buffer[ iPos++ ] = cChar; } else - { break; - } } while( iMax == 0 || iPos < iMax ); + hb_vmLock(); + if( iLen <= 0 ) { if( pResult ) @@ -1364,16 +1407,17 @@ HB_FUNC( HB_INETDATAREADY ) return; } - HB_SOCKET_ZERO_ERROR( Socket ); - - /* Watch our socket. */ - if( hb_pcount() > 1 ) + if( ISNUM( 1 ) ) { iVal = hb_parni( 2 ); tv.tv_sec = iVal / 1000; tv.tv_usec = (iVal % 1000) * 1000; } + hb_vmUnlock(); + + HB_SOCKET_ZERO_ERROR( Socket ); + FD_ZERO(&rfds); FD_SET(Socket->com, &rfds); @@ -1385,6 +1429,8 @@ HB_FUNC( HB_INETDATAREADY ) HB_SOCKET_SET_ERROR( Socket ); } + hb_vmLock(); + hb_retni( iVal ); } @@ -1416,6 +1462,8 @@ static void s_inetSendInternal( int iMode ) iSend = iLen; } + hb_vmUnlock(); + HB_SOCKET_ZERO_ERROR( Socket ); iSent = 0; @@ -1446,6 +1494,8 @@ static void s_inetSendInternal( int iMode ) Socket->count = iSent; + hb_vmLock(); + hb_retni( iLen > 0 ? iSent : -1 ); } @@ -1606,6 +1656,8 @@ HB_FUNC( HB_INETSERVER ) iListen = ISNUM( 3 ) ? hb_parni( 3 ) : 10; + hb_vmUnlock(); + if( bind( Socket->com, (struct sockaddr *) &Socket->remote, sizeof(Socket->remote) ) ) { HB_SOCKET_SET_ERROR( Socket ); @@ -1619,6 +1671,8 @@ HB_FUNC( HB_INETSERVER ) Socket->com = ( HB_SOCKET_T ) -1; } + hb_vmLock(); + if( pSocket ) hb_itemReturnRelease( pSocket ); else @@ -1653,6 +1707,8 @@ HB_FUNC( HB_INETACCEPT ) return; } + hb_vmUnlock(); + Len = sizeof( struct sockaddr_in ); /* @@ -1689,6 +1745,8 @@ HB_FUNC( HB_INETACCEPT ) iError = -1; } + hb_vmLock(); + if( iError == -1 ) { HB_SOCKET_SET_ERROR2( Socket, -1, "Timeout" ); @@ -1885,6 +1943,8 @@ HB_FUNC( HB_INETDGRAMBIND ) szAddress = hb_parc( 2 ); Socket->remote.sin_addr.s_addr = szAddress ? inet_addr( szAddress ) : INADDR_ANY; + hb_vmUnlock(); + if( bind( Socket->com, (struct sockaddr *) &Socket->remote, sizeof(Socket->remote) ) ) { HB_SOCKET_SET_ERROR( Socket ); @@ -1925,6 +1985,8 @@ HB_FUNC( HB_INETDGRAMBIND ) } } + hb_vmLock(); + hb_itemReturnRelease( pSocket ); } @@ -1998,6 +2060,8 @@ HB_FUNC( HB_INETDGRAMSEND ) iLen = iMaxLen; } + hb_vmUnlock(); + HB_SOCKET_ZERO_ERROR( Socket ); Socket->count = 0; @@ -2007,6 +2071,8 @@ HB_FUNC( HB_INETDGRAMSEND ) (const struct sockaddr *) &Socket->remote, sizeof( Socket->remote ) ); } + hb_vmLock(); + hb_retni( Socket->count ); if( Socket->count == 0 ) @@ -2060,6 +2126,8 @@ HB_FUNC( HB_INETDGRAMRECV ) iMaxLen = ( int ) hb_itemGetCLen( pBuffer ); } + hb_vmUnlock(); + HB_SOCKET_ZERO_ERROR( Socket ); do @@ -2074,10 +2142,12 @@ HB_FUNC( HB_INETDGRAMRECV ) iTimeElapsed += Socket->timeout; if( Socket->caPeriodic ) { + hb_vmLock(); hb_execFromArray( Socket->caPeriodic ); /* do we continue? */ fRepeat = hb_parl( -1 ) && ( Socket->timelimit == -1 || iTimeElapsed < Socket->timelimit ); + hb_vmUnlock(); } } while( fRepeat ); @@ -2102,6 +2172,9 @@ HB_FUNC( HB_INETDGRAMRECV ) { Socket->count = iLen; } + + hb_vmLock(); + hb_retni( iLen ); } diff --git a/harbour/source/vm/estack.c b/harbour/source/vm/estack.c index 4598991144..09e18dd281 100644 --- a/harbour/source/vm/estack.c +++ b/harbour/source/vm/estack.c @@ -380,6 +380,18 @@ void hb_stackSetQuitState( USHORT uiState ) { hb_stack.uiQuitState = uiState; } + +#undef hb_stackUnlock +int hb_stackUnlock( void ) +{ + return ++hb_stack.iUnlocked; +} + +#undef hb_stackLock +int hb_stackLock( void ) +{ + return --hb_stack.iUnlocked; +} #endif #undef hb_stackGetPrivateStack diff --git a/harbour/source/vm/hvm.c b/harbour/source/vm/hvm.c index 13bc3bdea9..808bbbe227 100644 --- a/harbour/source/vm/hvm.c +++ b/harbour/source/vm/hvm.c @@ -433,52 +433,58 @@ static void hb_vmRequestTest( void ) HB_VM_UNLOCK } -/* lock VM blocking GC execution by other threads */ -void hb_vmLock( void ) -{ - if( hb_stackId() ) /* check if thread has associated HVM stack */ - { - HB_VM_LOCK - while( TRUE ) - { - if( hb_vmThreadRequest & HB_THREQUEST_QUIT ) - { - if( !hb_stackQuitState() ) - { - hb_stackSetQuitState( TRUE ); - hb_stackSetActionRequest( HB_QUIT_REQUESTED ); - } - } - if( hb_vmThreadRequest & HB_THREQUEST_STOP ) - hb_threadCondWait( &s_vmCond, &s_vmMtx ); - else - break; - } - s_iRunningCount++; - HB_VM_UNLOCK - } -} - -/* unlock VM, allow GC execution */ +/* unlock VM, allow GC and other exclusive single task code execution */ void hb_vmUnlock( void ) { if( hb_stackId() ) /* check if thread has associated HVM stack */ { - HB_VM_LOCK - s_iRunningCount--; - if( hb_vmThreadRequest ) + if( hb_stackUnlock() == 1 ) { - if( hb_vmThreadRequest & HB_THREQUEST_QUIT ) + HB_VM_LOCK + s_iRunningCount--; + if( hb_vmThreadRequest ) { - if( !hb_stackQuitState() ) + if( hb_vmThreadRequest & HB_THREQUEST_QUIT ) { - hb_stackSetQuitState( TRUE ); - hb_stackSetActionRequest( HB_QUIT_REQUESTED ); + if( !hb_stackQuitState() ) + { + hb_stackSetQuitState( TRUE ); + hb_stackSetActionRequest( HB_QUIT_REQUESTED ); + } } + hb_threadCondBroadcast( &s_vmCond ); } - hb_threadCondBroadcast( &s_vmCond ); + HB_VM_UNLOCK + } + } +} + +/* lock VM blocking GC and other exclusive single task code execution */ +void hb_vmLock( void ) +{ + if( hb_stackId() ) /* check if thread has associated HVM stack */ + { + if( hb_stackLock() == 0 ) + { + HB_VM_LOCK + while( TRUE ) + { + if( hb_vmThreadRequest & HB_THREQUEST_QUIT ) + { + if( !hb_stackQuitState() ) + { + hb_stackSetQuitState( TRUE ); + hb_stackSetActionRequest( HB_QUIT_REQUESTED ); + } + } + if( hb_vmThreadRequest & HB_THREQUEST_STOP ) + hb_threadCondWait( &s_vmCond, &s_vmMtx ); + else + break; + } + s_iRunningCount++; + HB_VM_UNLOCK } - HB_VM_UNLOCK } }