Page 2 of 2
VO Question: dbServer FieldGET issue
Posted: Tue Nov 05, 2019 2:36 pm
by ic2
Hello Jamal,
Good detective work!
Please keep us posted about what Joachim replies.
Dick
VO Question: dbServer FieldGET issue
Posted: Thu Nov 14, 2019 5:57 pm
by Jamal
Hi All,
Joachim just replied and could not duplicate the issue.
In the mean time I think I may have found out the culprit: it has to do with multi-threading and DBF workarea gets all mixed up.
Disclaimer: I am no multi-threading expert, my conclusions may not be accurate.
I was creating a timer using code like the incomplete sample below. When the timer kicked in, the OpenDBFCallBack() is called. This function only opens another DBF, checks some values, closes dbServer and returns, but somehow, this affected bBrowser dbServer workarea in another unrelated datawindow1 where a bBrowser:refresh() was called by its refresh timer. The workarea got overwritten and no longer the same and thus FIELDGET("SOMEFIELD") crashed because my code that handles bBrowser on DataWindow1 innocently thinks it is still working with the same original workarea and its same dbf structure.
Here the a sample code:
_dll FUNCTION CreateTimerQueue() as ptr PASCAL:Kernel32.CreateTimerQueue
Code: Select all
function Test() as void pascal
local hTimer as ptr
local arg := 1234 as int
local gDoneEvent as ptr
LOCAL gTimerQueue as ptr
gDoneEvent := CreateEvent(null_ptr, true, FALSE, null_ptr)
// Create the timer queue.
gTimerQueue := CreateTimerQueue()
// Set a timer to call the timer routine every 5 minutes.
// Time in milliseconds. Multiply the time value by 60000. 5 MINUTES = 5*60000
CreateTimerQueueTimer( @hTimer, gTimerQueue, @OpenDBFCallBack(), @arg , 1*60000, 1*60000, 0)
return
function OpenDBFCallBack() as void pascal
// open dbf server, check some values
// close dbServer and return
return
Note: even before using the above CreateTimerQueueTimer(), I had issues with bBrowser sometimes failing with similar issues.
I had DbSetRestoreWorkarea(false) in the Start() of my app. I will do more tests to see if setting it to True makes a difference.
Jamal
VO Question: dbServer FieldGET issue
Posted: Thu Nov 14, 2019 6:41 pm
by wriedmann
Hi Jamal,
if you are not using multithreading in your application, then this is not the cause.
In VO both the RDDs and the Garbage Collector are no thread safe, but according to the Microsoft docs
https://docs.microsoft.com/de-de/window ... mer-queues this call does not creates an own thread.
There must be something other that confused the runtime and make it close the wrong server.
Wolfgang
VO Question: dbServer FieldGET issue
Posted: Thu Nov 14, 2019 6:59 pm
by Jamal
Hi Wolfgang,
You most likely right. If you notice I wrote:
Note: even before using the above CreateTimerQueueTimer(), I had issues with bBrowser sometimes failing with similar issues.
But my feeling is that it has to do with the way VO is handling works areas and may be the DbSetRestoreWorkarea(false) is the cause. I can't rule anything out at this point.
Jamal
VO Question: dbServer FieldGET issue
Posted: Thu Nov 14, 2019 7:10 pm
by wriedmann
Hi Jamal,
yes, I have noted that.
But in my applications (and I'm using bBrowser heavily) I had never this issue.
Do you are using a hybrid approach somewhere (mixed functions and servers9?
Wolfgang
VO Question: dbServer FieldGET issue
Posted: Thu Nov 14, 2019 7:33 pm
by Jamal
Hi Wolfgang,
It use mostly dbServer methods in my apps, and if I overrode any dbServer methods (for speed) I write for example:
Code: Select all
METHOD FIELDPUT( uField, uValue ) CLASS _JamalDBServer
LOCAL wPos as DWORD
LOCAL dwCurrentWorkArea as DWORD
VODBSelect( wWorkArea, @dwCurrentWorkArea ) // select workrea
wPos := __GetFldPos( uField, wFieldCount )
VODBFieldPut( wPos, uValue )
__DBSSetSelect( dwCurrentWorkArea ) //SE-060527 - restore workarea
RETURN uValue
Jamal
VO Question: dbServer FieldGET issue
Posted: Thu Nov 14, 2019 8:48 pm
by Karl-Heinz
Hi Jamal,
take a look at the __DBSSetSelect() sources. If you don´t use the DbSetRestoreWorkarea(TRUE) setting, the global var __glRestoreWorkarea never becomes true. So either use DbSetRestoreWorkarea(TRUE) or restore the workarea within your FieldPut()
Code: Select all
FUNCTION __DBSSetSelect(dwNew AS DWORD) AS DWORD PASCAL
//SE-060527
IF __glRestoreWorkarea <---------------------------------------
RETURN VODBSetSelect(LONGINT(dwNew))
ENDIF
RETURN dwNew
regards
Karl-Heinz
VO Question: dbServer FieldGET issue
Posted: Thu Nov 14, 2019 9:19 pm
by robert
Jamal, Karl-Heinz,
I suggest to set DbSetRestoreWorkarea(TRUE) .
In fact I will make that the default for the next build.
In VO switching workareas (especially when there are many fields) can be quite expensive. The runtime removes the fieldnames from the active table from the memvar/fields list and then adds the fields of the new area.
We added this setting as optimization.
But in X# things work differently, so there is no need anymore to suppress workarea switching. See
https://github.com/X-Sharp/XSharpPublic ... .prg#L1694
to see what we are doing: we are only changing the active workarea number.
Robert
VO Question: dbServer FieldGET issue
Posted: Thu Nov 14, 2019 10:19 pm
by Jamal
Hi Karl, Robert,
I will use DbSetRestoreWorkarea(TRUE) from now on in my VO apps.
Hopefully, this cures the issues.
Jamal