Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View 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>;
}

View 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;
}
}
}

View 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;
}
}

View 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;
}
}
}

View 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;
}

View 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;
}

View 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;
}

View File

@ -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);
}
}

View 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;
}

View File

@ -0,0 +1,6 @@
package sys.thread;
import haxe.Exception;
class ThreadPoolException extends Exception {
}

View 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;
}