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