package haxe; #if (target.threaded && !cppia) import sys.thread.Lock; import sys.thread.Mutex; import sys.thread.Thread; #elseif sys private class Lock { public function new() {} public inline function release() {} public inline function wait(?t:Float) {} } private class Mutex { public function new() {} public inline function acquire() {} public inline function release() {} } private class Thread { public static function create(f:Void->Void) { f(); } } #end /** If `haxe.MainLoop` is kept from DCE, then we will insert an `haxe.EntryPoint.run()` call just at then end of `main()`. This class can be redefined by custom frameworks so they can handle their own main loop logic. **/ class EntryPoint { #if sys static var mutex = new Mutex(); #if (target.threaded && !cppia) static var mainThread:Thread = Thread.current(); #else static var sleepLock = new Lock(); #end #end static var pending = new ArrayVoid>(); public static var threadCount(default, null):Int = 0; /** Wakeup a sleeping `run()` **/ public static function wakeup() { #if (sys && !(target.threaded && !cppia)) sleepLock.release(); #end } public static function runInMainThread(f:Void->Void) { #if sys #if (target.threaded && !cppia) mainThread.events.run(f); #else mutex.acquire(); pending.push(f); mutex.release(); wakeup(); #end #else pending.push(f); #end } public static function addThread(f:Void->Void) { #if sys mutex.acquire(); threadCount++; mutex.release(); #if (target.threaded && !cppia) mainThread.events.promise(); #end Thread.create(function() { f(); mutex.acquire(); threadCount--; if (threadCount == 0) wakeup(); mutex.release(); #if (target.threaded && !cppia) mainThread.events.runPromised(() -> {}); #end }); #else threadCount++; pending.push(function() { f(); threadCount--; }); #end } static function processEvents():Float { #if (target.threaded && !cppia) return -1; #else // flush all pending calls while (true) { #if sys mutex.acquire(); var f = pending.shift(); mutex.release(); #else var f = pending.shift(); #end if (f == null) break; f(); } var time = @:privateAccess MainLoop.tick(); if (!MainLoop.hasEvents() && threadCount == 0) return -1; return time; #end } /** Start the main loop. Depending on the platform, this can return immediately or will only return when the application exits. **/ @:keep public static function run() @:privateAccess { #if js var nextTick = processEvents(); inline function setTimeoutNextTick() { if (nextTick >= 0) { (untyped setTimeout)(run, nextTick * 1000); } } #if nodejs setTimeoutNextTick(); #else if(js.Lib.typeof(js.Browser.window) != 'undefined') { var window:Dynamic = js.Browser.window; var rqf:Dynamic = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame; if(rqf != null) { rqf(run); } else { setTimeoutNextTick(); } } else { setTimeoutNextTick(); } #end #elseif flash flash.Lib.current.stage.addEventListener(flash.events.Event.ENTER_FRAME, function(_) processEvents()); #elseif (target.threaded && !cppia) //everything is delegated to sys.thread.EventLoop #elseif sys while (true) { var nextTick = processEvents(); if (nextTick < 0) break; if (nextTick > 0) sleepLock.wait(nextTick); // wait until nextTick or wakeup() call } #else // no implementation available, let's exit immediately #end } }