tags:

views:

357

answers:

3

As every haXe developer knows, you could use haxe.Timer.delayed() to delay function call for some time. But this function doesn't exist for neko at all. Is there a way to achieve the same results?

+2  A: 

Have to check it first but

function delayed(f, time) {
   neko.vm.Thread.create(function() {
       neko.Sys.sleep(time);
       f();
   });
}

might be the closest thing possible. The only cons is that application becomes multi threaded which could lead to serious problems.

vava
What kind of problems if you only create a thread for this purpose?
Tom
@Tom, function f() is going to be executed in context of another thread. It might use shared resources or call other functions, that do use shared resources. Nothing really special about this case, just normal multithreaded application.
vava
In that case it's probably best to create the Neko application with haXe. Why don't you do that?
Tom
@Tom, I do that :) But `haxe.Timer` have just one method under neko or php, `stamp()`. `delayed()` is available on all other platforms but not in neko.
vava
Ah I see. In that case, I recommend you to create your own Timer class for neko. The static constructor would create a new thread, which simply loops at a certain interval, keeping track of timestamps and registering newly added timers. Good luck. If you're going to do this, it would be great if you could share the class for the haXe community.
Tom
Update: I worked on this tonight, see my answer.
Tom
A: 

Yes I don't know anything except for what you mention in your first answer. On Linux you can use SIGALARM - but this doesn't look trivial, 100% pure C code, and needs to be handled with great care to avoid crashing the VM.

Michael Pliskin
A: 

I thought about your issue and I think the best way is to create your own Timer class for Neko. I made a Timer class for you:

NekoTimer.hx

package;
import neko.Sys;

    class NekoTimer 
    {
    private static var threadActive:Bool = false;
    private static var timersList:Array<TimerInfo> = new Array<TimerInfo>();
    private static var timerInterval:Float = 0.1;

    public static function addTimer(interval:Int, callMethod:Void->Void):Int
    {
        //setup timer thread if not yet active
        if (!threadActive) setupTimerThread();

        //add the given timer
        return timersList.push(new TimerInfo(interval, callMethod, Sys.time() * 1000)) - 1;
    }

    public static function delTimer(id:Int):Void
    {
        timersList.splice(id, 1);
    }

    private static function setupTimerThread():Void
    {
        threadActive = true;
        neko.vm.Thread.create(function() {
            while (true) {
                Sys.sleep(timerInterval);
                for (timer in timersList) {
                    if (Sys.time() * 1000 - timer.lastCallTimestamp >= timer.interval) {
                        timer.callMethod();
                        timer.lastCallTimestamp = Sys.time() * 1000;
                    }
                }
            }
        });
    }
}

private class TimerInfo
{
    public var interval:Int;
    public var callMethod:Void->Void;
    public var lastCallTimestamp:Float;

    public function new(interval:Int, callMethod:Void->Void, lastCallTimestamp:Float) {
        this.interval = interval;
        this.callMethod = callMethod;
        this.lastCallTimestamp = lastCallTimestamp;
    }
}

Call it like this:

package ;

import neko.Lib;

class Main 
{
    private var timerId:Int;

    public function new()
    {
        trace("setting up timer...");
        timerId = NekoTimer.addTimer(5000, timerCallback);
        trace(timerId);

        //idle main app
        while (true) { }
    }

    private function timerCallback():Void
    {
        trace("it's now 5 seconds later");
        NekoTimer.delTimer(timerId);
        trace("removed timer");
    }

    //neko constructor
    static function main() 
    {
        new Main();
    }
}

Hope that helps.

Note: this one has an accuracy of 100ms. You can increase this by decreasing the timerInterval setting.

Tom
As much as I support your effort, this does not solve anything :) Callback will still be run in the context of different thread, the one you have created in the class, as there's no way you can migrate it to the main one.
vava
Actually I realized this when I went to bed... I'm going to ask about this issue on the haxe mailing list.
Tom