Skip to content

Instantly share code, notes, and snippets.

@hughsando
Created March 6, 2016 12:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hughsando/91a19a61a82bf8b7a9e6 to your computer and use it in GitHub Desktop.
Save hughsando/91a19a61a82bf8b7a9e6 to your computer and use it in GitHub Desktop.
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