166 lines
3.5 KiB
Haxe
166 lines
3.5 KiB
Haxe
|
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 Array<Void->Void>();
|
||
|
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
|
||
|
}
|
||
|
}
|