• All submissions to this site are governed by Second Life Project Contribution Agreement. By submitting patches and other information using this site, you acknowledge that you have read, understood, and agreed to those terms.
Issue Details (XML | Word | Printable)

Key: SVC-3099
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Showstopper Showstopper
Assignee: Periapse Linden
Reporter: darling brody
Votes: 1
Watchers: 2
Operations

If you were logged in you would be able to see more operations.
2. Second Life Service - SVC

MONO - llSetTimerEvent(0) is not stopping the timer! (clearing the event queue)

Created: 19/Sep/08 03:49 AM   Updated: 14/Oct/08 10:49 AM
Return to search
Component/s: None
Affects Version/s: 1.24 Server
Fix Version/s: None

Issue Links:
Relates

Linden Lab Issue ID: DEV-20933


 Description  « Hide
Before MONO rolled out to the grid the below code would not trigger a timer event. After MONO this code will incorrectly trigger a timer event.

It would appear that the event queue is not being cleared of unprocessed timer events when the timer is RESET. (note this error also occures if you set a new timer event. eg llSetTimer(60) can result in an immedialte trigger of the timer even if there are still timer events left in the event cue when you set a new timer.)

I have spent days chasing my tail trying to work out why reliable scripts have become unpredictable.

Correct behavior is for all pending timer events to be cleared when the timer is given a new value, and for the timer to start counting of the seconds again.

Note this is very similar behavior to the old llSensorRepeat triggering sensor events after llSensorRemove has been issued. The critical difference is that it's a new bug effecting existing code.

default
{
state_entry()

{ llSetTimerEvent(5); llSleep(10); llSetTimerEvent(0); }

timer()

{ llSay(0, "failed to reset"); }

}



 All   Comments   Change History      Sort Order: Ascending order - Click to sort in descending order
Catten Carter added a comment - 23/Sep/08 05:46 AM
I can't seem to repro this.

The timer is set to 5 sec, and after 10 sec, you clear it. This will result in one timer event being triggered, and it does?


Moon Metty added a comment - 23/Sep/08 12:40 PM
llSetTimerEvent(0) should always stop a previously set timer-event.

=======

// SVC-3099 llSleep triggers the bug
default
{
state_entry()

{ llSetTimerEvent(0.2); llSleep(0.2); llSetTimerEvent(0); }

timer()
{ llSay(0, "timer triggered"); }
}
// end

=======

// SVC-3099 llSetColor does not trigger the bug
default
{
state_entry()
{ llSetTimerEvent(0.2); llSetColor(<1, 1, 1>, ALL_SIDES); llSetTimerEvent(0); }
timer()
{ llSay(0, "timer triggered"); } }
}
// end

=======

// SVC-3099 llSleep-sweep
float base_time = 0.2;
float sweep_time = 0.01;
integer timer_triggered;
default
{
state_entry()

{ // start some event llSensor("you won't sense me", "", AGENT, 1, PI); }

no_sensor()
{ // try to trigger the bug
llSetTimerEvent(base_time);
llSleep(sweep_time);
llSetTimerEvent(0);

if (timer_triggered)

{ // the bug was triggered, restart the script llOwnerSay((string)sweep_time); llResetScript(); }

else

{ // the bug was not triggered, raise the time a bit, and try again sweep_time *= 1.01; llSensor("you won't sense me", "", AGENT, 1, PI); }

}
timer()

{ timer_triggered = TRUE; }

}
// end

=======

Is this a timer-bug, or a llSleep-bug?
It will take some sorting out...

In the llSleep-sweep script, you can see the longer the base_time is, the longer the sweep_time must be to trigger the bug.
During lagspikes, the bug occurs with much lower llSleep times.
LSL and Mono give similar results.

=======

Second Life 1.21.2 (96080) Sep 9 2008 09:42:01 (Second Life Release Candidate)
You are at 251717.3, 246597.0, 406.5 in Neptune located at sim4540.agni.lindenlab.com (63.210.158.190:12035)
Second Life Server 1.24.5.96115


Moon Metty added a comment - 23/Sep/08 02:02 PM
// SVC-3099 triggers once after compiling in Mono, but not in LSL
// Resetting never triggers the timer
default
{
state_entry() { llSetTimerEvent(0.01); llSetScale(<1, 1, 1>); llSetTimerEvent(0); }

timer()

{ llSay(0, "timer triggered"); }

}


Moon Metty added a comment - 23/Sep/08 02:34 PM - edited
Isn't llSleep() supposed to stop the progress of the [timer that triggers the] timer-event?

anthony reisman added a comment - 25/Sep/08 12:58 PM
I wouldn't think that llSleep should stop the timer progress. To me, that's the whole point of event queuing, the system is too busy (sleeping in this case) to handle the raised event. I wouldn't want llSetTimerEvent to clear an event queue completely, though if it could clear only timer events from the queue, I could see how that would be helful. Maybe a new function is needed, though so that we have both options.
1) llSetTimerEvent(0) stops any further events from being raised, but currently queued ones will still be processed.
2) llClearTimerEvents() clears any queued timer events.

darling brody added a comment - 26/Sep/08 08:35 PM - edited
llSetTimerEvent(0) is meant to stop the timer from triggering. however if the timer has elapsed before it is clearned with will have placed a timer event into the cue. If this even in the cue is not cleared when the timer is stopped, as it did before MONO, the result is lot of scripts out there that are triggering a timer even when they should not.

A typical use might be to read an external database (say for a stargate teleporter). the script sets a timer event as a timeout while requesting data using a HTTPRequest. The timer is cleared in the HTTPResponce event when the data is received. if the data is not received the timer() even will trigger and the script can re-request the data or give an error message. If the timer is not cleared in the HTTPResponce correctly under MONO (as with this bug) the result can be an error message being raised when there was no error. Locking a script into an endless loop of requesting data.

The llSleep command does not, has not, and should not pause the timer. All a llSleep does is give up it's share of the scripts processing time to other scripts until the x.x seconds have past. llSleep is not related to this problem, it is only used to simulate the timer taken by other processes that may be going on while the timer event is set. ie. the HTTPRequest used above.

You could use a llEmail in place of a llSleep, or any event that will last more than 5 seconds so the timer is due to be triggered at the point that it is reset to a new value.

Darling Brody


Moon Metty added a comment - 26/Sep/08 09:41 PM
Hmmm, that's funny

We have a new server now, and the bug doesn't seem to repro anymore.
Can you verify, Darling?

=======

Second Life 1.21.2 (96080) Sep 9 2008 09:42:01 (Second Life Release Candidate)
You are at 251721.3, 246592.8, 406.4 in Neptune located at sim4540.agni.lindenlab.com (63.210.158.190:13000)
Second Life Server 1.24.6.97433


Cappy Frantisek added a comment - 29/Sep/08 10:06 AM - edited
darling brody said:
"A typical use might be to read an external database (say for a stargate teleporter). the script sets a timer event as a timeout while requesting data using a HTTPRequest. The timer is cleared in the HTTPResponce event when the data is received. if the data is not received the timer() even will trigger and the script can re-request the data or give an error message. If the timer is not cleared in the HTTPResponce correctly under MONO (as with this bug) the result can be an error message being raised when there was no error. Locking a script into an endless loop of requesting data. "

I thought this to be the issues as well, so I tried some testing. Seems as it is not a bug but more a result of an incorrect use of the http_response time out. I used the following script:
[php]
key k;

default
{
state_entry()

{ llOwnerSay("started at - "+llGetSubString(llGetTimestamp(),11,18)); llSetTimerEvent(10.0); }

timer()

{ llSetTimerEvent(0.0); k = llHTTPRequest("http://xxx.xxx.xxx.xxx:xxxx/somethingtest.php",[],""); }

http_response(key r, integer i, list l, string b)
{
if(i==200)

{ llSetTimerEvent(10.0); llOwnerSay(b+" - "+llGetSubString(llGetTimestamp(),11,18)); }

else if(i==499)

{ llOwnerSay("server stopped responding"+" - "+llGetSubString(llGetTimestamp(),11,18)); }

}
}
[php]

This produced the following results (as expected):
[9:47] Object: started at - 16:47:47
[9:47] Object: on - 16:47:58
[9:48] Object: on - 16:48:08
[9:48] Object: on - 16:48:18
[9:48] Object: on - 16:48:28
[9:48] Object: on - 16:48:38
[9:49] Object: server stopped responding - 16:49:48

You have to remember, the http_response timeout is 60 seconds, therefore any timer that uses the llHTTPRequest will still be fired. What I did here was to stop the timer temporarily and then only refire if the server was active.

You are clearing, (llSetTimerEvent(0.0)??), the timer on valid response. Well the timer is still running while waiting for the http_response event to receive a 499 status code.

I hope this helps your coding, I had trouble with this as well when I first started to use llHTTPRequest.


darling brody added a comment - 04/Oct/08 08:00 AM
@Cappy Frantisek

You dont understand the problem. probably because I didnt descript it properly. let me try again

// excuse any compile errors, i typed this directly into the JIRA without testing it in world

// the main script calls the UpdateGate event to re-fresh it's details in the database when it gets a link message or some other trigger that has no bearing on the below code.

state UpdateGate
{
state_entry()

{ k = llHTTPRequest("http://xxx.xxx.xxx.xxx:xxxx/somethingtest.php",[],""); llSetTimerEvent(120); // give server 120 seconds to respond before retrying }

http_response(key r, integer i, list l, string b)

{ <---- do some stuff here to check we got the correct information. llSetTimerEvent(0); // stop the timer because we got the information we asked for. <--- and this is the timeout that can trigger when it shouldn't }

timer() // failed to get data. try again

{ k = llHTTPRequest("http://xxx.xxx.xxx.xxx:xxxx/somethingtest.php",[],""); llSetTimerEvent(120); // give server 120 seconds to respond before retrying }

}

As you can see the timer is being used to detect when HTTPRequest fails to get a responce. Of course you would have a lot more error checking in a real script, but you will still have a false fail if the timer is not reset and all pending timer events are cleared.