Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Timer control issue

Status
Not open for further replies.

DSummZZZ

Programmer
Oct 24, 2000
4,250
US
I have poked around some using google etc, but haven't seen any reasoning behind another issue I'm having.
A Timer control on a VFP 9 form works fine on an XP or Server 2003 machine, but seems to quit working (Timer event stops firing at the set interval) on a Windows 7 machine. It will run for quite a few minutes, or even for a few hours, then just stop firing.
Anyone else seen this behavior?


-Dave Summers-
[cheers]
Even more Fox stuff at:
 
The VFP Timer always has been less accurate than C/C++ Timers, but I never have seen it stop working, no. I wouldn't even know where to look for a difference in XP vs Win7. This timer is a VFP runtime internal, isn't it? How would the OS have any influence? What are you doing within the Timer code?

Bye, Olaf.
 
Hmmm... I've never seen a timer "just stop". If it works once it always works, within the conditions where timers work.

You do know that timers are blocked by open menus, right? A menu halts all execution, including timers. Could you have just hit a "lucky" coincidence here where users are leaving a menu open?
 
This timer is a VFP runtime internal, isn't it?
Yes. It's one of the VFP native timers.

What are you doing within the Timer code?
What I'm trying to do is check processes running on remote computers using WScript, then restart them if needed.
The timer also shows remaining seconds before the next 'poll', which, when the timer has stopped, stops counting down.

...users are leaving a menu open?
No such scenario there. So far, I have only been testing this app on my development computer, and I am the only one using it.


This makes no sense to me, unless for some reason, W7 has some other built in garbage collection that I'm not aware of. My app doesn't use much CPU, so maybe there's something inherent to W7 to pause thread processing if CPU usage goes down? No clue.


-Dave Summers-
[cheers]
Even more Fox stuff at:
 
This timer is a VFP runtime internal, isn't it?
Yes. It's one of the VFP native timers.

Well, I assumed so. What I'm saying is the timer control, it's behaviour etc. is part of VFP, not of the OS.
So I don't see a reason why this would be introduced by Windows 7.

I would still rather try to find code influencing your timer, it's Enabled status, eg also a Thisform.SETALL() call could do that by incidence, eg if you enable/disable form controls for read vs. edit mode.

Bye, Olaf.
 
It happened to me before. it was strange.

-what I did is I removed the timer completely. (I saved the code ofcourse)
-saved the form.
-re-opened the form in the project, added a new timer and then the code
-recompiled and it worked.

I am not sure if the form was corrupted somehow or not.. but, that did the trick for me.

another issue I had once, was the grid freezing... when I try to open the form.. I did the same thing as above... I think it was a corrupted form field or header or something...


Ali Koumaiha
TeknoSoft Inc.
Michigan
 
I appreciate the input, but a lot of the suggestions just don't apply. I'll go ahead and elaborate, so if you get bored reading I'll understand. [smile]

This is a real simple test app consisting of a form which has two grids bound to two tables, a couple text boxes for (domain) username and password, and the timer. Sure, there are a couple labels scattered around too, but there is no user interaction with the form at all. It just sits there on a spare monitor a does its thing.
All the form does is fire the timer event every 1000 milliseconds which checks to see if 5 minutes has elapsed. If so, the code queries a server for certain process names/IDs to see if CPU usage has changed. If it has, those processes show as green in the grid's DynamicBackgroundColor. Otherwise, they show as red, letting me know they may have stopped.

At first, I thought maybe setting the interval to 0 when the 5 minutes expired, running the code, then resetting it back to 1000 at the end of code execution may cause grief. But the timer has been stopping anywhere but at the 5 minute mark. It could be at 1:27, 2:35, 4:43, anytime.
I left it running when I went home last night, and when I got to work this morning, the 'Last Checked' caption read 20:13, and the 'Time Remaining' caption read 2:27 and was stopped.
By the way, I have my workstation power save sleep mode set to 'Never', so I know that's not an issue.


Ali,
I did delete the timer and add a new one after your suggestion, so I'll see how that behaves.

In the meantime, this isn't a critical production app, more of an experiment. But there is a good chance that future timer based apps currently in use at our office will be moved to W7 or W8 machines. I would like to I'm not going to have problems with those. Or at least be able to find a workaround.

Anyway, thanks again for the suggestions!


-Dave Summers-
[cheers]
Even more Fox stuff at:
 
I blieve all you say, but still don't see how that would relate to the OS.

What I do to ensure the timer code won't restart after the timer event is to temporaily set enabled = .f., not change the Interval to 0. I know the timer stops at other times than at the 5 minute interval, nevertheless I see it as better practice to disable the timer during it's event and restart afterwards.

If the app has nothing more to do than wait for the next timer event, you could also do a loop with:
Code:
ltNextevent = Datetime()
Do While .T.
   Do While Datetime()<ltNextevent 
      DoEvents Force
   EndDo
   ltNextevent = ltNextevent + 5*60
   _screen.activeform.YourEvent()
Enddo

Also, I would look into the windows event log, if anything ran at 20:13, which would explain a choke of your application. And is it really just the timer, or the whole process stopping to work?

Bye, Olaf.
 
I meant to stay during instead of after, of course. ...to ensure the timer code won't restart during the timer event
but actually it's not possible anyway.

Bye, Olaf.
 
i am wondering if the query is hanging or taking a while to process etc..

so, if its running, the 5 min elapsed, would the timer event fire again? while the original code didn't finish executing?

maybe permission issue since its a new machine? i don't know.. just throwing some ideas at ya i guess.

Ali Koumaiha
TeknoSoft Inc.
Michigan
 
Yes, if the timer is enabled and has Interval greater than 0, it can fire again, even if the previous processing code hasn't finished. This can quickly get ugly. That's why you absolutely should either disable the timer or set Interval to 0 at the top of your Timer method.

Tamar
 
I programmed a sample timer, which may show either the behavior to stop or to reenter the timer event before it finishes:

Code:
#Define cnMaxCount 5000000

o = Createobject("myTimer")
o.Enabled = .T.
On Key Label F12 Clear Events
Read Events
On Key Label F12
o = .Null.

Define Class myTimer As Timer
   Interval = 250
   Procedure Timer()
      * this.Interval = 0
      * this.enabled = .f.
      ? "1", Datetime()
      Local lnCount, loHTTP
      For lnCount = 1 To cnMaxCount
         DoEvents
      EndFor
      ? "2", Datetime()
      loHTTP = Createobject("msxml2.xmlhttp")
      loHTTP.Open("GET","[URL unfurl="true"]http://www.google.com")[/URL]
      loHTTP.Send()
      Do While loHTTP.readyState<>4
         DoEvents Force
      EndDo 
      ? "3", Datetime()
      For lnCount = 1 To cnMaxCount
         DoEvents
      Endfor
      ? "4", Datetime()
      * This.Interval = 60
      * This.enabled = .t.
   Endproc
Enddefine

The Timer Interval is 250ms, on my PC one run of the timer event needs about 1 to 2 seconds. You may need to adjust the value of cnMaxCount in the first line to also get there. Even though the timer event runs longer than the interval and I don't disable the timer during it's event, nor set Interval to 0, the timer never reentered itself before finishing. I can watch the order of output always is 1,2,3,4, I also observe the next start occurs immediately after the last output of 4, so it looks like next events are queued.

I let this run on my Win7 machine for the next few hours and see if it suddenly stops.

Bye, Olaf.
 
I didn't find any problems on my Win7 machine, but I didn't ran the timer for days, just a couple of hours.

So how long does it take to fail? Does it run a few days? Perhaps you just encountered an undocumented limitation of the duration a VFP Timer works. And you should perhaps investigate, if your timer code crashed the whole process. What do you do to observer processes? A WMI query?

Bye, Olaf.
 
All,

Thanks again for the suggestions.
The reason I'm thinking OS issue is because I have written a bunch of apps (not just this particular on) which have timer controls, all which run fine on XP or Windows Server platforms for weeks or months at a time. I can run those same apps on my W7 box (which has been in service for over 2 years) and the timer will just stop after a while. No consistency as to how long it runs before it stops, it just does.
The apps all do different types of processing, some just reading and updating table data, some FTP'ing files from a remote host and processing them, etc.
This particular app - like I mentioned - uses scripting to check process status on remote computers. Here is a code snippet:
Code:
loSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
loSWbemServices = loSWbemLocator.ConnectServer(lcRemoteComputer, "root\cimv2",lcAdminUserName,lcAdminPassword)
lcolSWbemObjectSet = loSWbemServices.InstancesOf("Win32_Process")

FOR EACH loProcess In lcolSWbemObjectSet
   STORE TRANSFORM(loProcess.Name) TO m.taskname 
   STORE loProcess.ProcessID TO m.procid
ENDFOR
I know it's not the query itself hanging, because the timer has stopped at a point where the code hadn't been called. Also, I know the app isn't hung because I have a 'Check Now' button I can click (which just sets the timer interval to 500 ms so it fires right away), and it continues to work fine for a while after that.

Anyway, I'm probably going to have to do something else, API call or something. Here is an example:


-Dave Summers-
[cheers]
Even more Fox stuff at:
 
Well, then have you run that particular EXE on any other system than Win7?

I still doubt it's Win7, as the timer is a native VFP one. Of course it may base on the C runtime and that may then base on OS timers, in the end VFPs Runtime itself also is using the Windows API to do memory management and some more, but it's rather self contained. Otherwise it would not have been possible to have a Unix and Mac Version of it, in the old days.

I doubt VFP has ever been very much changed in things like the timer class, but I don't know where it was introduced.

To me it rather looks, as if something is interfereing, that doesn't run on my PC. I'd give it some more tests, but to make that test more relevant, I'd like to add your way of disabling and resetting it. Last chance to show some code, otherwise I'll just uncomment the lines to set Interval to 0 and back.

Are you perhaps resetting it this way?

Code:
lnInterval = This.Interval
This.Interval = 0
...other code
This.Interval = lnInterval

Well, assume the worst case happens, and this doesn't prevent reentrance? Then at the start of the event the Interval is 0 and is reset to 0, the timer stops working.

I'd rather set Timer.Enabled = .f. at start and back to .t. in the end, that doesn't touch the Interval of the timer, so it can't get stuck at 0.

Bye, Olaf.
 
Oh, and in the end, all timers are based on some hardware timer, counter etc. So maybe it's neither VFP nor Windows, but your hardware.

How abot adding some button to check the Timer Interval and Enabled and other properties, so you get more info about the timer's state, when it's stuck?

Bye, Olaf.
 
Olaf,

I agree, there could be some hardware anomaly. If that's the case, I would still blame the OS for not behaving right. [wink]
Maybe setting Enabled off would make a difference, but I have never done that in any apps, as Interval=0 has always worked fine.

Anyway, here's the timer code...
Code:
STORE THIS.INTERVAL TO nOldInterval

nSecondsLeft = THISFORM.nDelay - THISFORM.nCounter 
nMinutes = nSecondsLeft/60
nSeconds = nSecondsLeft%60
Thisform.lblRemaining.Caption = ;
   TRANSFORM(nMinutes, "@L 99") + ;
   ":" +;
   TRANSFORM(nSeconds, "@L 99")

THISFORM.nCounter = THISFORM.nCounter + 1

IF THISFORM.nCounter >= THISFORM.nDelay
   THIS.INTERVAL = 0

   SELECT DISTINCT remotename ;
      FROM tasklist ;
      INTO CURSOR remotelist ;
      WHERE !DELETED()

   SELECT remotelist
   SCAN
      THISFORM.lblChecking.CAPTION = "Checking:"
      THISFORM.REFRESH()
      =THISFORM.usage(ALLTRIM(remotelist.remotename), ALLTRIM(THISFORM.txtUsername.VALUE), ALLTRIM(THISFORM.txtPassword.VALUE))
      
   ENDSCAN

   THIS.INTERVAL = THISFORM.nTimerInterval
   Thisform.nCounter = 0

ENDIF

RETURN

Here is what is contained in the 'usage' method:
Code:
PARAMETERS lcRemoteComputer, lcAdminUserName, lcAdminPassword
LOCAL loSWbemLocator, loSWbemServices

loSWbemLocator = CreateObject("WbemScripting.SWbemLocator")
loSWbemServices = loSWbemLocator.ConnectServer(lcRemoteComputer, "root\cimv2",lcAdminUserName,lcAdminPassword)
lcolSWbemObjectSet = loSWbemServices.InstancesOf("Win32_Process")

CREATE CURSOR pids (taskname c(35), pid i(4))
SELECT pids
INDEX ON ALLTRIM(taskname) + ALLTRIM(STR(pid)) TAG pid 

SELECT tasklist 
FOR EACH loProcess In lcolSWbemObjectSet

   STORE TRANSFORM(loProcess.Name) TO m.taskname 
   STORE loProcess.ProcessID TO m.procid
   STORE (VAL(loProcess.KernelModeTime)+;
          VAL(loProcess.UserModeTime)) / 10000000 TO m.usage 
   STORE lcRemoteComputer TO m.remotename
   
   STORE m.procid TO m.pid
   INSERT INTO pids FROM MEMVAR 
   
NEXT

&&... some process id cpu usage comparison stuff goes here...

USE IN pids 

RETURN


-Dave Summers-
[cheers]
Even more Fox stuff at:
 
Thanks,

First observations, not necessarily helpful:

nOldInterval
You never use this variable later in your code.

THISFORM.REFRESH()
You only do this in the if branch every 60 calls. If the countdown you display via Thisform.lblRemaining.Caption does update every second, you don't need the form refresh at all.

In regard to what Tamar says, you should always disable the timer at it's start and reenable it, not just fo the longer running cases.

What do you do about errors? Suppressing them? Do you have a comment in the Error event of the Timer and/or Form? Assume you somehow set THISFORM.nDelay to NULL or any type different than numeric (and this could be sneaking on you via some Seteall() call) then the line nSecondsLeft = THISFORM.nDelay - THISFORM.nCounter would error always and you'd never update the label caption, while the timer still runs. You'll never get passed this line, nothing happens and your process also doesn't stop.

Unlikely, as you say the timer starts working, if you resurrect it by only setting it's interval. But that again is another hint on setting timer.interval somewhere else from outside, be it by accident via some Setall() call.

Bye, Olaf.
 
Olaf,

Since I have played around with this project some, there are most likely some deprecated calls in the app that I have forgotten to remove. nOldInterval is a good example.
For the Thisform.Refresh() call, I am forcing the following to redraw BEFORE running the query. Otherwise it doesn't redraw until the query finishes:
Code:
      THISFORM.lblChecking.CAPTION = "Checking:"
      THISFORM.txtRemoteComputer.VALUE = remotelist.remotename
      THISFORM.txtRemoteComputer.DISABLEDBACKCOLOR = RGB(255,0,0)

      THISFORM.REFRESH()

What do you do about errors?
In this case, nothing. As I mentioned, this is just a test app that hasn't gone production yet, since I can't get reliable operation from the timer. So, there is no error handling done, so if there is/was any error, the dialog would just sit there on the screen until I acted on it.
I did check the timer's 'Error' event (good suggestion) for any stray characters or comments, and there were none. I also checked the entire form to make sure there are no stray "Interval=" settings anywhere.

Anyway, thanks again for the suggestions.


-Dave Summers-
[cheers]
Even more Fox stuff at:
 
Well, if you have to analyse something, this is the moment you introduce your normal error handler, in fact it should be in the default code of any new project, no matter if test or production. Don't you think?

You searched for "Interval="? Well, Setall() will not have a "=" in it. And there also is STORE, as you know. The only way to find any place where any Interval is set is to search for Interval on it's own via Codereferences or GoFish in the whole project.

Really, there is no way the OS would set the Interval to 0, no way. This really is just a VFP object property, and no other code than the VFP runtime and your own code on top is assigning values to it. There is no way this gets 0 on it's own.

Bye, Olaf.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top