Page 1 of 1
how to make a quick exit after match games are finished

Posted:
26 Jul 2010, 09:34
by nevatre
I am using the matchPause option to specify a short time between the games of a match. Is there a similar option to specify the time taken between the last match game finishing and xboard exiting? I would like to reduce it from the 2 - 3 secs it is at present, if possible.
Re: how to make a quick exit after match games are finished

Posted:
26 Jul 2010, 17:43
by H.G.Muller
I am not sure why you would have such a long delay. Before XBoard exits, it quits or kills the engine processes. It could be that you have a high setting of /deleayBeforeQuit and /delayAfterQuit. Besides that, I am not aware of any intentional delays in WinBoard at that point. If it is slow, it must be beause it is doing something. It might be trying to save its settings, or wait for system memory to be freed.
Re: how to make a quick exit after match games are finished

Posted:
27 Jul 2010, 05:59
by nevatre
Thanks H.G. I have found that the delay is caused by the sleep in the while loop here
"
/* [HGM] crash: the above GameEnds() is a dud if another one was running */
/* make sure this other one finishes before killing it! */
if(endingGame) { int count = 0;
if(appData.debugMode) fprintf(debugFP, "ExitEvent() during GameEnds(), wait\n");
while(endingGame && count++ < 10) DoSleep(1);
if(appData.debugMode && endingGame) fprintf(debugFP, "GameEnds() seems stuck, proceed exiting\n");
}
"
(in backend.c, xboard-4.4.3 source)
I have commented out the loop and xboard seems to exit fine, and without the delay.
Re: how to make a quick exit after match games are finished

Posted:
27 Jul 2010, 08:06
by H.G.Muller
That is a bit weird. This part of the code is supposed to be executed only when two independent attempts are made to end the game. Usually because one of the engine crashes when it is checkmated. This caused loss of the auto-saved PGN file: the uuto-save is done in GameEnds, and when the thread for the other engine also invokes GameEnds before it is done with it, the game would be lost.
This code makes the second GameEnds wait until the first one, doing the saving, finished. If that causes a delay, it must mean the first GameEnd was slow in saving, and aborting it might mean data loss.
Re: how to make a quick exit after match games are finished

Posted:
27 Jul 2010, 17:03
by nevatre
I agree that what I have done is unsatisfactory, I don't pretend to understand the code. I'd like to find out why GameEnds is stuck and address the issue directly, but so far haven't been able to do that. What I know is that the delay is for the full 10 seconds every time, and "GameEnds() seems stuck, proceed exiting" is printed to the debug file every time, which means that it is still stuck at the end of the delay loop. I would like to use the games saved by xboard, because the score/time/depth in the comments may be useful, but it is not a disaster if some games are dropped - my engine can save the games.
I'll leave the loop commented out for now, and watch in case it causes some other problems. Thanks for your help.
Re: how to make a quick exit after match games are finished

Posted:
27 Jul 2010, 19:10
by H.G.Muller
Well, just to get things clear: Is this in WinBoard or XBoard?
It seems the initial GameEnds() gets stuck somehow, which is not normal. (At least, in my WinBoard it rarely happens; I don't really use XBoard.) If that GameEnds() would work normally, it would be done in a flash, and the loop you now quoted out would not hurt you at all.
So the problem is to figure out what it gets stuck on. GameEnds does things like shutting down the engines, after informing them of the result, and saving the PGN. The engine processes are not terminated if the (default) /reuse option is in force. Otherwise the engine might be send quit, and then a kill signal, and this might involve delays (/delayBeforeQuit, /delayAfterQuit). So it is important to know if the engines are reused or not. Another thing I can imagine is that there somehow is a delay in opening the PGN file for writing. (E.g. you write it in a place that the system considers sensitive, and it runs a virus scanner on it.)
Unfortunately it is quite tedious to track down errors like that. (And if they don't occur reproducibly, quite impossible.) It would requite an fprintf(debugFP, ...) in many places in GameEnds(), which prints to the winboard.debug, so that you could see where exactly the GameEnds() gets stuck on.
Re: how to make a quick exit after match games are finished

Posted:
27 Jul 2010, 21:03
by nevatre
OK, I'll have a go at inserting the fprintf's in GameEnds(). I did glance at that function but, as you say, it's complex and I retreated quickly.The delay is reproducible so it should just require patience to track it down.
I am using linux with the following call to xboard
xboard -matchPause 300 -noGUI -xreuse -xreuse2 -xponder -size small -popupExitMessage false -mg 2 -tc 0:5 -fd ... -fcp ... etc
Thanks again for your help.
Re: how to make a quick exit after match games are finished

Posted:
28 Jul 2010, 18:04
by nevatre
OK, I think I understand what is happening. The relevant functions are GameEnds() and ExitEvent() in backend.c, DisplayFatalError() in xboard.c, and the relevant variable endingGame in backend.c, which is initialised to zero.
The first call to GameEnds() occurs, passing through the first if() and setting endingGame to 1. It gets as far as "sprintf(buf, _("Match %s vs. %s: final score %d-%d-%d"), first.tidy, second.tidy, first.matchWins, second.matchWins, appData.matchGames - (first.matchWins + second.matchWins));", then calls DisplayFatalError(). That function prints the buffer then calls ExitEvent(). That function proceeds to call GameEnds, which returns immediately because endingGame is set to 1. However, ExitEvent() then enters the wait loop as discussed above, because endingGame is set to 1. At this point there is only one GameEnds() running which cannot exit because ExitEvent() is waiting.
One possible solution would be to set endingGame to 2 just before the call to DisplayFatalError() in GemeEnds(), then alter the if condition in ExitEvent() to "if (endingGame==1)".
What do you think H. G. ?
Re: how to make a quick exit after match games are finished

Posted:
28 Jul 2010, 18:45
by H.G.Muller
Hmm, it is a bad thing that GameEnds can call itself recursively this way. The code is supposed to guard against simultanous calling of GameEnds by different threads. Then you can simply wait untill the other thread finishes GameEnds, and be sure everything is already done, so that you don't have to do it again in ExitEvent.
My first impulse would be to simply clear EndingGame before calling ExitEvent, if there is a guarantee the latter will call GameEnds again. Then the existing code would not suppress calling GameEnds for a second time, and you would rely on that. (So after it returns, and ExitEvent returns, you would not continue the original GameEnd, but immediately return from it.)
I am not sure if GameEnds has not already done something that must not be done in duplicate before it calls ExitEvent, though. I would have to look at the code a bit for that.
Anyway, thanks for your thorough analysis of the problem! I will get back to it.
Re: how to make a quick exit after match games are finished

Posted:
28 Jul 2010, 21:03
by H.G.Muller
OK, I guess the best solution is to declare an extra varianble in GameEnds():
char popupRequested = 0;
and then replace the call to DisplayFatalError() by
popupRequested++;
Finally, at the very end og GameEnds, after endingGame = 0;, you can then put
if(popupRequested) DisplayFatalError(buf, 0, 0);
This turns the recursion in a harmless tail recursion. When GameEnds() then is called again, it is really executed, but I checked that this duplicate execution is harmless. The first execution of GameEnds() will have set gameMode to EndOfGame, meaning that almost none of the stuff in there is done. Only the saving of the PGN, but nowadays I have built a test on that based on a checksum, so that it will never auto-save a game again that has already been saved, if it has exactly the same checksum (including comments).
I will fix it this way in the next release.
I guess in WinBoard I never noticed this, because in Windows Sleep(1) will sleep 1 msec. But in XBoard is sleeps 1 sec!