* *
* partial sync with the 3.4 fork codebase. These are the things
synces for the most part:
- copyright headers
- grammar/typos in comments and some readmes
- comment/whitespace/decorations
- variable scoping in C files
- DO CASE/SWITCH and some other alternate syntax usage
- minimal amount of human readable text in strings
- minor code updates
- HB_TRACE() void * casts for pointers and few other changes to
avoid C compiler warnings
- various other, minor code cleanups
- only Harbour/C code/headers were touched in src, utils, contrib,
include. No 3rd party code, no make files, and with just a few
exceptions, no 'tests' code was touched.
- certain components were not touched were 3.4 diverged too much
already, like f.e. hbmk2, hbssl, hbcurl, hbexpat
- the goal was that no actual program logic should be altered by
these changes. Except some possible minor exceptions, any such
change is probably a bug in this patch.
It's a massive patch, if you find anything broken after it, please
open an Issue with the details. Build test was done on macOS.
The goal is make it easier to see what actual code/logic was changed
in 3.4 compared to 3.2 and to make patches easier to apply in both
ways.
757 lines
21 KiB
C
757 lines
21 KiB
C
/*
|
|
* Default RDD module
|
|
*
|
|
* Copyright 1999 Bruno Cantero <bruno@issnet.net>
|
|
* Copyright 2007 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file LICENSE.txt. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA (or visit https://www.gnu.org/licenses/).
|
|
*
|
|
* As a special exception, the Harbour Project gives permission for
|
|
* additional uses of the text contained in its release of Harbour.
|
|
*
|
|
* The exception is that, if you link the Harbour libraries with other
|
|
* files to produce an executable, this does not by itself cause the
|
|
* resulting executable to be covered by the GNU General Public License.
|
|
* Your use of that executable is in no way restricted on account of
|
|
* linking the Harbour library code into it.
|
|
*
|
|
* This exception does not however invalidate any other reasons why
|
|
* the executable file might be covered by the GNU General Public License.
|
|
*
|
|
* This exception applies only to the code released by the Harbour
|
|
* Project under the name Harbour. If you copy code from other
|
|
* Harbour Project or Free Software Foundation releases into a copy of
|
|
* Harbour, as the General Public License permits, the exception does
|
|
* not apply to the code that you add in this way. To avoid misleading
|
|
* anyone as to the status of such modified files, you must delete
|
|
* this exception notice from them.
|
|
*
|
|
* If you write modifications of your own for Harbour, it is your choice
|
|
* whether to permit this exception to apply to your modifications.
|
|
* If you do not wish that, delete this exception notice.
|
|
*
|
|
*/
|
|
|
|
#include "hbapi.h"
|
|
#include "hbapirdd.h"
|
|
#include "hbapiitm.h"
|
|
#include "hbapierr.h"
|
|
#include "hbvm.h"
|
|
#include "hbstack.h"
|
|
#include "hbthread.h"
|
|
|
|
|
|
#define HB_SET_WA( n ) \
|
|
do \
|
|
{ \
|
|
pRddInfo->uiCurrArea = n; \
|
|
pRddInfo->pCurrArea = ( ( pRddInfo->uiCurrArea < pRddInfo->uiWaNumMax ) ? \
|
|
pRddInfo->waList[ pRddInfo->waNums[ pRddInfo->uiCurrArea ] ] : \
|
|
NULL ); \
|
|
} while( 0 )
|
|
|
|
|
|
/*
|
|
* Insert new WorkArea node at current WA position
|
|
*/
|
|
static void hb_waNodeInsert( PHB_STACKRDD pRddInfo, AREAP pArea )
|
|
{
|
|
HB_USHORT uiWaPos;
|
|
|
|
if( pRddInfo->uiCurrArea >= pRddInfo->uiWaNumMax )
|
|
{
|
|
int iSize = ( ( ( int ) pRddInfo->uiCurrArea + 256 ) >> 8 ) << 8;
|
|
|
|
if( iSize > HB_RDD_MAX_AREA_NUM )
|
|
iSize = HB_RDD_MAX_AREA_NUM;
|
|
|
|
if( pRddInfo->uiWaNumMax == 0 )
|
|
pRddInfo->waNums = ( HB_USHORT * ) hb_xgrab( iSize * sizeof( HB_USHORT ) );
|
|
else
|
|
pRddInfo->waNums = ( HB_USHORT * ) hb_xrealloc( pRddInfo->waNums, iSize * sizeof( HB_USHORT ) );
|
|
|
|
memset( &pRddInfo->waNums[ pRddInfo->uiWaNumMax ], 0, ( iSize - pRddInfo->uiWaNumMax ) * sizeof( HB_USHORT ) );
|
|
pRddInfo->uiWaNumMax = ( HB_USHORT ) iSize;
|
|
}
|
|
|
|
if( pRddInfo->uiWaSpace == 0 )
|
|
{
|
|
pRddInfo->uiWaSpace = 256;
|
|
pRddInfo->waList = ( void ** ) hb_xgrabz( pRddInfo->uiWaSpace * sizeof( void * ) );
|
|
uiWaPos = 1;
|
|
pRddInfo->uiWaMax = 2;
|
|
}
|
|
else
|
|
{
|
|
uiWaPos = pRddInfo->uiWaMax++;
|
|
if( pRddInfo->uiWaMax > pRddInfo->uiWaSpace )
|
|
{
|
|
int iSize = ( ( ( int ) pRddInfo->uiWaMax + 256 ) >> 8 ) << 8;
|
|
|
|
if( iSize > HB_RDD_MAX_AREA_NUM )
|
|
iSize = HB_RDD_MAX_AREA_NUM;
|
|
|
|
pRddInfo->uiWaSpace = ( HB_USHORT ) iSize;
|
|
pRddInfo->waList = ( void ** ) hb_xrealloc( pRddInfo->waList, pRddInfo->uiWaSpace * sizeof( void * ) );
|
|
memset( &pRddInfo->waList[ pRddInfo->uiWaMax ], 0, ( pRddInfo->uiWaSpace - pRddInfo->uiWaMax ) * sizeof( void * ) );
|
|
}
|
|
while( uiWaPos > 1 )
|
|
{
|
|
if( ( ( AREAP ) pRddInfo->waList[ uiWaPos - 1 ] )->uiArea < pRddInfo->uiCurrArea )
|
|
break;
|
|
pRddInfo->waList[ uiWaPos ] = pRddInfo->waList[ uiWaPos - 1 ];
|
|
pRddInfo->waNums[ ( ( AREAP ) pRddInfo->waList[ uiWaPos ] )->uiArea ] = uiWaPos;
|
|
uiWaPos--;
|
|
}
|
|
}
|
|
pRddInfo->waNums[ pRddInfo->uiCurrArea ] = uiWaPos;
|
|
pRddInfo->pCurrArea = pRddInfo->waList[ uiWaPos ] = pArea;
|
|
pArea->uiArea = pRddInfo->uiCurrArea;
|
|
}
|
|
|
|
/*
|
|
* Remove current WorkArea node
|
|
*/
|
|
static void hb_waNodeDelete( PHB_STACKRDD pRddInfo )
|
|
{
|
|
HB_USHORT uiWaPos;
|
|
|
|
uiWaPos = pRddInfo->waNums[ pRddInfo->uiCurrArea ];
|
|
pRddInfo->waNums[ pRddInfo->uiCurrArea ] = 0;
|
|
pRddInfo->uiWaMax--;
|
|
if( pRddInfo->uiWaMax <= 1 )
|
|
{
|
|
pRddInfo->uiWaSpace = pRddInfo->uiWaMax = pRddInfo->uiWaNumMax = 0;
|
|
hb_xfree( pRddInfo->waList );
|
|
hb_xfree( pRddInfo->waNums );
|
|
pRddInfo->waList = NULL;
|
|
pRddInfo->waNums = NULL;
|
|
}
|
|
else
|
|
{
|
|
while( uiWaPos < pRddInfo->uiWaMax )
|
|
{
|
|
pRddInfo->waList[ uiWaPos ] = pRddInfo->waList[ uiWaPos + 1 ];
|
|
pRddInfo->waNums[ ( ( AREAP ) pRddInfo->waList[ uiWaPos ] )->uiArea ] = uiWaPos;
|
|
uiWaPos++;
|
|
}
|
|
pRddInfo->waList[ pRddInfo->uiWaMax ] = NULL;
|
|
if( pRddInfo->uiWaSpace - pRddInfo->uiWaMax > 256 )
|
|
{
|
|
int iSize = ( ( ( int ) pRddInfo->uiWaMax + 256 ) >> 8 ) << 8;
|
|
|
|
if( iSize > HB_RDD_MAX_AREA_NUM )
|
|
iSize = HB_RDD_MAX_AREA_NUM;
|
|
|
|
pRddInfo->uiWaSpace = ( HB_USHORT ) iSize;
|
|
pRddInfo->waList = ( void ** ) hb_xrealloc( pRddInfo->waList, pRddInfo->uiWaSpace * sizeof( void * ) );
|
|
}
|
|
}
|
|
pRddInfo->pCurrArea = NULL;
|
|
}
|
|
|
|
/*
|
|
* Return the next free WorkArea for later use.
|
|
*/
|
|
HB_ERRCODE hb_rddSelectFirstAvailable( void )
|
|
{
|
|
PHB_STACKRDD pRddInfo;
|
|
HB_USHORT uiArea;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddSelectFirstAvailable()" ) );
|
|
|
|
pRddInfo = hb_stackRDD();
|
|
|
|
uiArea = 1;
|
|
while( uiArea < pRddInfo->uiWaNumMax )
|
|
{
|
|
if( pRddInfo->waNums[ uiArea ] == 0 )
|
|
break;
|
|
uiArea++;
|
|
}
|
|
if( uiArea >= HB_RDD_MAX_AREA_NUM )
|
|
return HB_FAILURE;
|
|
HB_SET_WA( uiArea );
|
|
return HB_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Create and insert the new WorkArea node
|
|
*/
|
|
HB_USHORT hb_rddInsertAreaNode( const char * szDriver )
|
|
{
|
|
PHB_STACKRDD pRddInfo;
|
|
LPRDDNODE pRddNode;
|
|
HB_USHORT uiRddID;
|
|
AREAP pArea;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddInsertAreaNode(%s)", szDriver ) );
|
|
|
|
pRddInfo = hb_stackRDD();
|
|
if( pRddInfo->uiCurrArea && pRddInfo->pCurrArea )
|
|
return 0;
|
|
|
|
pRddNode = hb_rddFindNode( szDriver, &uiRddID );
|
|
if( ! pRddNode )
|
|
return 0;
|
|
|
|
if( pRddInfo->uiCurrArea == 0 )
|
|
{
|
|
if( hb_rddSelectFirstAvailable() != HB_SUCCESS )
|
|
return 0;
|
|
}
|
|
|
|
pArea = ( AREAP ) hb_rddNewAreaNode( pRddNode, uiRddID );
|
|
if( ! pArea )
|
|
return 0;
|
|
|
|
hb_waNodeInsert( pRddInfo, pArea );
|
|
|
|
return pRddInfo->uiCurrArea;
|
|
}
|
|
|
|
/*
|
|
* Closes and releases the current WorkArea preparing it
|
|
* to be used with a new database.
|
|
*/
|
|
void hb_rddReleaseCurrentArea( void )
|
|
{
|
|
PHB_STACKRDD pRddInfo;
|
|
AREAP pArea;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddReleaseCurrentArea()" ) );
|
|
|
|
pRddInfo = hb_stackRDD();
|
|
pArea = ( AREAP ) pRddInfo->pCurrArea;
|
|
if( ! pArea )
|
|
return;
|
|
|
|
if( SELF_CLOSE( pArea ) == HB_FAILURE )
|
|
return;
|
|
|
|
SELF_RELEASE( pArea );
|
|
|
|
hb_waNodeDelete( pRddInfo );
|
|
}
|
|
|
|
/*
|
|
* Closes all WorkAreas.
|
|
*/
|
|
void hb_rddCloseAll( void )
|
|
{
|
|
PHB_STACKRDD pRddInfo;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddCloseAll()" ) );
|
|
|
|
pRddInfo = hb_stackRDD();
|
|
if( pRddInfo->uiWaMax > 0 )
|
|
{
|
|
HB_BOOL isParents, isFinish = HB_FALSE;
|
|
AREAP pArea;
|
|
HB_USHORT uiIndex;
|
|
|
|
do
|
|
{
|
|
isParents = HB_FALSE;
|
|
for( uiIndex = 1; uiIndex < pRddInfo->uiWaMax; uiIndex++ )
|
|
{
|
|
pArea = ( AREAP ) pRddInfo->waList[ uiIndex ];
|
|
HB_SET_WA( pArea->uiArea );
|
|
if( isFinish )
|
|
{
|
|
SELF_RELEASE( pArea );
|
|
pRddInfo->waNums[ pRddInfo->uiCurrArea ] = 0;
|
|
pRddInfo->pCurrArea = NULL;
|
|
}
|
|
else if( pArea->uiParents )
|
|
{
|
|
isParents = HB_TRUE;
|
|
}
|
|
else
|
|
{
|
|
SELF_CLOSE( pArea );
|
|
}
|
|
}
|
|
if( ! isParents && ! isFinish )
|
|
{
|
|
isParents = isFinish = HB_TRUE;
|
|
}
|
|
}
|
|
while( isParents );
|
|
|
|
pRddInfo->uiWaSpace = pRddInfo->uiWaMax = pRddInfo->uiWaNumMax = 0;
|
|
hb_xfree( pRddInfo->waList );
|
|
hb_xfree( pRddInfo->waNums );
|
|
pRddInfo->waList = NULL;
|
|
pRddInfo->waNums = NULL;
|
|
HB_SET_WA( 1 );
|
|
}
|
|
}
|
|
|
|
void hb_rddFlushAll( void )
|
|
{
|
|
PHB_STACKRDD pRddInfo = hb_stackRDD();
|
|
HB_USHORT uiArea = ( HB_AREANO ) hb_rddGetCurrentWorkAreaNumber(), uiIndex;
|
|
|
|
for( uiIndex = 1; uiIndex < pRddInfo->uiWaMax; ++uiIndex )
|
|
{
|
|
hb_rddSelectWorkAreaNumber( ( ( AREAP ) pRddInfo->waList[ uiIndex ] )->uiArea );
|
|
SELF_FLUSH( ( AREAP ) pRddInfo->pCurrArea );
|
|
}
|
|
hb_rddSelectWorkAreaNumber( uiArea );
|
|
}
|
|
|
|
void hb_rddUnLockAll( void )
|
|
{
|
|
PHB_STACKRDD pRddInfo = hb_stackRDD();
|
|
HB_USHORT uiArea = ( HB_AREANO ) hb_rddGetCurrentWorkAreaNumber(), uiIndex;
|
|
|
|
for( uiIndex = 1; uiIndex < pRddInfo->uiWaMax; ++uiIndex )
|
|
{
|
|
hb_rddSelectWorkAreaNumber( ( ( AREAP ) pRddInfo->waList[ uiIndex ] )->uiArea );
|
|
SELF_UNLOCK( ( AREAP ) pRddInfo->pCurrArea, NULL );
|
|
}
|
|
hb_rddSelectWorkAreaNumber( uiArea );
|
|
}
|
|
|
|
/*
|
|
* call a pCallBack function with all open workareas ###
|
|
*/
|
|
HB_ERRCODE hb_rddIterateWorkAreas( WACALLBACK pCallBack, void * cargo )
|
|
{
|
|
PHB_STACKRDD pRddInfo;
|
|
HB_ERRCODE errCode = HB_SUCCESS;
|
|
HB_USHORT uiIndex;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddIterateWorkAreas(%p, %p)", ( void * ) pCallBack, cargo ) );
|
|
|
|
pRddInfo = hb_stackRDD();
|
|
for( uiIndex = 1; uiIndex < pRddInfo->uiWaMax; uiIndex++ )
|
|
{
|
|
AREAP pArea = ( AREAP ) pRddInfo->waList[ uiIndex ];
|
|
errCode = pCallBack( pArea, cargo );
|
|
if( errCode != HB_SUCCESS )
|
|
break;
|
|
if( uiIndex >= pRddInfo->uiWaMax ||
|
|
pArea != ( AREAP ) pRddInfo->waList[ uiIndex ] )
|
|
uiIndex--;
|
|
}
|
|
return errCode;
|
|
}
|
|
|
|
HB_BOOL hb_rddGetNetErr( void )
|
|
{
|
|
return hb_stackRDD()->fNetError;
|
|
}
|
|
|
|
void hb_rddSetNetErr( HB_BOOL fNetErr )
|
|
{
|
|
hb_stackRDD()->fNetError = fNetErr;
|
|
}
|
|
|
|
/*
|
|
* Get (/set) default RDD driver
|
|
*/
|
|
const char * hb_rddDefaultDrv( const char * szDriver )
|
|
{
|
|
PHB_STACKRDD pRddInfo;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddDefaultDrv(%s)", szDriver ) );
|
|
|
|
pRddInfo = hb_stackRDD();
|
|
|
|
if( szDriver && *szDriver )
|
|
{
|
|
char szNewDriver[ HB_RDD_MAX_DRIVERNAME_LEN + 1 ];
|
|
LPRDDNODE pRddNode;
|
|
|
|
hb_strncpyUpper( szNewDriver, szDriver, sizeof( szNewDriver ) - 1 );
|
|
pRddNode = hb_rddFindNode( szNewDriver, NULL );
|
|
if( ! pRddNode )
|
|
return NULL;
|
|
|
|
pRddInfo->szDefaultRDD = pRddNode->szName;
|
|
}
|
|
else if( ! pRddInfo->szDefaultRDD && hb_rddGetNode( 0 ) )
|
|
{
|
|
const char * szDrvTable[] = { "DBFNTX", "DBFCDX", "DBFFPT", "DBF" };
|
|
int i;
|
|
|
|
pRddInfo->szDefaultRDD = "";
|
|
for( i = 0; i < ( int ) HB_SIZEOFARRAY( szDrvTable ); ++i )
|
|
{
|
|
if( hb_rddFindNode( szDrvTable[ i ], NULL ) )
|
|
{
|
|
pRddInfo->szDefaultRDD = szDrvTable[ i ];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return pRddInfo->szDefaultRDD;
|
|
}
|
|
|
|
/*
|
|
* Get default RDD driver respecting passed table/file name
|
|
*/
|
|
const char * hb_rddFindDrv( const char * szDriver, const char * szFileName )
|
|
{
|
|
LPRDDNODE pRddNode = NULL;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddFindDrv(%s, %s)", szDriver, szFileName ) );
|
|
|
|
if( szDriver && *szDriver )
|
|
{
|
|
char szNewDriver[ HB_RDD_MAX_DRIVERNAME_LEN + 1 ];
|
|
|
|
hb_strncpyUpper( szNewDriver, szDriver, sizeof( szNewDriver ) - 1 );
|
|
pRddNode = hb_rddFindNode( szNewDriver, NULL );
|
|
}
|
|
else
|
|
{
|
|
PHB_STACKRDD pRddInfo = hb_stackRDD();
|
|
|
|
if( pRddInfo->szDefaultRDD )
|
|
{
|
|
if( pRddInfo->szDefaultRDD[ 0 ] )
|
|
pRddNode = hb_rddFindNode( pRddInfo->szDefaultRDD, NULL );
|
|
}
|
|
else if( hb_rddGetNode( 0 ) )
|
|
{
|
|
const char * szDrvTable[] = { "DBFNTX", "DBFCDX", "DBFFPT", "DBF" };
|
|
int i;
|
|
|
|
pRddInfo->szDefaultRDD = "";
|
|
for( i = 0; i < ( int ) HB_SIZEOFARRAY( szDrvTable ); ++i )
|
|
{
|
|
pRddNode = hb_rddFindNode( szDrvTable[ i ], NULL );
|
|
if( pRddNode )
|
|
{
|
|
pRddInfo->szDefaultRDD = szDrvTable[ i ];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return pRddNode ? hb_rddFindFileNode( pRddNode, szFileName )->szName : NULL;
|
|
}
|
|
|
|
/*
|
|
* Function for getting given workarea pointer
|
|
*/
|
|
void * hb_rddGetWorkAreaPointer( int iArea )
|
|
{
|
|
PHB_STACKRDD pRddInfo;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddGetWorkAreaPointer(%d)", iArea ) );
|
|
|
|
pRddInfo = hb_stackRDD();
|
|
|
|
if( iArea == 0 )
|
|
return pRddInfo->pCurrArea;
|
|
else if( iArea >= 1 && ( HB_UINT ) iArea < ( HB_UINT ) pRddInfo->uiWaNumMax )
|
|
return pRddInfo->waList[ pRddInfo->waNums[ iArea ] ];
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Function for getting current workarea pointer
|
|
*/
|
|
void * hb_rddGetCurrentWorkAreaPointer( void )
|
|
{
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddGetCurrentWorkAreaPointer()" ) );
|
|
|
|
return hb_stackRDD()->pCurrArea;
|
|
}
|
|
|
|
/*
|
|
* Return the current WorkArea number.
|
|
*/
|
|
int hb_rddGetCurrentWorkAreaNumber( void )
|
|
{
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddGetCurrentWorkAreaNumber()" ) );
|
|
|
|
return hb_stackRDD()->uiCurrArea;
|
|
}
|
|
|
|
/*
|
|
* Select a WorkArea by the number.
|
|
*/
|
|
HB_ERRCODE hb_rddSelectWorkAreaNumber( int iArea )
|
|
{
|
|
PHB_STACKRDD pRddInfo;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddSelectWorkAreaNumber(%d)", iArea ) );
|
|
|
|
pRddInfo = hb_stackRDD();
|
|
if( iArea < 1 || iArea > HB_RDD_MAX_AREA_NUM )
|
|
HB_SET_WA( 0 );
|
|
else
|
|
HB_SET_WA( ( HB_AREANO ) iArea );
|
|
|
|
return ( pRddInfo->pCurrArea == NULL ) ? HB_FAILURE : HB_SUCCESS;
|
|
}
|
|
|
|
|
|
/* Moving workareas between threads */
|
|
|
|
static HB_CRITICAL_NEW( s_waMtx );
|
|
static HB_COND_NEW( s_waCond );
|
|
static PHB_ITEM s_pDetachedAreas = NULL;
|
|
|
|
static HB_GARBAGE_FUNC( hb_waHolderDestructor )
|
|
{
|
|
AREAP * pHolder = ( AREAP * ) Cargo;
|
|
|
|
if( *pHolder )
|
|
{
|
|
AREAP pArea;
|
|
int iArea;
|
|
|
|
pArea = *pHolder;
|
|
*pHolder = NULL;
|
|
|
|
iArea = hb_rddGetCurrentWorkAreaNumber();
|
|
|
|
if( hb_rddSelectFirstAvailable() != HB_SUCCESS )
|
|
/* workarea number HB_RDD_MAX_AREA_NUM is reserved
|
|
for this destructor and used when all other workareas
|
|
are active [druzus] */
|
|
hb_rddSelectWorkAreaNumber( HB_RDD_MAX_AREA_NUM );
|
|
hb_waNodeInsert( hb_stackRDD(), pArea );
|
|
hb_rddReleaseCurrentArea();
|
|
|
|
hb_rddSelectWorkAreaNumber( iArea );
|
|
}
|
|
}
|
|
|
|
static const HB_GC_FUNCS s_gcWAFuncs =
|
|
{
|
|
hb_waHolderDestructor,
|
|
hb_gcDummyMark
|
|
};
|
|
|
|
void hb_rddCloseDetachedAreas( void )
|
|
{
|
|
PHB_ITEM pDetachedArea;
|
|
|
|
/* protect by critical section access to s_pDetachedAreas array */
|
|
hb_threadEnterCriticalSectionGC( &s_waMtx );
|
|
pDetachedArea = s_pDetachedAreas;
|
|
s_pDetachedAreas = NULL;
|
|
/* leave critical section */
|
|
hb_threadLeaveCriticalSection( &s_waMtx );
|
|
/* release detached areas */
|
|
if( pDetachedArea )
|
|
hb_itemRelease( pDetachedArea );
|
|
}
|
|
|
|
HB_ERRCODE hb_rddDetachArea( AREAP pArea, PHB_ITEM pCargo )
|
|
{
|
|
AREAP * pHolder;
|
|
PHB_ITEM pDetachedArea;
|
|
HB_SIZE nPos;
|
|
int iArea;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddDetachArea(%p, %p)", ( void * ) pArea, ( void * ) pCargo ) );
|
|
|
|
/* save current WA number */
|
|
iArea = hb_rddGetCurrentWorkAreaNumber();
|
|
/* select given WA */
|
|
hb_rddSelectWorkAreaNumber( pArea->uiArea );
|
|
/* flush buffers */
|
|
SELF_GOCOLD( pArea );
|
|
|
|
/* tests shows that Xbase++ does not remove locks */
|
|
/* SELF_UNLOCK( pArea, NULL ); */
|
|
|
|
/* Xbase++ documentation says that child areas are also detached but
|
|
* but tests shows that it's not true and either child or parent relations
|
|
* are still active and corresponding WA are not detached together.
|
|
* Harbour clears all child and parent relations.
|
|
*/
|
|
SELF_CLEARREL( pArea );
|
|
hb_rddCloseAllParentRelations( pArea );
|
|
|
|
/* detach WA and alias */
|
|
hb_waNodeDelete( hb_stackRDD() );
|
|
pArea->uiArea = 0;
|
|
if( pArea->atomAlias )
|
|
hb_dynsymSetAreaHandle( ( PHB_DYNS ) pArea->atomAlias, 0 );
|
|
|
|
/* restore previous WA number */
|
|
hb_rddSelectWorkAreaNumber( iArea );
|
|
|
|
/* protect by critical section access to s_pDetachedAreas array */
|
|
hb_threadEnterCriticalSectionGC( &s_waMtx );
|
|
if( ! s_pDetachedAreas )
|
|
{
|
|
s_pDetachedAreas = hb_itemArrayNew( 1 );
|
|
nPos = 1;
|
|
}
|
|
else
|
|
{
|
|
nPos = hb_arrayLen( s_pDetachedAreas ) + 1;
|
|
hb_arraySize( s_pDetachedAreas, nPos );
|
|
}
|
|
pDetachedArea = hb_arrayGetItemPtr( s_pDetachedAreas, nPos );
|
|
hb_arrayNew( pDetachedArea, 2 );
|
|
if( pCargo )
|
|
hb_arraySet( pDetachedArea, 2, pCargo );
|
|
pHolder = ( AREAP * ) hb_gcAllocate( sizeof( AREAP ), &s_gcWAFuncs );
|
|
*pHolder = pArea;
|
|
hb_arraySetPtrGC( pDetachedArea, 1, pHolder );
|
|
/* siagnal waiting processes that new area is available */
|
|
hb_threadCondBroadcast( &s_waCond );
|
|
/* leave critical section */
|
|
hb_threadLeaveCriticalSection( &s_waMtx );
|
|
|
|
return HB_SUCCESS;
|
|
}
|
|
|
|
AREAP hb_rddRequestArea( const char * szAlias, PHB_ITEM pCargo,
|
|
HB_BOOL fNewArea, HB_ULONG ulMilliSec )
|
|
{
|
|
PHB_DYNS pSymAlias = NULL;
|
|
AREAP pArea = NULL;
|
|
|
|
if( pCargo )
|
|
hb_itemClear( pCargo );
|
|
|
|
/* close current WA or chose 1st free available */
|
|
if( ! fNewArea )
|
|
{
|
|
hb_rddReleaseCurrentArea();
|
|
}
|
|
else if( hb_rddSelectFirstAvailable() != HB_SUCCESS )
|
|
{
|
|
hb_errRT_DBCMD( EG_ARG, EDBCMD_BADPARAMETER, NULL, HB_ERR_FUNCNAME );
|
|
return NULL;
|
|
}
|
|
|
|
if( szAlias )
|
|
{
|
|
pSymAlias = hb_dynsymGet( szAlias );
|
|
|
|
/* verify if the alias name is valid symbol */
|
|
if( hb_rddVerifyAliasName( szAlias ) != HB_SUCCESS )
|
|
{
|
|
hb_errRT_DBCMD_Ext( EG_BADALIAS, EDBCMD_BADALIAS, NULL, szAlias, EF_CANDEFAULT );
|
|
return NULL;
|
|
}
|
|
/* verify if the alias is already in use */
|
|
if( hb_dynsymAreaHandle( pSymAlias ) != 0 )
|
|
{
|
|
hb_errRT_DBCMD_Ext( EG_DUPALIAS, EDBCMD_DUPALIAS, NULL, szAlias, EF_CANDEFAULT );
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* protect by critical section access to s_pDetachedAreas array */
|
|
hb_threadEnterCriticalSectionGC( &s_waMtx );
|
|
for( ;; )
|
|
{
|
|
if( s_pDetachedAreas )
|
|
{
|
|
HB_SIZE nLen = hb_arrayLen( s_pDetachedAreas ), nPos = 1;
|
|
if( pSymAlias )
|
|
{
|
|
for( nPos = 1; nPos <= nLen; ++nPos )
|
|
{
|
|
AREAP * pDetachedArea = ( AREAP * )
|
|
hb_arrayGetPtrGC( hb_arrayGetItemPtr( s_pDetachedAreas, nPos ),
|
|
1, &s_gcWAFuncs );
|
|
if( pSymAlias == ( PHB_DYNS ) ( *pDetachedArea )->atomAlias )
|
|
break;
|
|
}
|
|
}
|
|
if( nPos <= nLen )
|
|
{
|
|
PHB_ITEM pArray = hb_arrayGetItemPtr( s_pDetachedAreas, nPos );
|
|
AREAP * pDetachedArea = ( AREAP * )
|
|
hb_arrayGetPtrGC( pArray, 1, &s_gcWAFuncs );
|
|
|
|
pArea = *pDetachedArea;
|
|
*pDetachedArea = NULL;
|
|
if( pCargo )
|
|
hb_arrayGet( pArray, 2, pCargo );
|
|
hb_arrayDel( s_pDetachedAreas, nPos );
|
|
hb_arraySize( s_pDetachedAreas, nLen - 1 );
|
|
}
|
|
}
|
|
|
|
if( pArea || ulMilliSec == 0 )
|
|
break;
|
|
|
|
hb_vmUnlock();
|
|
/* wait for detached workareas */
|
|
if( ulMilliSec == HB_THREAD_INFINITE_WAIT )
|
|
hb_threadCondWait( &s_waCond, &s_waMtx );
|
|
else if( ! hb_threadCondTimedWait( &s_waCond, &s_waMtx, ulMilliSec ) )
|
|
ulMilliSec = 0;
|
|
hb_vmLock();
|
|
|
|
if( ulMilliSec == 0 || hb_vmRequestQuery() != 0 )
|
|
break;
|
|
}
|
|
/* leave critical section */
|
|
hb_threadLeaveCriticalSection( &s_waMtx );
|
|
|
|
/* attach WA and set alias */
|
|
if( pArea )
|
|
{
|
|
hb_waNodeInsert( hb_stackRDD(), pArea );
|
|
if( pArea->atomAlias )
|
|
{
|
|
if( hb_dynsymAreaHandle( ( PHB_DYNS ) pArea->atomAlias ) == 0 )
|
|
hb_dynsymSetAreaHandle( ( PHB_DYNS ) pArea->atomAlias, pArea->uiArea );
|
|
}
|
|
}
|
|
|
|
return pArea;
|
|
}
|
|
|
|
PHB_ITEM hb_rddDetachedList( void )
|
|
{
|
|
PHB_ITEM pArray;
|
|
|
|
HB_TRACE( HB_TR_DEBUG, ( "hb_rddDetachedList()" ) );
|
|
|
|
pArray = hb_itemArrayNew( 0 );
|
|
/* protect by critical section access to s_pDetachedAreas array */
|
|
hb_threadEnterCriticalSectionGC( &s_waMtx );
|
|
if( s_pDetachedAreas )
|
|
{
|
|
HB_SIZE nLen = hb_arrayLen( s_pDetachedAreas ), nPos;
|
|
|
|
hb_arraySize( pArray, nLen );
|
|
for( nPos = 1; nPos <= nLen; ++nPos )
|
|
{
|
|
AREAP * pDetachedArea = ( AREAP * )
|
|
hb_arrayGetPtrGC( hb_arrayGetItemPtr( s_pDetachedAreas, nPos ),
|
|
1, &s_gcWAFuncs );
|
|
PHB_DYNS pAlias = ( PHB_DYNS ) ( *pDetachedArea )->atomAlias;
|
|
hb_arraySetC( pArray, nPos, hb_dynsymName( pAlias ) );
|
|
}
|
|
}
|
|
/* leave critical section */
|
|
hb_threadLeaveCriticalSection( &s_waMtx );
|
|
|
|
return pArray;
|
|
}
|