1

Trying to create a simple command-line application in Haxe which has a ticking Timer, but it does not seem to work out; the Timer never actually starts 'ticking'.

package;

import haxe.Timer;

class TimerCallback {
    private static inline var CHAR_SPACE : Int = 32;

    public static function main() : Void {
        var myME = new TimerTicker();
        while (Sys.getChar(false) != CHAR_SPACE) {
            //loop until [space] detected, do nothing here
        }
    }
}

class TimerTicker {
    private var myTimer : Timer = null;

    public function new() {
        myTimer = new Timer(20);
        myTimer.run = timer_OnTick;
    }

    private function timer_OnTick() : Void {
        Sys.println ("foobar");
    }
/* destructor?! */
}


And this is the build command:

>haxe.exe -lib nme -main TimerCallback -cpp .\bin

If I am not adding -lib nme, the code does not compile (based on API doc it's OK as Timer is not supported for cpp, so only static functions are available)

If I am adding this, however, the code is compiled -as nme supports cpp Timers-, and the exe is created (win), but timer_OnTick() is never called. So exe starts, nothing happens, one press SPACE and app. quits.

Additional info:
- The imported Timer.hx file is this one: haxe\lib\nme\5,1,8\haxe. And if I am right, this should be OK & working.
- Using haxe 3.1.3, nme 5.1.8, hxcpp 3.1.39 (and haxelib 3.1.0-rc.4 if matters)

Any help would be much appreciated.

1 Answer 1

1

Okay, I've got help from the Haxe Community (mailing list). Here are the solutions if anyone happen to need them:

PSEUDO CODE (not tested)

class RunLoop {
   static var queue = new Deque<Void->Void>();
   static var keepAlives:Int; = 1;

static public function release() enque(function () keepAlives--);

static public function retain() enque(function () keepAlives++);

static public function enque(task:Void->Void) queue.add(task);

static function main() { enque(entryPoint); release(); } static function entryPoint() { //code goes here } static function run() while (keepAlives:Int > 0) queue.pop()(); }

//Now you can go an implement a timer like so:

class Timer { var active:Bool = true; public function new(msecs:Int) { RunLoop.retain(); Thread.create(function () while(active) { Sys.sleep(msecs / 1000); if (active) RunLoop.enque(this.run); }); } public dynamic function run() {} public function stop() { active = false; RunLoop.release(); } }

//And a helper for blocking code:

class Task { var task:Void->T; var onDone:T->Void; public function new(task:Void->T, onDone:T->Void) { RunLoop.retain(); Thread.create(function () { var result = task(); RunLoop.enque(onDone.bind(result)); }); } }

//So then the code you want would look roughly like this:

static function entryPoint() { var timer = new Timer(); timer.run = function () trace('foobar'); function waitForSpace() { while (Sys.getChar(false) != CHAR_SPACE) { //loop until [space] detected, do nothing here } return true; } new Task( waitForSpace, function (_) timer.stop() //stop the timer so that the run loop can exit ); }

(solution provided by back2dos)

/*
1. Neko : works
2. C++: works, However, incrementing count in the if statement instead ( if( count++ == 0 ) { ... ) fails to increment count!  Fixed on Git?
3. Flash : works
4. Java : fails using Haxe 3.1.3
*/

### build.hxml ###

-main Main -swf main.swf -swf-version 12

--next

-main Main -neko main.n

--next

-main Main -cpp cpp -cmd cp cpp/Main ./main

--next

-main Main -java java -cmd cp java/Main.jar ./main-jar

### Main.hx ###

class Main { public static function main() { #if sys var count = 0; while( true ) { if( count == 0 ) { Timer.delay(function() trace("doThing1"), 3000); Timer.delay(function() trace("doThing2"), 1000); count++; } } #else Timer.delay(function() trace("doThing1"), 3000); Timer.delay(function() trace("doThing2"), 1000); #end } }

### Timer.hx ###

#if neko import neko.vm.Deque; import neko.vm.Thread; import neko.vm.Mutex; import neko.vm.Lock; #elseif cpp import cpp.vm.Deque; import cpp.vm.Thread; import cpp.vm.Mutex; import cpp.vm.Lock; #elseif java import java.vm.Deque; import java.vm.Thread; import java.vm.Mutex; import java.vm.Lock; #end

class Timer { #if sys static var timerThread : TimerThread; #else static var timers : Array; #end

static function __init__() {
    #if sys
    timerThread = new TimerThread();
    #else
    timers = [];
    #end
}

public static function stop() {
    #if sys
    timerThread.quit();
    #else
    for( t in timers )
        t.stop();
    #end
}

public static function delay( func : Void -> Void, delayMillis : Int ) {
    #if sys
    timerThread.addTimer(delayMillis/1000, func);
    #else
    timers.push( haxe.Timer.delay(func, delayMillis) );
    #end
}

} #if sys typedef TTimerData = { time : Float, func : Void -> Void
}

class TimerThread { var mutex : Mutex; var queueLock : Lock; var queue : Array; var running : Bool; public function new() { queue = []; queueLock = new Lock(); mutex = new Mutex(); running = true; Thread.create( mainLoop ); } public function addTimer( delaySec : Float, cb : Void -> Void ) { mutex.acquire(); var time = haxe.Timer.stamp() + delaySec; var index = 0; while( index < queue.length && time >= queue[index].time ) index++; queue.insert(index, { time : time, func : cb }); mutex.release(); queueLock.release(); } public function quit( ?cb : Void -> Void ) { var me = this; addTimer( 0, function() { me.running = false; if( cb != null ) cb(); } ); } function mainLoop() { while( running ) { var wake : Null = null; var now = haxe.Timer.stamp(); var ready = new Array(); mutex.acquire(); while( queue.length > 0 ) if( queue[0].time <= now ) ready.push(queue.shift()); else { wake = queue[0].time; break; } mutex.release(); for( d in ready ) { d.func(); if( !running ) break; } if( !running ) break; if( wake == null ) queueLock.wait(); else { var delay = wake - haxe.Timer.stamp(); if( delay > 0 ) queueLock.wait(delay); } } } } #end

(Solution provided by Zjnue, modified code of Hugh)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.