123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- package haxe;
- import haxe.EntryPoint;
- #if (target.threaded && !cppia)
- import sys.thread.EventLoop;
- import sys.thread.Thread;
- #end
- class MainEvent {
- var f:Void->Void;
- var prev:MainEvent;
- var next:MainEvent;
- /**
- Tells if the event can lock the process from exiting (default:true)
- **/
- public var isBlocking:Bool = true;
- public var nextRun(default, null):Float;
- public var priority(default, null):Int;
- function new(f, p) {
- this.f = f;
- this.priority = p;
- nextRun = Math.NEGATIVE_INFINITY;
- }
- /**
- Delay the execution of the event for the given time, in seconds.
- If t is null, the event will be run at tick() time.
- **/
- public function delay(t:Null<Float>) {
- nextRun = t == null ? Math.NEGATIVE_INFINITY : haxe.Timer.stamp() + t;
- }
- /**
- Call the event. Will do nothing if the event has been stopped.
- **/
- public inline function call() {
- if (f != null)
- f();
- }
- /**
- Stop the event from firing anymore.
- **/
- public function stop() {
- if (f == null)
- return;
- f = null;
- nextRun = Math.NEGATIVE_INFINITY;
- if (prev == null)
- @:privateAccess MainLoop.pending = next;
- else
- prev.next = next;
- if (next != null)
- next.prev = prev;
- }
- }
- @:access(haxe.MainEvent)
- class MainLoop {
- #if (target.threaded && !cppia)
- static var eventLoopHandler:Null<EventHandler>;
- static var mutex = new sys.thread.Mutex();
- static var mainThread = Thread.current();
- #end
- static var pending:MainEvent;
- public static var threadCount(get, never):Int;
- inline static function get_threadCount()
- return EntryPoint.threadCount;
- public static function hasEvents() {
- var p = pending;
- while (p != null) {
- if (p.isBlocking)
- return true;
- p = p.next;
- }
- return false;
- }
- public static function addThread(f:Void->Void) {
- EntryPoint.addThread(f);
- }
- public static function runInMainThread(f:Void->Void) {
- EntryPoint.runInMainThread(f);
- }
- /**
- Add a pending event to be run into the main loop.
- **/
- public static function add(f:Void->Void, priority = 0):MainEvent@:privateAccess {
- if (f == null)
- throw "Event function is null";
- var e = new MainEvent(f, priority);
- var head = pending;
- if (head != null)
- head.prev = e;
- e.next = head;
- pending = e;
- injectIntoEventLoop(0);
- return e;
- }
- static function injectIntoEventLoop(waitMs:Int) {
- #if (target.threaded && !cppia)
- mutex.acquire();
- if(eventLoopHandler != null)
- mainThread.events.cancel(eventLoopHandler);
- eventLoopHandler = mainThread.events.repeat(
- () -> {
- mainThread.events.cancel(eventLoopHandler);
- var wait = tick();
- if(hasEvents()) {
- injectIntoEventLoop(Std.int(wait * 1000));
- }
- },
- waitMs
- );
- mutex.release();
- #end
- }
- static function sortEvents() {
- // pending = haxe.ds.ListSort.sort(pending, function(e1, e2) return e1.nextRun > e2.nextRun ? -1 : 1);
- // we can't use directly ListSort because it requires prev/next to be public, which we don't want here
- // we do then a manual inline, this also allow use to do a Float comparison of nextRun
- var list = pending;
- if (list == null)
- return;
- var insize = 1, nmerges, psize = 0, qsize = 0;
- var p, q, e, tail:MainEvent;
- while (true) {
- p = list;
- list = null;
- tail = null;
- nmerges = 0;
- while (p != null) {
- nmerges++;
- q = p;
- psize = 0;
- for (i in 0...insize) {
- psize++;
- q = q.next;
- if (q == null)
- break;
- }
- qsize = insize;
- while (psize > 0 || (qsize > 0 && q != null)) {
- if (psize == 0) {
- e = q;
- q = q.next;
- qsize--;
- } else if (qsize == 0
- || q == null
- || (p.priority > q.priority || (p.priority == q.priority && p.nextRun <= q.nextRun))) {
- e = p;
- p = p.next;
- psize--;
- } else {
- e = q;
- q = q.next;
- qsize--;
- }
- if (tail != null)
- tail.next = e;
- else
- list = e;
- e.prev = tail;
- tail = e;
- }
- p = q;
- }
- tail.next = null;
- if (nmerges <= 1)
- break;
- insize *= 2;
- }
- list.prev = null; // not cycling
- pending = list;
- }
- /**
- Run the pending events. Return the time for next event.
- **/
- static function tick() {
- sortEvents();
- var e = pending;
- var now = haxe.Timer.stamp();
- var wait = 1e9;
- while (e != null) {
- var next = e.next;
- var wt = e.nextRun - now;
- if (wt <= 0) {
- wait = 0;
- e.call();
- } else if (wait > wt)
- wait = wt;
- e = next;
- }
- return wait;
- }
- }
|