SysWait() in v12.10 ... broken?

  • This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.
#1
This sort of routine works great in v11.

Code:
VOID WaitUntilTickCount64 ( ULONGLONG ullTickCountDue )
{
    while ( TickCount64() < ullTickCountDue )
    {
        SysWait(0,2);
    }
}
In v12.10, SysWait(0,2) never returns.
 
#2
I wasn't finished with that last post. In v12.10 SysWait(0,2) (or any number of milliseconds) never returns, regardless of how I use it.

And if I change that to SysWait(1,0) in the WaitUntilTickCount64() function below, then, after 2 or 3 times through the loop, I get an access violation. FWIW, I get TickCount64() like this:

Code:
ULONGLONG TickCount64()
{
    ULONGLONG ullPerfCount;
    QueryPerformanceCounter((LARGE_INTEGER*) &ullPerfCount);
    return ullPerfCount / (global.ullPerfFreq / 1000); // ms
}

This sort of routine works great in v11.

Code:
VOID WaitUntilTickCount64 ( ULONGLONG ullTickCountDue )
{
    while ( TickCount64() < ullTickCountDue )
    {
        SysWait(0,2);
    }
}
In v12.10, SysWait(0,2) never returns.
 

rconn

Administrator
Staff member
May 14, 2008
10,289
90
#3
This sort of routine works great in v11.

Code:
VOID WaitUntilTickCount64 ( ULONGLONG ullTickCountDue )
{
    while ( TickCount64() < ullTickCountDue )
    {
        SysWait(0,2);
    }
}
In v12.10, SysWait(0,2) never returns.
Hadn't we agreed in a previous thread that there wasn't any reason for you to be using SysWait? Unless you know the intimate details of SysWait (and you don't!) you shouldn't go near it.

(And SysWait for 1 or 2 milliseconds is never going to work, because it will sleep more than that before doing the check.)
 

samintz

Scott Mintz
May 20, 2008
1,232
11
Solon, OH, USA
#4
Vince,

In the event plugin I wrote, I use the
following construct in my EventWait function:

do

sleep for 100 ms

check for doneness

tty_yield(0)
loop


That allows Ctrl-C processing to abort
the wait as well as allow other stuff to happen. It has a granularity
of 100ms.
Did you need a high performance counter?
Or do you just need to delay a certain number of milliseconds?

I'm not familiar with the SysWait()
function. Is that a Win32 API or TCMD API?

-Scott


vefatica <> wrote on 03/25/2011
02:52:21 PM:


> vefatica <>
> 03/25/2011 02:52 PM
>
> I wasn't finished with that last post. In v12.10 SysWait(0,2)
(or

> any number of milliseconds) never returns, regardless of how I use
it.

>
> And if I change that to SysWait(1,0) in the WaitUntilTickCount64()

> function below, then, after 2 or 3 times through the loop, I get an

> access violation. FWIW, I get TickCount64() like this:
>
>
> Code:
> ---------
> ULONGLONG TickCount64()
> {
> ULONGLONG ullPerfCount;
> QueryPerformanceCounter((LARGE_INTEGER*) &ullPerfCount);
> return ullPerfCount / (global.ullPerfFreq / 1000); //
ms

> }
> ---------
>
>
> ---Quote (Originally by vefatica)---
> This sort of routine works great in v11.
>
>
> Code:
> ---------
> VOID WaitUntilTickCount64 ( ULONGLONG ullTickCountDue )
> {
> while ( TickCount64() < ullTickCountDue )
> {
> SysWait(0,2);
> }
> }
> ---------
> In v12.10, SysWait(0,2) never returns.
> ---End Quote---
>
>
>
 
#5
On Fri, 25 Mar 2011 16:05:17 -0400, you wrote:

|Hadn't we agreed in a previous thread that there wasn't any reason for you to be using SysWait? Unless you know the intimate details of SysWait (and you don't!) you shouldn't go near it.
|
|(And SysWait for 1 or 2 milliseconds is never going to work, because it will sleep more than that before doing the check.)

I believe we did not discuss SysWait() at all (at least in several years).

It does work well.

I can

Code:
typedef VOID *(WINAPI *SYSWAITTYPE)(ULONGLONG, INT);
HMODULE hTC = GetModuleHandle(L"TakeCmd.DLL");
syswait = (SYSWAITTYPE) GetProcAddress(hTC, "SysWait");
and that works well in v12.10. But it also gets it from earlier versions of the
DLL though in which case, the signature is wrong and it doesn't work correctly.
I suppose I could test _VERSION and decide whether to do that.

In another recent post, samintz said he gets signal handling when he loops
arounf Sleep() and tty_yield(0). I don't. ... ???
 
#6
On Fri, 25 Mar 2011 16:16:14 -0400, you wrote:

|Vince,
|
|In the event plugin I wrote, I use the
|following construct in my EventWait function:
|
| do
|
| sleep for 100 ms
|
| check for doneness
|
| tty_yield(0)
| loop
|
|
|That allows Ctrl-C processing to abort
|the wait as well as allow other stuff to happen. It has a granularity
|of 100ms.
|Did you need a high performance counter?
| Or do you just need to delay a certain number of milliseconds?
|
|I'm not familiar with the SysWait()
|function. Is that a Win32 API or TCMD API?

It's a TCMD API (see the header). Apparently in a recent change, its first arg
went from DWORD to ULONGLONG.

When I just loop around Sleep() and tty_yield(0), I don't get Ctrl-C handling
... have always had to add/remove my own handler for that.
 
#8
On Fri, 25 Mar 2011 16:29:35 -0400, you wrote:

||(And SysWait for 1 or 2 milliseconds is never going to work, because it will sleep more than that before doing the check.)

Sleep() has the same granularity problems (~10ms or ~16ms) doesn't it?
 

rconn

Administrator
Staff member
May 14, 2008
10,289
90
#9
On Fri, 25 Mar 2011 16:29:35 -0400, you wrote:

||(And SysWait for 1 or 2 milliseconds is never going to work, because it will sleep more than that before doing the check.)

Sleep() has the same granularity problems (~10ms or ~16ms) doesn't it?
First, your SysWait call is trying to wait 0 milliseconds, which seems pretty pointless. You're doing a lot of heavy lifting inside SysWait setting everything up, and then throwing it all away immediately.

Second, if you want to sleep for a millisecond or two using Sleep(), you just need to adjust your timer resolution. (See the Sleep() docs for details.) If you just want to give up your time slice, use Sleep(0).
 
#11
On Sat, 26 Mar 2011 09:45:59 -0400, you wrote:

|---Quote (Originally by vefatica)---
|In another recent post, samintz said he gets signal handling when he loops
|arounf Sleep() and tty_yield(0). I don't. ... ???
|---End Quote---
|tty_yield(0) does service the message queue, though only if there's a message already waiting.

My point was that **I** must add a ConsoleCtrlHandler if I want to interrupt
this loop:

Code:
VOID WaitUntilTickCount64 ( ULONGLONG ullTickCountDue )
{
	while ( TickCount64() < ullTickCountDue )
	{
		Sleep(1);
		tty_yield(0);
	}
}
while SysWait() (apparently) adds one for me. Isn't that correct?

But not I see that SysWait() adding/removing a ConsoleCtrlHandler every few
milliseconds is inefficient (when I could do it just once outside the wait
loop).
 

rconn

Administrator
Staff member
May 14, 2008
10,289
90
#12
My point was that **I** must add a ConsoleCtrlHandler if I want to interrupt
this loop:

Code:
VOID WaitUntilTickCount64 ( ULONGLONG ullTickCountDue )
{
	while ( TickCount64() < ullTickCountDue )
	{
		Sleep(1);
		tty_yield(0);
	}
}
while SysWait() (apparently) adds one for me. Isn't that correct?
No; SysWait does not set a ctrl handler.
 
#13
On Sat, 26 Mar 2011 12:51:18 -0400, you wrote:

|No; SysWait does not set a ctrl handler.

That's really odd since I get one with SysWait() and I don't with {Sleep(1);
tty_yield(0);}.
 

rconn

Administrator
Staff member
May 14, 2008
10,289
90
#14
> That's really odd since I get one with SysWait() and I don't with
> {Sleep(1);
> tty_yield(0);}.
SysWait does this at the end of its loop:

// check for an unhandled ^C in the exception thread
if ( aGlobals.fBreak )
BreakHandler();

Which just checks to see if somebody hit a ^C. But it definitely does not
install / remove a control handler.
 
#15
I ]m allowing breaking out of a wait loop like this:

Code:
VOID WaitUntilTickCount64 ( ULONGLONG ullDue )
{
    while ( TickCount64() < ullDue && bContinue )
    {
        Sleep(1);
        tty_yield(0);
    }
    bContinue = TRUE;
    SetConsoleCtrlHandler(WaitCtrlHandler, FALSE);
}
where I add the Ctrl handler before calling the wait function. The handler just sets bContinue to FALSE. Is that kosher? How would you do it in a plugin?
 

rconn

Administrator
Staff member
May 14, 2008
10,289
90
#16
How would you do it in a plugin?
I wouldn't do it that way (which will mangle the existing handler, fail to execute any ON BREAK statements, and fail to shut down hooks).

TCC already has a handler running, which sets aGlobals.fBreak to 1 whenever a ^C or ^Break is entered -- just check for that in your loop.
 
#17
On Sun, 27 Mar 2011 22:33:11 -0400, you wrote:

|TCC already has a handler running, which sets aGlobals.fBreak to 1 whenever a ^C or ^Break is entered -- just check for that in your loop.

That would be nice, but how do I check aGlobals? Is a pointer to it exported
... it's members documented?
 
#18
On Sun, 27 Mar 2011 23:19:33 -0400, you wrote:

||TCC already has a handler running, which sets aGlobals.fBreak to 1 whenever a ^C or ^Break is entered -- just check for that in your loop.
|
|That would be nice, but how do I check aGlobals? Is a pointer to it exported
|... it's members documented?

I'm eagerly looking forward to hearing about this.
 
#19
I wouldn't do it that way (which will mangle the existing handler, fail to execute any ON BREAK statements, and fail to shut down hooks).

TCC already has a handler running, which sets aGlobals.fBreak to 1 whenever a ^C or ^Break is entered -- just check for that in your loop.
Apparently, the address of aGlobals is exported:

Also apparently, the fBreak member is at byte offset 44 (that byte changes from 0 to 1 when Ctrl-C or Ctrl-Break is pressed).

Testing that in my wait loop as you suggested works quite well, saving me adding a console ctrl handler (and possibly screwing up yours). I could eliminate ctrl handlers in four of 4UTILS commands, simplifying my coding and probably saving on dll size.

Is it correct that fBreak is at byte offset 44? Is it likely to stay there. What's its type? [Actually, just testing the byte works.]
 
#21
The aGlobals structure changes in every new version, but (not 100% guaranteed!) new fields are added to the end.
Thanks. In the event the offset changed, the plugin author could do nothing, even knowing the aGlobals declaration. fBreak is useful. Would you consider exporting its location? ... should be a one-liner and very of little cost to the binary ... even decorated ... it'd be easy enough to get at it.
 

Charles Dye

Super Moderator
Staff member
May 20, 2008
3,479
44
Albuquerque, NM
prospero.unm.edu
#22
The aGlobals structure changes in every new version, but (not 100% guaranteed!) new fields are added to the end.
Is this stuff documented somewhere, and I'm just to stupid to find/recognize it? Are there other useful variables in aGlobals? Or is this the kind of private internal stuff that it would be catastrophically dumb to rely upon?
 
#23
On Fri, 01 Apr 2011 22:35:12 -0400, you wrote:

|---Quote (Originally by rconn)---
|The aGlobals structure changes in every new version, but (not 100% guaranteed!) new fields are added to the end.
|---End Quote---
|Is this stuff documented somewhere, and I'm just to stupid to find/recognize it? Are there other useful variables in aGlobals? Or is this the kind of private internal stuff that it would be catastrophically dumb to rely upon?

I first heard of it when Rex suggested testing the fBreak member instead of
installing my own console ctrl handler. I looked around in it a bit and saw
some stuff you might expect ... startup (?) directory, ini file name, tcstart
file name, a couple of familiar-looking numerical constants. But I may have
been looking well beyond it ... found the tcstart file name at byte-offset
316040!. If you've followed this thread you see the value of the fBreak member.
I don't know what else might be of interest that we can't already get at (except
possibly the tcstart file name which I'd like in a variable). Maybe Rex will
say more.

I searched my news server archives (tens of thousands of posts) and found one
mention of aGlobals ... in a 6-7 year-old user-posted assembly language patch to
fix something having to do with MBCS characters.
 
#24
vefatica:
...
| the tcstart file name which I'd like in a variable

I just test inserting the command
@set tcstart=%_batchname
in my TCSTART.BTM.

It does exactly that! BTW, I did it BEFORE detecting PIPE etc... - thus it
is exactly what in internal variable would contain.
--
Steve
 

rconn

Administrator
Staff member
May 14, 2008
10,289
90
#25
Is this stuff documented somewhere, and I'm just to stupid to find/recognize it? Are there other useful variables in aGlobals? Or is this the kind of private internal stuff that it would be catastrophically dumb to rely upon?
It's not documented because (1) it changes in every version (and sometimes between builds), and (2) you can do irreperable harm by accessing the wrong fields. (Which might not show up until much later!)
 
#26
On Sat, 02 Apr 2011 08:48:31 -0400, you wrote:

|vefatica:
|...
|| the tcstart file name which I'd like in a variable
|
|I just test inserting the command
| @set tcstart=%_batchname
|in my TCSTART.BTM.
|
|It does exactly that! BTW, I did it BEFORE detecting PIPE etc... - thus it
|is exactly what in internal variable would contain.

Yes, I know, and then it would be in the environment. And I could do the same
with _STARTPATH and maybe a few others. Everyone who was interested could do
it. Or TCC could do it, just once, and everyone could use it.