EntryPoint.hx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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;
  32. @:keep static function init() {
  33. mainThread = Thread.current();
  34. }
  35. #else
  36. static var sleepLock = new Lock();
  37. #end
  38. #end
  39. static var pending = new Array<Void->Void>();
  40. public static var threadCount(default, null):Int = 0;
  41. /**
  42. Wakeup a sleeping `run()`
  43. **/
  44. public static function wakeup() {
  45. #if (sys && !(target.threaded && !cppia))
  46. sleepLock.release();
  47. #end
  48. }
  49. public static function runInMainThread(f:Void->Void) {
  50. #if sys
  51. #if (target.threaded && !cppia)
  52. mainThread.events.run(f);
  53. #else
  54. mutex.acquire();
  55. pending.push(f);
  56. mutex.release();
  57. wakeup();
  58. #end
  59. #else
  60. pending.push(f);
  61. #end
  62. }
  63. public static function addThread(f:Void->Void) {
  64. #if sys
  65. mutex.acquire();
  66. threadCount++;
  67. mutex.release();
  68. #if (target.threaded && !cppia)
  69. mainThread.events.promise();
  70. #end
  71. Thread.create(function() {
  72. f();
  73. mutex.acquire();
  74. threadCount--;
  75. if (threadCount == 0)
  76. wakeup();
  77. mutex.release();
  78. #if (target.threaded && !cppia)
  79. mainThread.events.runPromised(() -> {});
  80. #end
  81. });
  82. #else
  83. threadCount++;
  84. pending.push(function() {
  85. f();
  86. threadCount--;
  87. });
  88. #end
  89. }
  90. static function processEvents():Float {
  91. #if (target.threaded && !cppia)
  92. return -1;
  93. #else
  94. // flush all pending calls
  95. while (true) {
  96. #if sys
  97. mutex.acquire();
  98. var f = pending.shift();
  99. mutex.release();
  100. #else
  101. var f = pending.shift();
  102. #end
  103. if (f == null)
  104. break;
  105. f();
  106. }
  107. var time = @:privateAccess MainLoop.tick();
  108. if (!MainLoop.hasEvents() && threadCount == 0)
  109. return -1;
  110. return time;
  111. #end
  112. }
  113. /**
  114. Start the main loop. Depending on the platform, this can return immediately or will only return when the application exits.
  115. **/
  116. @:keep public static function run() @:privateAccess {
  117. #if js
  118. var nextTick = processEvents();
  119. inline function setTimeoutNextTick() {
  120. if (nextTick >= 0) {
  121. (untyped setTimeout)(run, nextTick * 1000);
  122. }
  123. }
  124. #if nodejs
  125. setTimeoutNextTick();
  126. #else
  127. if(js.Lib.typeof(js.Browser.window) != 'undefined') {
  128. var window:Dynamic = js.Browser.window;
  129. var rqf:Dynamic = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame;
  130. if(rqf != null) {
  131. rqf(run);
  132. } else {
  133. setTimeoutNextTick();
  134. }
  135. } else {
  136. setTimeoutNextTick();
  137. }
  138. #end
  139. #elseif flash
  140. flash.Lib.current.stage.addEventListener(flash.events.Event.ENTER_FRAME, function(_) processEvents());
  141. #elseif (target.threaded && !cppia)
  142. //everything is delegated to sys.thread.EventLoop
  143. #elseif sys
  144. while (true) {
  145. var nextTick = processEvents();
  146. if (nextTick < 0)
  147. break;
  148. if (nextTick > 0)
  149. sleepLock.wait(nextTick); // wait until nextTick or wakeup() call
  150. }
  151. #else
  152. // no implementation available, let's exit immediately
  153. #end
  154. }
  155. }