Getting Failed Framework Assertion Trying to Turn a Timer Off

Hey guys,

I have some code I am using that I got online that is a TFTP server in Xojo. I’ve brought it up to date and it’s been working pretty well but I’m having a problem right now I can’t understand.

I am getting a Framework Failed Assertion Error when trying to turn a timer off. Here’s the code:

		' this method is public so listening socket can pass the first recieved packet to the port switched session socket.
		Dim mb As MemoryBlock
		Dim packet_length As Integer
		Dim Filename, Mode, DataStr, ErrorMsg As String
		Dim OP_Code, BlockNum, ErrorCode As UInt16
		
		packet_length = Data.LenB
		mb = New MemoryBlock(packet_length)
		mb.LittleEndian = False
		
		mb.StringValue(0, packet_length)= Data
		
		Dim tt as UInt16
		
		tt = mb.UInt16Value(0)
		Select Case mb.UInt16Value(0)
		Case OP_RRQ
				Filename = mb.CString(2)
				Mode = mb.CString(2+Filename.LenB+1)
				intRetryAttempts = 0
				WatchDog.Mode = Xojo.Core.Timer.Modes.Off
				Recieve_Read_Request(Filename, Mode)
		Case OP_WRQ
				Filename = mb.CString(2)
				Mode = mb.CString(2+Filename.LenB+1)
				intRetryAttempts = 0
				WatchDog.Mode = Xojo.Core.Timer.Modes.Off
				Recieve_Write_Request(Filename, Mode)
		Case OP_ACK
				
				Dim int2 as Integer = Microseconds-me.mSec
				
				BlockNum = mb.UInt16Value(2)
				intRetryAttempts = 0
				WatchDog.Mode = Xojo.Core.Timer.Modes.Off
				Recieve_Acknowledge(BlockNum)
		Case OP_DATA
				BlockNum = mb.UInt16Value(2)
				DataStr = mb.StringValue(4, packet_length-4)
				intRetryAttempts = 0
				WatchDog.Mode = Xojo.Core.Timer.Modes.Off
				Recieve_Data_Block(BlockNum, DataStr)
		Case OP_ERROR
				ErrorCode = mb.UInt16Value(2)
				ErrorMsg = mb.CString(4)
				Recieve_Error(ErrorCode, ErrorMsg)
		End Select
		
		intTimestamp = Get_Time

The WatchDog is the timer in question. This method is called by the DataAvailable event of the socket.

I’ve tried this with both the standard old framework timer and also with the Xojo Framework Timer. Both give the same problem. I’m somewhat stumped as to why this is the case. I also thought that perhaps the problem was that he was using the ActionNotificationReceiver interface for handling the timer’s action event. I changed that to an AddHandler directive instead. No difference. Same thing…

It only creates a problem in debugging but I think a compiled version has problems too as when I ran a compiled windows version, it all worked but I kept getting numerous beeps that were like indications of errors…

So I am stuck as what might be causing this. I turn timers off in other applications with no problem…What does this assertion mean?

Here’s the information sent to Feedback:

IDE Version : 2016 Release 4.1

Location: WinTimer.cpp(146)

Condition: ::SetTimer(sTimerWND, it->second, 1, (TIMERPROC)TimerProc) != 0

Message: 

Platform: Macintosh Intel 10.111

And one of my Feedback Reports on this: <https://xojo.com/issue/46537>

Does it work, if you check mode before setting it, so you only set it if new mode is different?

if SetTimer fails to create the timer, it returns 0, so maybe you have too many timers?

I’m sorry Christian, I don’t follow you. There is no SetTimer method I am using (oh wait - I see - it’s in the Xojo framework that method. No idea…). Here’s the Constructor for the TFTP session which is a UDPSocket subclass:

Public Sub Constructor(Remote_Address As String, Remote_Port As Integer, Netint as NetworkInterface = Nil, Path As FolderItem, Timeout As Integer = 4, EventLogger As EventLoggerInterface = Nil)
  Dim r As New Random
  SysLog = EventLogger
  szRemote_Address = Remote_Address
  intRemote_Port = Remote_Port
  Self.RouterHops = 64
  me.NetworkInterface = NetInt
  
  If Path.Exists And Path.Directory Then
    fiPath = Path
  Else ' bad path given
    'System.DebugLog("Access Error - Can not find root - bad file path"
    Send_Error(ERROR_ACCESS, "Can not find root.")
    intSessionMode = SESSION_QUIT
    Return
  End If
  
  Do
    Self.Port = r.InRange(49152,65535)
    Self.Connect
  Loop Until Self.IsConnected
  
  WatchDog = New Xojo.Core.Timer
  WatchDog.Period = 100
  WatchDog.Mode = Xojo.Core.Timer.Modes.Off
  AddHandler WatchDog.Action, WeakAddressOf PerformTimerAction
  'WatchDog.addActionNotificationReceiver(Self)
  
  CloseTimer = New Timer
  CloseTimer.Period = 0
  CloseTimer.Mode = Timer.ModeOff
  AddHandler CloseTimer.Action, AddressOf DoClose
  
  FlushThread = New Thread
  AddHandler FlushThread.run, AddressOf FlushThreadAction
  
  FlushThread.run
  
  intTimestamp = Get_Time
  intSessionMode = SESSION_UNKNOWN
  intTimeout = Timeout
  
  Write_Log("New sesion to "+Remote_Address+":"+Str(Remote_Port)+" File:"+Path.NativePath)
  'System.DebugLog("New sesion to "+Remote_Address+":"+Str(Remote_Port)+" File:"+Path.NativePath)
End Sub

That’s where WatchDog and some other timers are created.

I haven’t attempt to check if the timer is off before turning it off…I can. Sounds silly to have to do that though…

SetTimer is a Windows OS functions:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx

OK. So then the Xojo Framework uses that Windows function. So there’s an error with the timer not being set properly then in Windows?

You get a failed assertion, because the developer doing the xojo framework wrote an assert() check.
He expects the function SetTimer used here to always return a value which is not zero.
Now it returns zero, but the case is not handled by raising an exception (as it should), but causing your app to exit with reporting a failed assertion.

OK. Makes sense. Problem is there’s no way to handle it! Odd that it’s returning zero… I wonder why.

Maybe the framework registers a lot of timers with Windows OS without freeing them.

For the time until a fix is done, please check if you have a memory leak with timers.
You call removeHandler for each addHandler, do you?

I just started using AddHandler today. Previously, the code was using the ActionNotifierReceiver interface for handling the timer. So right now, I haven’t messed with RemoveHandler, but that should not be a problem because I’m using a WeakRef in the AddHandler Statement. So whenever the timer goes out of scope, the link to the method should break anyhow. But bottom line is this was happening before the code was changed by me a short while ago.

I previously have not had this issue. So I’m not sure what changed… And the code should only create one timer per TFTP session. So I don’t think there’s a ton of timers here (this is a different Timer issue with a different application than my StackException timer issue in another thread).

What’s really odd is that this code works fine for some period of time. Then it suddenly fails. And only one timer is being created - the constructor is the only place and it’s only called once…

I’m wondering if the following scenario could be happening…

The TFTP Socket has two events where the timer is set to mode single. Those are in SendComplete and in Resend_Packet. I’m wondering if the timer gets set to mode single but before Windows is able to do it’s thing and complete it’s function of setting the timer, the Xojo framework is trying to change the mode of the time a second time. Maybe it’s all happening too quickly…

It’s gotta be some sort of conflict like that because sometimes it works. Then it doesn’t…

[quote=308415:@Christian Schmitz]Maybe the framework registers a lot of timers with Windows OS without freeing them.
[/quote]

Well, Christian, I think you hit the nail on the head with this one…

It’s only one timer. However, a LOT of calls are made to the SetTimer function… Here’s why…

When the TFTPSocket sends out a Datagram, it then starts the timer going looking for an ACK or other response from the device it is communicating with. If it receives that ACK, it turns the timer off. Due to the size of the packets and the speed at which the transfer is taking place, it is making a lot of calls to SetTimer. I put a counter in the SendComplete method for the socket and it made 9985 calls to SetTimer before the assertion started happening.

I tried everything - using CallLater, not turning the timer off but instead setting a boolean variable that would bypass the time code once the timer fired, etc. Still got the assertion.

Then I began thinking that the timer period is 100 mSeconds. That’s fairly long when you are sending 4 byte packets. The timer is being set to mode single multiple times when it’s already running! So I set it to only start the timer if the timer isn’t already running. That made things work just fine. I know doing so messes up the function of the watchdog somewhat. It should really be reset after every datagram is sent. The way I have it now, the 100 mS Wait period would only be valid for the first datagram sent. If a datagram some milliseconds later is not acknowledged, the timer will effectively fire early for that datagram.

I’m just not sure how to accomplish this without hammering the set timer function so much. It seems amazing to me that Windows is having problems after approximately 10,000 calls to SetTimer…

I’m open to ideas…

I got the same assertion with this code:

  for i as integer = 1 to 10000
    timer1.mode= 1
    timer1.mode= 0
  next

It died at i = 9968.

One workaround that comes to mind would be to set the timer to a shorter interval, say 20ms, make it mode multiple, and use a global/appropriately scoped variable to store the Microseconds value when you start looking for a response (instead of starting the timer) and set it to zero when you get the response (instead of stopping the timer). The timer action code would be something like

if TimeoutCounter > 0 then
   if (Microseconds - TimeoutCounter) > 100000 then
      // we've been waiting 100ms
   end
end

[quote=308462:@Tim Hare]I got the same assertion with this code:

  for i as integer = 1 to 10000
    timer1.mode= 1
    timer1.mode= 0
  next

It died at i = 9968.

One workaround that comes to mind would be to set the timer to a shorter interval, say 20ms, make it mode multiple, and use a global/appropriately scoped variable to store the Microseconds value when you start looking for a response (instead of starting the timer) and set it to zero when you get the response (instead of stopping the timer). The timer action code would be something like

if TimeoutCounter > 0 then if (Microseconds - TimeoutCounter) > 100000 then // we've been waiting 100ms end end [/quote]

TIm. Thank you. Good idea. I’ll look into doing something like this.

I think that not being able to run code this simple without a failure is a problem. Looks like it is a Windows problem since Xojo uses its SetTimer function. But Xojo should definitely not throw a framework assertion…

So it sounds like a bug in the framework.
They don’t call KillTimer properly.

Well, feedback filed and thanks to Tim, a simple example project! :smiley:

[quote=308462:@Tim Hare]
One workaround that comes to mind would be to set the timer to a shorter interval, say 20ms, make it mode multiple, and use a global/appropriately scoped variable to store the Microseconds value when you start looking for a response (instead of starting the timer) and set it to zero when you get the response (instead of stopping the timer). The timer action code would be something like

if TimeoutCounter > 0 then if (Microseconds - TimeoutCounter) > 100000 then // we've been waiting 100ms end end [/quote]

Hey Tim,

FYI - I’ve implemented your idea here in my code and it seems to work pretty well. Thanks!

Good to hear.