EntryPoint.hx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. package haxe;
  2. #if (target.threaded && !cppia)
  3. import sys.thread.Lock;
  4. import sys.thread.Mutex;
  5. import sys.thread.Thread;
  6. #elseif sys
  7. private class Lock {
  8. public function new() {}
  9. public inline function release() {}
  10. public inline function wait(?t:Float) {}
  11. }
  12. private class Mutex {
  13. public function new() {}
  14. public inline function acquire() {}
  15. public inline function release() {}
  16. }
  17. private class Thread {
  18. public static function create(f:Void->Void) {
  19. f();
  20. }
  21. }
  22. #end
  23. /**
  24. If `haxe.MainLoop` is kept from DCE, then we will insert an `haxe.EntryPoint.run()` call just at then end of `main()`.
  25. This class can be redefined by custom frameworks so they can handle their own main loop logic.
  26. **/
  27. class EntryPoint {
  28. #if sys
  29. static var mutex = new Mutex();
  30. #if (target.threaded && !cppia)
  31. static var mainThread:Thread = Thread.current();
  32. #else
  33. static var sleepLock = new Lock();
  34. #end
  35. #end
  36. static var pending = new Array<Void->Void>();
  37. public static var threadCount(default, null):Int = 0;
  38. /**
  39. Wakeup a sleeping `run()`
  40. **/
  41. public static function wakeup() {
  42. #if (sys && !(target.threaded && !cppia))
  43. sleepLock.release();
  44. #end
  45. }
  46. public static function runInMainThread(f:Void->Void) {
  47. #if sys
  48. #if (target.threaded && !cppia)
  49. mainThread.events.run(f);
  50. #else
  51. mutex.acquire();
  52. pending.push(f);
  53. mutex.release();
  54. wakeup();
  55. #end
  56. #else
  57. pending.push(f);
  58. #end
  59. }
  60. public static function addThread(f:Void->Void) {
  61. #if sys
  62. mutex.acquire();
  63. threadCount++;
  64. mutex.release();
  65. #if (target.threaded && !cppia)
  66. mainThread.events.promise();
  67. #end
  68. Thread.create(function() {
  69. f();
  70. mutex.acquire();
  71. threadCount--;
  72. if (threadCount == 0)
  73. wakeup();
  74. mutex.release();
  75. #if (target.threaded && !cppia)
  76. mainThread.events.runPromised(() -> {});
  77. #end
  78. });
  79. #else
  80. threadCount++;
  81. pending.push(function() {
  82. f();
  83. threadCount--;
  84. });
  85. #end
  86. }
  87. static function processEvents():Float {
  88. #if (target.threaded && !cppia)
  89. return -1;
  90. #else
  91. // flush all pending calls
  92. while (true) {
  93. #if sys
  94. mutex.acquire();
  95. var f = pending.shift();
  96. mutex.release();
  97. #else
  98. var f = pending.shift();
  99. #end
  100. if (f == null)
  101. break;
  102. f();
  103. }
  104. var time = @:privateAccess MainLoop.tick();
  105. if (!MainLoop.hasEvents() && threadCount == 0)
  106. return -1;
  107. return time;
  108. #end
  109. }
  110. /**
  111. Start the main loop. Depending on the platform, this can return immediately or will only return when the application exits.
  112. **/
  113. @:keep public static function run() @:privateAccess {
  114. #if js
  115. var nextTick = processEvents();
  116. inline function setTimeoutNextTick() {
  117. if (nextTick >= 0) {
  118. (untyped setTimeout)(run, nextTick * 1000);
  119. }
  120. }
  121. #if nodejs
  122. setTimeoutNextTick();
  123. #else
  124. if(js.Lib.typeof(js.Browser.window) != 'undefined') {
  125. var window:Dynamic = js.Browser.window;
  126. var rqf:Dynamic = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
  127. if(rqf != null) {
  128. rqf(run);
  129. } else {
  130. setTimeoutNextTick();
  131. }
  132. } else {
  133. setTimeoutNextTick();
  134. }
  135. #end
  136. #elseif flash
  137. flash.Lib.current.stage.addEventListener(flash.events.Event.ENTER_FRAME, function(_) processEvents());
  138. #elseif (target.threaded && !cppia)
  139. //everything is delegated to sys.thread.EventLoop
  140. #elseif lua
  141. inline function luvRun(mode:String):Bool
  142. return untyped __lua__('_hx_luv.run({0})', mode);
  143. while (true) {
  144. var nextTick = processEvents();
  145. if(untyped __lua__('_hx_luv.loop_alive()')) {
  146. if(nextTick < 0)
  147. luvRun("once")
  148. else
  149. luvRun("nowait");
  150. } else {
  151. if (nextTick < 0)
  152. break;
  153. if (nextTick > 0)
  154. sleepLock.wait(nextTick);
  155. }
  156. }
  157. #elseif sys
  158. while (true) {
  159. var nextTick = processEvents();
  160. if (nextTick < 0)
  161. break;
  162. if (nextTick > 0)
  163. sleepLock.wait(nextTick); // wait until nextTick or wakeup() call
  164. }
  165. #else
  166. // no implementation available, let's exit immediately
  167. #end
  168. }
  169. }