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