* harbour/include/hbstack.h
% enable assembler inline function to access HVM thread stack pointer
without native compiler TLS support even if HB_STACK_PRELOAD is not
defined in MinGW builds. It gives some additional small speed
improvement in MT mode
* harbour/source/rtl/idle.c
* unlock HVM inside hb_releaseCPU() function
* harbour/contrib/hbwin/win_ole.c
! fixed casting and C++ compilation in some compilers
* harbour/include/Makefile
+ harbour/contrib/examples/rdddbt/hbrdddbt.h
- harbour/include/hbrdddbt.h
! moved hbrdddbt.h to correct location
* harbour/include/Makefile
! added missinf hbthread.h
* harbour/tests/rddtest/rddmktst.prg
* harbour/tests/rddtest/adscl52.prg
* harbour/tests/rddtest/adscl53.prg
* harbour/tests/rddtest/ntxcl52.prg
* harbour/tests/rddtest/ntxcl53.prg
* harbour/tests/rddtest/cdxcl52.prg
* harbour/tests/rddtest/rddtst.prg
* harbour/tests/rddtest/cdxcl53.prg
! fixed description in header I wrongly copied without updating
from other files
+ harbour/tests/hsxtest.prg
+ added test code for HiPer-SEEK indexes
* harbour/source/rtl/filesys.c
+ added new functions: hb_fsExtName(), hb_fsReadAt(), hb_fsWriteAt(),
hb_fsTruncAt() to use with shared file handles.
Please test it in other *nixes. I used pread[64]()/pwrite[64]()
POSIX functions but I do not know if they are available by default
in other supported platforms like MacOSX, BSD, HPUX, SunOS.
If not they I will have to implement some workaround.
* harbour/common.mak
* harbour/source/rtl/Makefile
* harbour/include/hbapifs.h
+ harbour/source/rtl/filebuf.c
+ added set of new file functions (hb_file*()) which are designed to
use with shared file handles and locks (buffers in the future):
hb_fileExtOpen(), hb_fileCreateTemp(), hb_fileClose(), hb_fileLock(),
hb_fileReadAt(), hb_fileWriteAt(), hb_fileTruncAt(), hb_fileSize(),
hb_fileCommit(), hb_fileHandle()
These functions operate on PHB_FILE structure instead of HB_FHANDLE.
Now in POSIX systems they share file handle between aliased or
simultaneously open by other thread work areas. It resolves the
problem with releasing all process FCNTL locks by any close()
operation even on duplicated or open() separately handle.
Now DOS deny flags emulation works in single process even if
BSD locks are disabled (non Linux *nixes).
They also keep internal file lock list what allows to synchronize
threads and aliases with file locks in POSIX systems. In the future
it will be used also for internal locking to synchronize threads
without OS level locks - pseudo exclusive mode in cloned WA.
Finally these structures will be used also for file buffers
which will be shared between aliased WA and threads.
* harbour/include/hbrdddbf.h
* harbour/include/hbrddcdx.h
* harbour/include/hbrddntx.h
* harbour/include/hbrdddel.h
* harbour/include/hbrddsdf.h
* harbour/source/rdd/dbf1.c
* harbour/source/rdd/delim1.c
* harbour/source/rdd/sdf1.c
* harbour/source/rdd/dbffpt/dbffpt1.c
* harbour/source/rdd/dbfntx/dbfntx1.c
* harbour/source/rdd/dbfcdx/dbfcdx1.c
* harbour/source/rdd/hsx/hsx.c
* harbour/contrib/hbbmcdx/bmdbfcdx.c
* harbour/contrib/hbbmcdx/hbbmcdx.h
* use PHB_FILE and hb_file*() functions instead of HB_FHANDLE (hb_fs*())
to access files.
+ harbour/tests/aliaslck.prg
+ added test code for file lock synchronization between aliased
work areas
260 lines
5.4 KiB
Plaintext
260 lines
5.4 KiB
Plaintext
/*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* Harbour Project source code:
|
|
* RDD tests
|
|
*
|
|
* Copyright 2008 Przemyslaw Czerpak <druzus / at / priv.onet.pl>
|
|
* www - http://www.harbour-project.org
|
|
*
|
|
*/
|
|
|
|
//#define _TEST_CREATE_
|
|
|
|
#ifndef N_LOOP
|
|
#define N_LOOP 15
|
|
#endif
|
|
|
|
#ifndef EOL
|
|
#define EOL chr(13)+chr(10)
|
|
#endif
|
|
|
|
#command ? => outstd(EOL)
|
|
#command ? <xx,...> => outstd(<xx>, EOL)
|
|
#command ?? =>
|
|
#command ?? <xx,...> => outstd(<xx>)
|
|
|
|
//#command RDDTEST <x> => rdd_test( <x> )
|
|
//#command RDDTEST <f>, <r>, <x> => rdd_test( #<f>, <{f}>, <r>, <x> )
|
|
|
|
#ifdef _TEST_CREATE_
|
|
#command RDDTESTC <*x*> => <x>; rddtst_wr( #<x> )
|
|
#command RDDTESTF <x> => rddtst_wr( #<x>, <x> )
|
|
#command RDDTEST <*x*> => RDDTESTC <x>
|
|
#command RDDTEST <x> => RDDTESTF <x>
|
|
#else
|
|
#command RDDTESTC <s>, <*x*> => <x>; rddtst_tst( #<x>, <s> )
|
|
#command RDDTESTF <r>, <s>, <x> => rddtst_tst( #<x>, <s>, <x>, <r> )
|
|
//#command RDDTEST <s>, <*x*> => RDDTESTC <x>
|
|
#endif
|
|
#define _DBNAME "_tst"
|
|
|
|
REQUEST DBFCDX
|
|
field FSTR, FNUM
|
|
|
|
#ifdef _TEST_CREATE_
|
|
static hMake := -1
|
|
#endif
|
|
static nTested := 0
|
|
static nErrors := 0
|
|
|
|
/* list of functions which may return unexpected value in Clipper
|
|
instead of documented NIL. If you will find others please add them */
|
|
static aBadRetFunc:={ "DBSKIP", "DBGOTO", "DBDELETE", "DBRECALL", ;
|
|
"DBUNLOCK", "DBCOMMIT" }
|
|
|
|
#ifdef _TEST_SCOPE_
|
|
#include "ord.ch"
|
|
#include "dbinfo.ch"
|
|
#endif
|
|
|
|
#ifdef __HARBOUR__
|
|
#ifdef _TEST_ADS_
|
|
#include "ads.ch"
|
|
REQUEST ADS
|
|
init proc adstest_init()
|
|
rddRegister( "ADS", 1 )
|
|
AdsSetServerType( ADS_LOCAL_SERVER )
|
|
//__rddSetDefault( "ADS" )
|
|
return
|
|
#endif
|
|
#endif
|
|
|
|
//REQUEST DBSEEK, DBGOTO, DBGOTOP, DBGOBOTTOM, ORDSETFOCUS, ORDSCOPE
|
|
|
|
#ifdef _TEST_CREATE_
|
|
function main(cOutFile, rdd)
|
|
test_init(rdd,cOutFile)
|
|
test_main()
|
|
test_close()
|
|
return nil
|
|
#else
|
|
function main(rdd)
|
|
test_init(rdd)
|
|
test_main()
|
|
test_close()
|
|
return nil
|
|
#endif
|
|
|
|
static function test_init(rdd,cOutFile)
|
|
local n, cOut, aDb:={{"FSTR", "C", 10, 0},{"FNUM", "N", 10, 0}}
|
|
|
|
if empty(rdd)
|
|
#ifdef _TESTRDD
|
|
rdd:=_TESTRDD
|
|
#else
|
|
rdd:="DBFCDX"
|
|
#endif
|
|
endif
|
|
rddSetDefault(rdd)
|
|
#ifdef _TEST_CREATE_
|
|
if empty(cOutFile)
|
|
? "Syntax: <outfile.prg> [<rddname>]"
|
|
quit
|
|
elseif (hMake:=fcreate(cOutFile))==-1
|
|
? "Cannot create file: ", cOutFile
|
|
quit
|
|
endif
|
|
cOut:=""
|
|
#ifdef _TEST_ADS_
|
|
cOut+='#define _TEST_ADS_'+EOL
|
|
#endif
|
|
cOut+=;
|
|
'REQUEST '+rdd+EOL+;
|
|
'#define _TESTRDD "'+rdd+'"'+EOL+;
|
|
'#include "rddtst.prg"'+EOL+;
|
|
EOL+;
|
|
'FUNCTION test_main()'+EOL+;
|
|
EOL
|
|
if !fwrite(hMake, cOut)==len(cOut)
|
|
? "write error."
|
|
quit
|
|
endif
|
|
#endif
|
|
|
|
aeval(directory("./"+_DBNAME+".??x"),{|x|ferase(x[1])})
|
|
aeval(directory("./TG_?.??x"),{|x|ferase(x[1])})
|
|
ferase("./"+_DBNAME+".dbf")
|
|
? "RDD: "+rdd
|
|
? "creating databse and index..."
|
|
dbcreate(_DBNAME, aDb)
|
|
/*
|
|
use _DBNAME shared
|
|
|
|
for n:=1 to N_LOOP
|
|
dbappend()
|
|
replace FNUM with int((n+2)/3)
|
|
replace FSTR with chr(FNUM+48)
|
|
//? FNUM, FSTR, recno(), eof(), bof()
|
|
next
|
|
dbcommit()
|
|
dbunlock()
|
|
*/
|
|
return nil
|
|
|
|
|
|
static function test_close()
|
|
local cOut
|
|
#ifdef _TEST_CREATE_
|
|
if hMake != -1
|
|
cOut:=EOL+;
|
|
'RETURN NIL'+EOL
|
|
if !fwrite(hMake, cOut)==len(cOut)
|
|
? "write error."
|
|
quit
|
|
endif
|
|
fclose(hMake)
|
|
endif
|
|
#else
|
|
?
|
|
? "Number of tests: "+ltrim(str(nTested))
|
|
? "Number of errors: "+ltrim(str(nErrors))
|
|
#endif
|
|
dbclosearea()
|
|
aeval(directory("./"+_DBNAME+".??x"),{|x|ferase(x[1])})
|
|
aeval(directory("./TG_?.??x"),{|x|ferase(x[1])})
|
|
ferase("./"+_DBNAME+".dbf")
|
|
?
|
|
return nil
|
|
|
|
static procedure rdd_retval()
|
|
return
|
|
|
|
static function rdd_state()
|
|
return {recno(), bof(), eof(), found()}
|
|
|
|
|
|
static function itm2str(itm)
|
|
local cStr:="", i
|
|
if itm==NIL
|
|
cStr+="NIL"
|
|
elseif valtype(itm)=="C"
|
|
cStr+='"'+strtran(itm,'"','"+chr(34)+"')+'"'
|
|
elseif valtype(itm)=="N"
|
|
cStr+=ltrim(str(itm))
|
|
elseif valtype(itm)=="L"
|
|
cStr+=iif(itm,".t.",".f.")
|
|
elseif valtype(itm)=="D"
|
|
cStr+="CTOD("+DTOC(itm)+")"
|
|
elseif valtype(itm)=="B"
|
|
cStr+="{||"+itm2str(eval(itm))+"}"
|
|
elseif valtype(itm)=="A"
|
|
cStr+="{"
|
|
for i:=1 to len(itm)
|
|
cStr+=iif(i==1,"",",")+itm2str(itm[i])
|
|
next
|
|
cStr+="}"
|
|
endif
|
|
return cStr
|
|
|
|
|
|
#ifdef _TEST_CREATE_
|
|
static function rddtst_wr(cAction, xRet)
|
|
local aState, cOut
|
|
|
|
if ascan( aBadRetFunc, {|x| upper(cAction) = x + "(" } ) != 0
|
|
xRet := NIL
|
|
endif
|
|
aState:=rdd_state()
|
|
if pcount()>1
|
|
cOut:="RDDTESTF "+itm2str(xRet)+", "+itm2str(aState)+", "+cAction+EOL
|
|
else
|
|
cOut:="RDDTESTC "+itm2str(aState)+", "+cAction+EOL
|
|
endif
|
|
if !fwrite(hMake, cOut)==len(cOut)
|
|
? "write error."
|
|
quit
|
|
endif
|
|
return nil
|
|
#else
|
|
//rddtst_tst( #<x>, <s>, <x>, <r> )
|
|
static function rddtst_tst(cAction, aExState, xRet, xExRet)
|
|
local aState, lOK:=(.t.), s1, s2, i
|
|
|
|
aState:=rdd_state()
|
|
if pcount()>=4
|
|
if ascan( aBadRetFunc, {|x| upper(cAction) = x + "(" } ) != 0
|
|
xRet := NIL
|
|
endif
|
|
if !valtype(xRet)==valtype(xExRet) .or.;
|
|
!iif(valtype(xRet)=="B", eval(xRet)==eval(xExRet), xRet==xExRet)
|
|
lOK:=(.f.)
|
|
endif
|
|
s1:=itm2str(xRet)
|
|
s2:=itm2str(xExRet)
|
|
s1:=padr(s1, max(len(s1),len(s2))+1)
|
|
s2:=padr(s2, len(s1))
|
|
else
|
|
s1:=s2:=""
|
|
endif
|
|
if !empty(aExState) .and. lOK
|
|
for i:=1 to len(aExState)
|
|
if !valtype(aState[i])==valtype(aExState[i]) .or. !aState[i]==aExState[i]
|
|
lOK:=(.f.)
|
|
exit
|
|
endif
|
|
next
|
|
endif
|
|
?
|
|
?? iif(lOK,"OK ", "ERR ")+cAction+" => "+s1+itm2str(aState)
|
|
if !lOK
|
|
?
|
|
?? " "+cAction+" => "+s2+itm2str(aExState)
|
|
nErrors++
|
|
endif
|
|
nTested++
|
|
return nil
|
|
#endif
|