SRL Archive - Bugs

TTimers


Shuttleu

2010-07-21 17:01:35

i cant get TTimers to work
this is what i have
program New;

var
Timer: TTimer;
t: Integer;

Procedure hi(Sender: TObject);

begin
writeln('hi');
end;

Procedure CreateTimer;

Begin
Timer := TTimer.Create(nil);
Timer.Interval := 2000;
Timer.Enabled := True;
Timer.OnTimer := @hi;
End;

Procedure DeleteTimer;

Begin
Timer.Enabled := False;
Timer.Free;
End;

Procedure ScriptTerminate;

Var
V: TVariantArray;

Begin
SetLength(V, 0);
ThreadSafeCall('DeleteTimer', V);
Writeln(IntToStr(getsystemtime - t));
End;

Var
V: TVariantArray;
begin
SetLength(V, 0);
ThreadSafeCall('CreateTimer', V);
t := getsystemtime;
Repeat
Wait(100);
Until getsystemtime - t > 8000;
end.
and as you can see it doesnt even output anything when it ends which suggests that it doesnt even call ScriptTerminate

~shut

EDIT: forgot to say, this works perfectly in SCAR 3.22

i luffs yeww

2010-07-21 17:08:41

How could it not call ScriptTerminate? 'o.O

Shuttleu

2010-07-21 17:16:09

i dont know, but my simba just crashed and that script is the only thing that i have run in that one

so there is a problem…

~shut

Wizzup?

2010-07-21 17:23:40

Simba does not call ScriptTerminate this way, see the simba compatibility file in SRL. Use SetScriptProp(SP_OnTerminate, etc)

As for the timer stopping after one run, we'll have to investigate.

Rick

2010-07-21 17:24:32

Use


function AddOnTerminate(const proc : string) : boolean;
var
OldProcs : TVariantArray;
i : integer;
begin
result := false;
GetScriptProp(SP_OnTerminate,OldProcs);
for i := 0 to high(OldProcs) do
if lowercase(OldProcs[i]) = lowercase(proc) then
exit;
setlength(OldProcs,Length(OldProcs)+1);
OldProcs[high(OldProcs)] := proc;
SetScriptProp(SP_OnTerminate,oldprocs);
result := True;
end;

Then add:


AddOnTerminate('ScriptTerminate');

to the Main Loop.

(Taken from SRL/SRL/Core/Simba.simba)

Wizzup?

2010-07-21 17:38:39

This is a really funny/nasty bug. ;)


procedure psWriteln(str : string); extdecl;
begin
if CurrThread.Prop.WriteTimeStamp then
str := format('[%s]: %s', [TimeToStr(TimeStampToDateTime(MSecsToTimeStamp(GetTickCount - CurrThread.StartTime))), str]);
if Assigned(CurrThread.DebugTo) then
CurrThread.DebugTo(str)
else
mDebugLn(str);
end;

CurrThread is a threadvar which means it is specific to each thread.
The TTimer's writeln is called on the main thread, the main thread obviously has no CurrThread, so it will segfault as it tries to access invalid memory (0x0 + position of.Prop)

Fix would probably be to check whether CurrThread is valid or not.

E: For ThreadSafeCall normal use, this is not an issue, as the other thread's data is passed to the main thread, but since the TTimer calls stuff on the main thread all by itself, it causes a serious problem.

Wizzup?

2010-07-21 17:46:53

It will be trickier to make it write to the debug though, as the main thread on itself can control the form, but the way we set it up the unit mmlpsthread has no knowledge of any form whatsoever.

Cigue

2010-07-21 17:50:45

Not sure if I'm the only one who's wondered this so far, but what the snoot is a TTimer?

NCDS

2010-07-21 18:24:46

From: Cigue
Not sure if I'm the only one who's wondered this so far, but what the snoot is a TTimer?


http://villavu.com/forum/showpost.php?p=520210 ;)

Nava2

2010-07-21 18:35:44

Thus, all in all.. TTimer's work, just you can't use them to writeln.

So, just use it as you would like, and just don't ask it to writeln. :p

TTimers work in extensions, Wizzup.

Wizzup?

2010-07-21 18:38:55

From: Nava2
Thus, all in all.. TTimer's work, just you can't use them to writeln.

So, just use it as you would like, and just don't ask it to writeln. :p

TTimers work in extensions, Wizzup.


I know they work in Extensions, because Extensions work different from the scripts. There's probably a bit more you can't do than just writeln, but it's an example. Still, I can patch this by changing the writeln to only write to the cmd window, but that would only be a quick fix. There's probably a couple of other things it cannot do as well. (Like, everything that uses CurrThread, which is just about any MML procedure)

Nava2

2010-07-21 18:58:15

Might be excessive, but would there be a way to spawn a thread per TTimer created?

Its not like they are very common, but they are useful.

Wizzup?

2010-07-21 18:59:05

From: Nava2
Might be excessive, but would there be a way to spawn a thread per TTimer created?

Its not like they are very common, but they are useful.


How would this help and how would you implement this?

Wizzup?

2010-07-22 15:27:50

There are a few solutions to this, none of them are simple.

  • Only allow one script per Simba instance to run. (like SCAR)
  • Don't mess too much with forms.
  • Go from Threads to Processes

Shuttleu

2010-07-22 15:29:06

what would be the disadvantage of switchning from threads to processes?

~shut

Nava2

2010-07-22 15:42:32

From: Shuttleu
what would be the disadvantage of switchning from threads to processes?

~shut


Read the thread he linked to.

Wizzup?

2010-07-22 16:11:21

From: Shuttleu
what would be the disadvantage of switchning from threads to processes?

~shut


It would be much more complex to implement. There are no real disadvantages.
Advantages: Scripts run their own process and can all have their own separate plugins, forms, etc. And if the script crashes somehow, it doesn't kill the Simba GUI. Note that this is really close to the Simba Daemon… http://villavu.com/wiki/Simba_Daemon

Wizzup?

2010-07-22 18:04:02

Shuttleu/everyone else, I have bumped Simba unstable branch to 704, which now uses a single thread only. Mind you, I did this quickly and I am not sober. It works for me however, perhaps you can give it a go? (Mess with pausing the script as well, etc)

Switch to unstable by changing the '/Stable/" to "/Unstable/" in the URLs in the following settings: Settings/Updater/RemoteLink, Settings/Updater/RemoteVersionLink.

E: You can also switch by shutting down all Simba.exe instances, deleting it and downloading this Simba.exe in here: http://simba.villavu.com/bin/Windows/x86/Unstable/
That way you don't need to modify the settings, and you will go back to stable once I push the upcoming 705 to stable.


program New;

var
Timer: TTimer;
t: Integer;

Procedure hi(Sender: TObject);

begin
writeln('hi');
writeln(getcolor(50,50));
end;

Procedure CreateTimer;

Begin
Timer := TTimer.Create(nil);
Timer.interval := 2000;
Timer.ontimer := @hi;
Timer.enabled := true;
End;

Procedure DeleteTimer;

Begin
Timer.enabled := false;
Timer.Free;
End;

Var
V, Stop: TVariantArray;
begin
Stop := ['DeleteTimer'];
SetScriptProp(SP_OnTerminate, Stop);

SetLength(V, 0);
ThreadSafeCall('CreateTimer', V);
t := getsystemtime;
Repeat
Wait(100);
Until getsystemtime - t > 8000;
end.

E2: Note that other usage like not properly freeing the TTimer WILL lead to crashes, and will eventually crash Simba. There's nothing we can do about this. (Except when we use processes, then Simba itself will not crash)
So code wisely.

Shuttleu

2010-07-22 18:46:42

just had a quick test and it seems to be working fine, at least it handles it better than SCAR

if you run the script in my first post then pause it while its running it will crash scar
but in simba it continues to call hi

whether its ment to still call hi when its paused or not i dont know, but i like it calling hi while its paused, especially when its being used for progress reports

~shut

mastaraymond

2010-07-23 11:39:09

Timers are not made for these purposes.. Full stop. Scripts run in there own thread whereas a timer executes on the mainthread because it need procesmessages to be called (the internals of a ttimer suck.. Basically it needs a proc to be called fucking often and then it compares the last time it was called and wheter it shuld execute the ontimer). So make your own sorta timer if you want to have something like that OUTSIDE of a form (in showmodal its perfectly acceptable to use a timer, as it is designed for forms..)

Scripts are not multithreaded, dont bother dodgy workarounds.

Wizzup?

2010-07-23 12:03:03

From: mastaraymond
Timers are not made for these purposes.. Full stop. Scripts run in there own thread whereas a timer executes on the mainthread because it need procesmessages to be called (the internals of a ttimer suck.. Basically it needs a proc to be called fucking often and then it compares the last time it was called and wheter it shuld execute the ontimer). So make your own sorta timer if you want to have something like that OUTSIDE of a form (in showmodal its perfectly acceptable to use a timer, as it is designed for forms..)

Scripts are not multithreaded, dont bother dodgy workarounds.


Shall I revert the commit then? I fear the same problem occurs when you use a form .Show though.

Shuttleu

2010-07-23 15:15:51

it turns out that when i use a TTimer in a script anyway it seems to crash/close/terminate simba, so yea you can revert if you want, as there is no real advantage unless someone was to use it in a form

~shut