forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
63
Kha/Tools/linux_x64/std/sys/thread/Deque.hx
Normal file
63
Kha/Tools/linux_x64/std/sys/thread/Deque.hx
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C)2005-2019 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package sys.thread;
|
||||
|
||||
#if (!target.threaded)
|
||||
#error "This class is not available on this target"
|
||||
#end
|
||||
|
||||
/**
|
||||
A Deque is a double-ended queue with a `pop` method that can block until
|
||||
an element is available. It is commonly used to synchronize threads.
|
||||
*/
|
||||
@:coreApi extern class Deque<T> {
|
||||
/**
|
||||
Create a new Deque instance which is initially empty.
|
||||
**/
|
||||
function new():Void;
|
||||
|
||||
/**
|
||||
Adds an element at the end of `this` Deque.
|
||||
|
||||
(Java,Jvm): throws `java.lang.NullPointerException` if `i` is `null`.
|
||||
**/
|
||||
function add(i:T):Void;
|
||||
|
||||
/**
|
||||
Adds an element at the front of `this` Deque.
|
||||
|
||||
(Java,Jvm): throws `java.lang.NullPointerException` if `i` is `null`.
|
||||
**/
|
||||
function push(i:T):Void;
|
||||
|
||||
/**
|
||||
Tries to retrieve an element from the front of `this` Deque.
|
||||
|
||||
If an element is available, it is removed from the queue and returned.
|
||||
|
||||
If no element is available and `block` is `false`, `null` is returned.
|
||||
|
||||
Otherwise, execution blocks until an element is available and returns it.
|
||||
**/
|
||||
function pop(block:Bool):Null<T>;
|
||||
}
|
198
Kha/Tools/linux_x64/std/sys/thread/ElasticThreadPool.hx
Normal file
198
Kha/Tools/linux_x64/std/sys/thread/ElasticThreadPool.hx
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C)2005-2019 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package sys.thread;
|
||||
|
||||
#if (!target.threaded)
|
||||
#error "This class is not available on this target"
|
||||
#end
|
||||
|
||||
import haxe.Exception;
|
||||
|
||||
/**
|
||||
Thread pool with a varying amount of threads.
|
||||
|
||||
A new thread is spawned every time a task is submitted while all existing
|
||||
threads are busy.
|
||||
**/
|
||||
@:coreApi
|
||||
class ElasticThreadPool implements IThreadPool {
|
||||
/* Amount of alive threads in this pool. */
|
||||
public var threadsCount(get,null):Int;
|
||||
/* Maximum amount of threads in this pool. */
|
||||
public var maxThreadsCount:Int;
|
||||
/** Indicates if `shutdown` method of this pool has been called. */
|
||||
public var isShutdown(get,never):Bool;
|
||||
var _isShutdown = false;
|
||||
function get_isShutdown():Bool return _isShutdown;
|
||||
|
||||
final pool:Array<Worker> = [];
|
||||
final queue = new Deque<()->Void>();
|
||||
final mutex = new Mutex();
|
||||
final threadTimeout:Float;
|
||||
|
||||
/**
|
||||
Create a new thread pool with `threadsCount` threads.
|
||||
|
||||
If a worker thread does not receive a task for `threadTimeout` seconds it
|
||||
is terminated.
|
||||
**/
|
||||
public function new(maxThreadsCount:Int, threadTimeout:Float = 60):Void {
|
||||
if(maxThreadsCount < 1)
|
||||
throw new ThreadPoolException('ElasticThreadPool needs maxThreadsCount to be at least 1.');
|
||||
this.maxThreadsCount = maxThreadsCount;
|
||||
this.threadTimeout = threadTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
Submit a task to run in a thread.
|
||||
|
||||
Throws an exception if the pool is shut down.
|
||||
**/
|
||||
public function run(task:()->Void):Void {
|
||||
if(_isShutdown)
|
||||
throw new ThreadPoolException('Task is rejected. Thread pool is shut down.');
|
||||
if(task == null)
|
||||
throw new ThreadPoolException('Task to run must not be null.');
|
||||
|
||||
mutex.acquire();
|
||||
var submitted = false;
|
||||
var deadWorker = null;
|
||||
for(worker in pool) {
|
||||
if(deadWorker == null && worker.dead) {
|
||||
deadWorker = worker;
|
||||
}
|
||||
if(worker.task == null) {
|
||||
submitted = true;
|
||||
worker.wakeup(task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!submitted) {
|
||||
if(deadWorker != null) {
|
||||
deadWorker.wakeup(task);
|
||||
} else if(pool.length < maxThreadsCount) {
|
||||
var worker = new Worker(queue, threadTimeout);
|
||||
pool.push(worker);
|
||||
worker.wakeup(task);
|
||||
} else {
|
||||
queue.add(task);
|
||||
}
|
||||
}
|
||||
mutex.release();
|
||||
}
|
||||
|
||||
/**
|
||||
Initiates a shutdown.
|
||||
All previousely submitted tasks will be executed, but no new tasks will
|
||||
be accepted.
|
||||
|
||||
Multiple calls to this method have no effect.
|
||||
**/
|
||||
public function shutdown():Void {
|
||||
if(_isShutdown) return;
|
||||
mutex.acquire();
|
||||
_isShutdown = true;
|
||||
for(worker in pool) {
|
||||
worker.shutdown();
|
||||
}
|
||||
mutex.release();
|
||||
}
|
||||
|
||||
function get_threadsCount():Int {
|
||||
var result = 0;
|
||||
for(worker in pool)
|
||||
if(!worker.dead)
|
||||
++result;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private class Worker {
|
||||
public var task(default,null):Null<()->Void>;
|
||||
public var dead(default,null) = false;
|
||||
|
||||
final deathMutex = new Mutex();
|
||||
final waiter = new Lock();
|
||||
final queue:Deque<()->Void>;
|
||||
final timeout:Float;
|
||||
var thread:Thread;
|
||||
var isShutdown = false;
|
||||
|
||||
public function new(queue:Deque<()->Void>, timeout:Float) {
|
||||
this.queue = queue;
|
||||
this.timeout = timeout;
|
||||
start();
|
||||
}
|
||||
|
||||
public function wakeup(task:()->Void) {
|
||||
deathMutex.acquire();
|
||||
if(dead)
|
||||
start();
|
||||
this.task = task;
|
||||
waiter.release();
|
||||
deathMutex.release();
|
||||
}
|
||||
|
||||
public function shutdown() {
|
||||
isShutdown = true;
|
||||
waiter.release();
|
||||
}
|
||||
|
||||
function start() {
|
||||
dead = false;
|
||||
thread = Thread.create(loop);
|
||||
}
|
||||
|
||||
function loop() {
|
||||
try {
|
||||
while(waiter.wait(timeout)) {
|
||||
switch task {
|
||||
case null:
|
||||
if(isShutdown)
|
||||
break;
|
||||
case fn:
|
||||
fn();
|
||||
//if more tasks were added while all threads were busy
|
||||
while(true) {
|
||||
switch queue.pop(false) {
|
||||
case null: break;
|
||||
case fn: fn();
|
||||
}
|
||||
}
|
||||
task = null;
|
||||
}
|
||||
}
|
||||
deathMutex.acquire();
|
||||
//in case a task was submitted right after the lock timed out
|
||||
if(task != null)
|
||||
start()
|
||||
else
|
||||
dead = true;
|
||||
deathMutex.release();
|
||||
} catch(e) {
|
||||
task = null;
|
||||
start();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
275
Kha/Tools/linux_x64/std/sys/thread/EventLoop.hx
Normal file
275
Kha/Tools/linux_x64/std/sys/thread/EventLoop.hx
Normal file
@ -0,0 +1,275 @@
|
||||
package sys.thread;
|
||||
|
||||
/**
|
||||
When an event loop has an available event to execute.
|
||||
**/
|
||||
enum NextEventTime {
|
||||
/** There's already an event waiting to be executed */
|
||||
Now;
|
||||
/** No new events are expected. */
|
||||
Never;
|
||||
/**
|
||||
An event is expected to arrive at any time.
|
||||
If `time` is specified, then the event will be ready at that time for sure.
|
||||
*/
|
||||
AnyTime(time:Null<Float>);
|
||||
/** An event is expected to be ready for execution at `time`. */
|
||||
At(time:Float);
|
||||
}
|
||||
|
||||
/**
|
||||
An event loop implementation used for `sys.thread.Thread`
|
||||
**/
|
||||
@:coreApi
|
||||
class EventLoop {
|
||||
final mutex = new Mutex();
|
||||
final oneTimeEvents = new Array<Null<()->Void>>();
|
||||
var oneTimeEventsIdx = 0;
|
||||
final waitLock = new Lock();
|
||||
var promisedEventsCount = 0;
|
||||
var regularEvents:Null<RegularEvent>;
|
||||
|
||||
public function new():Void {}
|
||||
|
||||
/**
|
||||
Schedule event for execution every `intervalMs` milliseconds in current loop.
|
||||
**/
|
||||
public function repeat(event:()->Void, intervalMs:Int):EventHandler {
|
||||
mutex.acquire();
|
||||
var interval = 0.001 * intervalMs;
|
||||
var event = new RegularEvent(event, Sys.time() + interval, interval);
|
||||
inline insertEventByTime(event);
|
||||
waitLock.release();
|
||||
mutex.release();
|
||||
return event;
|
||||
}
|
||||
|
||||
function insertEventByTime(event:RegularEvent):Void {
|
||||
switch regularEvents {
|
||||
case null:
|
||||
regularEvents = event;
|
||||
case current:
|
||||
var previous = null;
|
||||
while(true) {
|
||||
if(current == null) {
|
||||
previous.next = event;
|
||||
event.previous = previous;
|
||||
break;
|
||||
} else if(event.nextRunTime < current.nextRunTime) {
|
||||
event.next = current;
|
||||
current.previous = event;
|
||||
switch previous {
|
||||
case null:
|
||||
regularEvents = event;
|
||||
case _:
|
||||
event.previous = previous;
|
||||
previous.next = event;
|
||||
current.previous = event;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
previous = current;
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Prevent execution of a previously scheduled event in current loop.
|
||||
**/
|
||||
public function cancel(eventHandler:EventHandler):Void {
|
||||
mutex.acquire();
|
||||
var event:RegularEvent = eventHandler;
|
||||
event.cancelled = true;
|
||||
if(regularEvents == event) {
|
||||
regularEvents = event.next;
|
||||
}
|
||||
switch event.next {
|
||||
case null:
|
||||
case e: e.previous = event.previous;
|
||||
}
|
||||
switch event.previous {
|
||||
case null:
|
||||
case e: e.next = event.next;
|
||||
}
|
||||
mutex.release();
|
||||
}
|
||||
|
||||
/**
|
||||
Notify this loop about an upcoming event.
|
||||
This makes the thread to stay alive and wait for as many events as many times
|
||||
`.promise()` was called. These events should be added via `.runPromised()`
|
||||
**/
|
||||
public function promise():Void {
|
||||
mutex.acquire();
|
||||
++promisedEventsCount;
|
||||
mutex.release();
|
||||
}
|
||||
|
||||
/**
|
||||
Execute `event` as soon as possible.
|
||||
**/
|
||||
public function run(event:()->Void):Void {
|
||||
mutex.acquire();
|
||||
oneTimeEvents[oneTimeEventsIdx++] = event;
|
||||
waitLock.release();
|
||||
mutex.release();
|
||||
}
|
||||
|
||||
/**
|
||||
Add previously promised `event` for execution.
|
||||
**/
|
||||
public function runPromised(event:()->Void):Void {
|
||||
mutex.acquire();
|
||||
oneTimeEvents[oneTimeEventsIdx++] = event;
|
||||
--promisedEventsCount;
|
||||
waitLock.release();
|
||||
mutex.release();
|
||||
}
|
||||
|
||||
/**
|
||||
Executes all pending events.
|
||||
|
||||
The returned time stamps can be used with `Sys.time()` for calculations.
|
||||
|
||||
Depending on a target platform this method may be non-reentrant. It must
|
||||
not be called from event callbacks.
|
||||
**/
|
||||
public function progress():NextEventTime {
|
||||
return switch __progress(Sys.time(), [], []) {
|
||||
case {nextEventAt:-2}: Now;
|
||||
case {nextEventAt:-1, anyTime:false}: Never;
|
||||
case {nextEventAt:-1, anyTime:true}: AnyTime(null);
|
||||
case {nextEventAt:time, anyTime:true}: AnyTime(time);
|
||||
case {nextEventAt:time, anyTime:false}: At(time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Blocks until a new event is added or `timeout` (in seconds) to expires.
|
||||
|
||||
Depending on a target platform this method may also automatically execute arriving
|
||||
events while waiting. However if any event is executed it will stop waiting.
|
||||
|
||||
Returns `true` if more events are expected.
|
||||
Returns `false` if no more events expected.
|
||||
|
||||
Depending on a target platform this method may be non-reentrant. It must
|
||||
not be called from event callbacks.
|
||||
**/
|
||||
public function wait(?timeout:Float):Bool {
|
||||
return waitLock.wait(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
Execute all pending events.
|
||||
Wait and execute as many events as many times `promiseEvent()` was called.
|
||||
Runs until all repeating events are cancelled and no more events is expected.
|
||||
|
||||
Depending on a target platform this method may be non-reentrant. It must
|
||||
not be called from event callbacks.
|
||||
**/
|
||||
public function loop():Void {
|
||||
var recycleRegular = [];
|
||||
var recycleOneTimers = [];
|
||||
while(true) {
|
||||
var r = __progress(Sys.time(), recycleRegular, recycleOneTimers);
|
||||
switch r {
|
||||
case {nextEventAt:-2}:
|
||||
case {nextEventAt:-1, anyTime:false}:
|
||||
break;
|
||||
case {nextEventAt:-1, anyTime:true}:
|
||||
waitLock.wait();
|
||||
case {nextEventAt:time}:
|
||||
var timeout = time - Sys.time();
|
||||
waitLock.wait(Math.max(0, timeout));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
`.progress` implementation with a reusable array for internal usage.
|
||||
The `nextEventAt` field of the return value denotes when the next event
|
||||
is expected to run:
|
||||
* -1 - never
|
||||
* -2 - now
|
||||
* other values - at specified time
|
||||
**/
|
||||
inline function __progress(now:Float, recycleRegular:Array<RegularEvent>, recycleOneTimers:Array<()->Void>):{nextEventAt:Float, anyTime:Bool} {
|
||||
var regularsToRun = recycleRegular;
|
||||
var eventsToRunIdx = 0;
|
||||
// When the next event is expected to run
|
||||
var nextEventAt:Float = -1;
|
||||
|
||||
mutex.acquire();
|
||||
//reset waitLock
|
||||
while(waitLock.wait(0.0)) {}
|
||||
// Collect regular events to run
|
||||
var current = regularEvents;
|
||||
while(current != null) {
|
||||
if(current.nextRunTime <= now) {
|
||||
regularsToRun[eventsToRunIdx++] = current;
|
||||
current.nextRunTime += current.interval;
|
||||
nextEventAt = -2;
|
||||
} else if(nextEventAt == -1 || current.nextRunTime < nextEventAt) {
|
||||
nextEventAt = current.nextRunTime;
|
||||
}
|
||||
current = current.next;
|
||||
}
|
||||
mutex.release();
|
||||
|
||||
// Run regular events
|
||||
for(i in 0...eventsToRunIdx) {
|
||||
if(!regularsToRun[i].cancelled)
|
||||
regularsToRun[i].run();
|
||||
regularsToRun[i] = null;
|
||||
}
|
||||
eventsToRunIdx = 0;
|
||||
|
||||
var oneTimersToRun = recycleOneTimers;
|
||||
// Collect pending one-time events
|
||||
mutex.acquire();
|
||||
for(i => event in oneTimeEvents) {
|
||||
switch event {
|
||||
case null:
|
||||
break;
|
||||
case _:
|
||||
oneTimersToRun[eventsToRunIdx++] = event;
|
||||
oneTimeEvents[i] = null;
|
||||
}
|
||||
}
|
||||
oneTimeEventsIdx = 0;
|
||||
var hasPromisedEvents = promisedEventsCount > 0;
|
||||
mutex.release();
|
||||
|
||||
//run events
|
||||
for(i in 0...eventsToRunIdx) {
|
||||
oneTimersToRun[i]();
|
||||
oneTimersToRun[i] = null;
|
||||
}
|
||||
|
||||
// Some events were executed. They could add new events to run.
|
||||
if(eventsToRunIdx > 0) {
|
||||
nextEventAt = -2;
|
||||
}
|
||||
return {nextEventAt:nextEventAt, anyTime:hasPromisedEvents}
|
||||
}
|
||||
}
|
||||
|
||||
abstract EventHandler(RegularEvent) from RegularEvent to RegularEvent {}
|
||||
|
||||
private class RegularEvent {
|
||||
public var nextRunTime:Float;
|
||||
public final interval:Float;
|
||||
public final run:()->Void;
|
||||
public var next:Null<RegularEvent>;
|
||||
public var previous:Null<RegularEvent>;
|
||||
public var cancelled:Bool = false;
|
||||
|
||||
public function new(run:()->Void, nextRunTime:Float, interval:Float) {
|
||||
this.run = run;
|
||||
this.nextRunTime = nextRunTime;
|
||||
this.interval = interval;
|
||||
}
|
||||
}
|
116
Kha/Tools/linux_x64/std/sys/thread/FixedThreadPool.hx
Normal file
116
Kha/Tools/linux_x64/std/sys/thread/FixedThreadPool.hx
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C)2005-2019 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package sys.thread;
|
||||
|
||||
#if (!target.threaded)
|
||||
#error "This class is not available on this target"
|
||||
#end
|
||||
|
||||
import haxe.Exception;
|
||||
|
||||
/**
|
||||
Thread pool with a constant amount of threads.
|
||||
Threads in the pool will exist until the pool is explicitly shut down.
|
||||
**/
|
||||
@:coreApi
|
||||
class FixedThreadPool implements IThreadPool {
|
||||
/* Amount of threads in this pool. */
|
||||
public var threadsCount(get,null):Int;
|
||||
function get_threadsCount():Int return threadsCount;
|
||||
|
||||
/** Indicates if `shutdown` method of this pool has been called. */
|
||||
public var isShutdown(get,never):Bool;
|
||||
var _isShutdown = false;
|
||||
function get_isShutdown():Bool return _isShutdown;
|
||||
|
||||
final pool:Array<Worker>;
|
||||
final poolMutex = new Mutex();
|
||||
final queue = new Deque<()->Void>();
|
||||
|
||||
/**
|
||||
Create a new thread pool with `threadsCount` threads.
|
||||
**/
|
||||
public function new(threadsCount:Int):Void {
|
||||
if(threadsCount < 1)
|
||||
throw new ThreadPoolException('FixedThreadPool needs threadsCount to be at least 1.');
|
||||
this.threadsCount = threadsCount;
|
||||
pool = [for(i in 0...threadsCount) new Worker(queue)];
|
||||
}
|
||||
|
||||
/**
|
||||
Submit a task to run in a thread.
|
||||
|
||||
Throws an exception if the pool is shut down.
|
||||
**/
|
||||
public function run(task:()->Void):Void {
|
||||
if(_isShutdown)
|
||||
throw new ThreadPoolException('Task is rejected. Thread pool is shut down.');
|
||||
if(task == null)
|
||||
throw new ThreadPoolException('Task to run must not be null.');
|
||||
queue.add(task);
|
||||
}
|
||||
|
||||
/**
|
||||
Initiates a shutdown.
|
||||
All previousely submitted tasks will be executed, but no new tasks will
|
||||
be accepted.
|
||||
|
||||
Multiple calls to this method have no effect.
|
||||
**/
|
||||
public function shutdown():Void {
|
||||
if(_isShutdown) return;
|
||||
_isShutdown = true;
|
||||
for(_ in pool) {
|
||||
queue.add(shutdownTask);
|
||||
}
|
||||
}
|
||||
|
||||
static function shutdownTask():Void {
|
||||
throw new ShutdownException('');
|
||||
}
|
||||
}
|
||||
|
||||
private class ShutdownException extends Exception {}
|
||||
|
||||
private class Worker {
|
||||
var thread:Thread;
|
||||
final queue:Deque<Null<()->Void>>;
|
||||
|
||||
public function new(queue:Deque<Null<()->Void>>) {
|
||||
this.queue = queue;
|
||||
thread = Thread.create(loop);
|
||||
}
|
||||
|
||||
function loop() {
|
||||
try {
|
||||
while(true) {
|
||||
var task = queue.pop(true);
|
||||
task();
|
||||
}
|
||||
} catch(_:ShutdownException) {
|
||||
} catch(e) {
|
||||
thread = Thread.create(loop);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
51
Kha/Tools/linux_x64/std/sys/thread/IThreadPool.hx
Normal file
51
Kha/Tools/linux_x64/std/sys/thread/IThreadPool.hx
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C)2005-2019 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package sys.thread;
|
||||
|
||||
/**
|
||||
A thread pool interface.
|
||||
**/
|
||||
interface IThreadPool {
|
||||
|
||||
/** Amount of alive threads in this pool. */
|
||||
var threadsCount(get,never):Int;
|
||||
|
||||
/** Indicates if `shutdown` method of this pool has been called. */
|
||||
var isShutdown(get,never):Bool;
|
||||
|
||||
/**
|
||||
Submit a task to run in a thread.
|
||||
|
||||
Throws an exception if the pool is shut down.
|
||||
**/
|
||||
function run(task:()->Void):Void;
|
||||
|
||||
/**
|
||||
Initiates a shutdown.
|
||||
All previousely submitted tasks will be executed, but no new tasks will
|
||||
be accepted.
|
||||
|
||||
Multiple calls to this method have no effect.
|
||||
**/
|
||||
function shutdown():Void;
|
||||
}
|
80
Kha/Tools/linux_x64/std/sys/thread/Lock.hx
Normal file
80
Kha/Tools/linux_x64/std/sys/thread/Lock.hx
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (C)2005-2019 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package sys.thread;
|
||||
|
||||
#if (!target.threaded)
|
||||
#error "This class is not available on this target"
|
||||
#end
|
||||
|
||||
/**
|
||||
A Lock allows blocking execution until it has been unlocked. It keeps track
|
||||
of how often `release` has been called, and blocks exactly as many `wait`
|
||||
calls.
|
||||
|
||||
The order of the `release` and `wait` calls is irrelevant. That is, a Lock
|
||||
can be released before anyone waits for it. In that case, the `wait` call
|
||||
will execute immediately.
|
||||
|
||||
Usage example:
|
||||
|
||||
```haxe
|
||||
var lock = new Lock();
|
||||
var elements = [1, 2, 3];
|
||||
for (element in elements) {
|
||||
// Create one thread per element
|
||||
new Thread(function() {
|
||||
trace(element);
|
||||
Sys.sleep(1);
|
||||
// Release once per thread = 3 times
|
||||
lock.release();
|
||||
});
|
||||
}
|
||||
for (_ in elements) {
|
||||
// Wait 3 times
|
||||
lock.wait();
|
||||
}
|
||||
trace("All threads finished");
|
||||
```
|
||||
**/
|
||||
extern class Lock {
|
||||
/**
|
||||
Creates a new Lock which is initially locked.
|
||||
**/
|
||||
function new():Void;
|
||||
|
||||
/**
|
||||
Waits for the lock to be released, or `timeout` (in seconds)
|
||||
to expire. Returns `true` if the lock is released and `false`
|
||||
if a time-out occurs.
|
||||
**/
|
||||
function wait(?timeout:Float):Bool;
|
||||
|
||||
/**
|
||||
Releases the lock once.
|
||||
|
||||
The thread does not need to own the lock in order to release
|
||||
it. Each call to `release` allows exactly one call to `wait`
|
||||
to execute.
|
||||
**/
|
||||
function release():Void;
|
||||
}
|
59
Kha/Tools/linux_x64/std/sys/thread/Mutex.hx
Normal file
59
Kha/Tools/linux_x64/std/sys/thread/Mutex.hx
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C)2005-2019 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package sys.thread;
|
||||
|
||||
#if (!target.threaded)
|
||||
#error "This class is not available on this target"
|
||||
#end
|
||||
|
||||
/**
|
||||
Creates a mutex, which can be used to acquire a temporary lock
|
||||
to access some ressource. The main difference with a lock is
|
||||
that a mutex must always be released by the owner thread.
|
||||
**/
|
||||
extern class Mutex {
|
||||
/**
|
||||
Creates a mutex.
|
||||
**/
|
||||
function new():Void;
|
||||
|
||||
/**
|
||||
The current thread acquire the mutex or wait if not available.
|
||||
The same thread can acquire several times the same mutex but
|
||||
must release it as many times it has been acquired.
|
||||
**/
|
||||
function acquire():Void;
|
||||
|
||||
/**
|
||||
Try to acquire the mutex, returns true if acquire or false
|
||||
if it's already locked by another thread.
|
||||
**/
|
||||
function tryAcquire():Bool;
|
||||
|
||||
/**
|
||||
Release a mutex that has been acquired by the current thread.
|
||||
The behavior is undefined if the current thread does not own
|
||||
the mutex.
|
||||
**/
|
||||
function release():Void;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package sys.thread;
|
||||
|
||||
import haxe.Exception;
|
||||
|
||||
class NoEventLoopException extends Exception {
|
||||
public function new(msg:String = 'Event loop is not available. Refer to sys.thread.Thread.runWithEventLoop.', ?previous:Exception) {
|
||||
super(msg, previous);
|
||||
}
|
||||
}
|
83
Kha/Tools/linux_x64/std/sys/thread/Thread.hx
Normal file
83
Kha/Tools/linux_x64/std/sys/thread/Thread.hx
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C)2005-2019 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package sys.thread;
|
||||
|
||||
#if (!target.threaded)
|
||||
#error "This class is not available on this target"
|
||||
#end
|
||||
|
||||
private typedef ThreadImpl = {};
|
||||
|
||||
extern abstract Thread(ThreadImpl) from ThreadImpl {
|
||||
/**
|
||||
Event loop of this thread (if available).
|
||||
|
||||
Note that by default event loop is only available in the main thread.
|
||||
To setup an event loop in other threads use `sys.thread.Thread.runWithEventLoop`
|
||||
or create new threads with built-in event loops using `sys.thread.Thread.createWithEventLoop`
|
||||
**/
|
||||
public var events(get,never):EventLoop;
|
||||
|
||||
/**
|
||||
Send a message to the thread queue. This message can be read by using `readMessage`.
|
||||
**/
|
||||
public function sendMessage(msg:Dynamic):Void;
|
||||
|
||||
/**
|
||||
Returns the current thread.
|
||||
**/
|
||||
public static function current():Thread;
|
||||
|
||||
/**
|
||||
Creates a new thread that will execute the `job` function, then exit.
|
||||
|
||||
This function does not setup an event loop for a new thread.
|
||||
**/
|
||||
public static function create(job:()->Void):Thread;
|
||||
|
||||
/**
|
||||
Simply execute `job` if current thread already has an event loop.
|
||||
|
||||
But if current thread does not have an event loop: setup event loop,
|
||||
run `job` and then destroy event loop. And in this case this function
|
||||
does not return until no more events left to run.
|
||||
**/
|
||||
public static function runWithEventLoop(job:()->Void):Void;
|
||||
|
||||
/**
|
||||
This is logically equal to `Thread.create(() -> Thread.runWithEventLoop(job));`
|
||||
**/
|
||||
public static function createWithEventLoop(job:()->Void):Thread;
|
||||
|
||||
/**
|
||||
Reads a message from the thread queue. If `block` is true, the function
|
||||
blocks until a message is available. If `block` is false, the function
|
||||
returns `null` if no message is available.
|
||||
**/
|
||||
public static function readMessage(block:Bool):Dynamic;
|
||||
|
||||
/**
|
||||
Run event loop of the current thread
|
||||
**/
|
||||
private static function processEvents():Void;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package sys.thread;
|
||||
|
||||
import haxe.Exception;
|
||||
|
||||
class ThreadPoolException extends Exception {
|
||||
}
|
45
Kha/Tools/linux_x64/std/sys/thread/Tls.hx
Normal file
45
Kha/Tools/linux_x64/std/sys/thread/Tls.hx
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C)2005-2019 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package sys.thread;
|
||||
|
||||
#if (!target.threaded)
|
||||
#error "This class is not available on this target"
|
||||
#end
|
||||
|
||||
/**
|
||||
Creates thread local storage.
|
||||
|
||||
(hl) Warning: At the moment `Tls` does not protect the value from being
|
||||
garbage collected. Keep the value reachable to avoid crashes.
|
||||
**/
|
||||
extern class Tls<T> {
|
||||
var value(get, set):T;
|
||||
|
||||
/**
|
||||
Creates thread local storage. This is placeholder that can store
|
||||
a value that will be different depending on the local thread.
|
||||
Set the tls value to `null` before exiting the thread
|
||||
or the memory will never be collected.
|
||||
**/
|
||||
function new():Void;
|
||||
}
|
Reference in New Issue
Block a user