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
 | 
						|
	}
 | 
						|
}
 |