Created
March 6, 2016 12:29
-
-
Save hughsando/91a19a61a82bf8b7a9e6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class IScheduleClient | |
{ | |
public function getNextWake():Float; | |
public function onPoll():Void; | |
} | |
class Scheduler | |
{ | |
public static var INFINITE(default,null) = 1e20; | |
static var frameworkAsyncWake:Void->Void; | |
static var clientsChangedinPollCallback:Int; | |
static var mainThreadJobs:Array<Void->Void>; | |
static var clients:Array<IScheduleClient>; | |
static var clientPos; | |
static var activeThreads = 0; | |
#if !(browser || flash) | |
static var waitEvent:sys.vm.WaitableEvent; | |
#end | |
public static function registerFramework(onWake:Void->Void) | |
{ | |
frameworkAsyncWake = onWake; | |
} | |
// Must be called from the main thread... | |
public static function addClient(client:IScheduleClient) | |
{ | |
if (clients==null) | |
clients = [client]; | |
else | |
clients.push(client); | |
} | |
// Must be called from the main thread... | |
public static function removeClient(client:IScheduleClient) | |
{ | |
var index = client.indexOf(client); | |
if (index<0) throw "huh"; | |
// clientPos will be incremented in the loop (this needs to be tested) | |
if (index <= clientPos) | |
clientPos--; | |
clients.removeAt(index) | |
} | |
// Can be called from any thread | |
public static function wakeMainLoop() | |
{ | |
#if !(browser || flash) | |
if (waitEvent!=null) | |
waitEvent.signal(); | |
else | |
#end | |
if (frameworkAsyncWake!=null) | |
frameworkAsyncWake(); | |
} | |
// may be called directly by framework | |
public static function poll() | |
{ | |
var jobs:Array<Void->Void> = null; | |
jobsMutex.lock(); | |
jobs = mainThreadJobs; | |
mainThreadJobs = null; | |
if (clients.length==0 && activeThreads==0 && (jobs==null || jobs.length==0)) | |
break; | |
jobsMutex.unlock(); | |
if (jobs!=null) | |
for(job in jobs) | |
job(); | |
// It it tricky to process clients exactly once in the face of | |
// clients being added and removed in the onPoll callbacks. | |
// Taking a copy of the array should be avoided if possible... | |
clientPos = 0; | |
while(clientPos<client.length) | |
{ | |
clients[clientPos].onPoll(); | |
clientPos++; | |
} | |
clientPos = -1; | |
} | |
public static function getNextWake() | |
{ | |
// How long to sleep for.... | |
var nextWake = INFINITE; | |
for(client in clients) | |
{ | |
var clientWake = client.getNextWake(); | |
if (clientWake<nextWake) | |
nextWake = clientWake; | |
} | |
} | |
// Macro magic - inject if class is used | |
public static function mainLoop() | |
{ | |
// No framework registered? | |
#if !(browser || flash) | |
if (asynkWake==null && clients!=null) | |
{ | |
waitEvent = new sys.vm.WaitableEvent(); | |
while(true) | |
{ | |
poll(); | |
if (clients.length==0 && activeThreads==0 && (jobs==null || jobs.length==0)) | |
break; | |
var nextWake = getNextWake(); | |
if (nextWake>0) | |
{ | |
if (nextWake==INFINITE) | |
waitEvent.wait(); | |
else | |
waitEvent.wait(nextWake); | |
} | |
} | |
} | |
#end | |
} | |
public static function createThread(threadFunc:Void->Void) | |
{ | |
// Interlock increment... | |
activeThreads++; | |
sys.createThread( function() { | |
threadFunc(); | |
/* Interlock decrment */ activeThreads--; | |
wakeMainLoop(); | |
} ); | |
} | |
public static function runOnMainThread(inFunc:Void->Void) | |
{ | |
jobsMutex.lock(); | |
if (mainThreadJobs==null) | |
mainThreadJobs = [inFunc]; | |
else | |
mainThreadJobs.push)(inFunc); | |
jobsMutex.unlock(); | |
wakeMainLoop(); | |
} | |
} | |
// --- Timer -- | |
class TimerClient | |
{ | |
public function onPoll() | |
{ | |
Timer.onPoll(); | |
} | |
public function getNextWake() | |
{ | |
// Find when next one is due... | |
} | |
} | |
class Timer | |
{ | |
static var client = new TimerClient() | |
static var allTimers : Array<Timer>() | |
public function new() | |
{ | |
if (allTimers==null) | |
allTimers = [this]; | |
else | |
allTimers.push(this); | |
// new! | |
if (allTimers.length==1) | |
Scheduler.addClient(client); | |
} | |
function remove() | |
{ | |
allTimers.remove(this); | |
if (allTimers.length==0) | |
Scheduler.removeClient(client); | |
} | |
} | |
// ----- | |
class Http | |
{ | |
public static function createAsync(onResult, onError) | |
{ | |
Scheduler.createThread( function() { | |
var syncHttp = new Http(); | |
syncHttp.onError = function() Scheduler.runOnMainThread( function() onError() ); | |
syncHttp.onResult = function() Scheduler.runOnMainThread( function() onResult() ); | |
syncHttp.request(); | |
} | |
); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment