This commit is contained in:
Dante
2026-05-21 23:40:20 -07:00
parent 3e2915dff7
commit 877a69d844
5737 changed files with 29796 additions and 1589684 deletions

View File

@ -33,7 +33,7 @@ class Sys {
extern static public function getEnv(s:String):String;
extern static public function putEnv(s:String, v:String):Void;
extern static public function putEnv(s:String, v:Null<String>):Void;
extern static public function environment():Map<String, String>;

View File

@ -18,7 +18,10 @@ class Exception {
if(Std.isOfType(value, Exception)) {
return value;
} else {
return new ValueException(value, null, value);
var e = new ValueException(value, null, value);
// Undo automatic __shiftStack()
e.__unshiftStack();
return e;
}
}
@ -63,6 +66,12 @@ class Exception {
__skipStack++;
}
@:noCompletion
@:ifFeature("haxe.Exception.get_stack")
inline function __unshiftStack():Void {
__skipStack--;
}
function get_message():String {
return __exceptionMessage;
}

View File

@ -5,8 +5,8 @@ import haxe.io.Bytes;
extern class PkContext {
function new():Void;
function parse_key(key:Bytes, ?pwd:String):Int;
function parse_keyfile(path:String, ?password:String):Int;
function parse_key(key:Bytes, ?pwd:String, ctr_dbg: CtrDrbg):Int;
function parse_keyfile(path:String, ?password:String, ctr_dbg: CtrDrbg):Int;
function parse_public_key(key:Bytes):Int;
function parse_public_keyfile(path:String):Int;
}

View File

@ -43,11 +43,11 @@ class Host {
this.ip = ip;
}
extern static public function localhost();
extern static public function localhost():String;
extern static function hostReverse(ip:Int);
extern static function hostReverse(ip:Int):String;
extern static function hostToString(ip:Int);
extern static function hostToString(ip:Int):String;
extern static function resolve(name:String);
extern static function resolve(name:String):Int;
}

View File

@ -38,7 +38,7 @@ class Key {
var code = if (isPublic) {
key.native.parse_public_keyfile(file);
} else {
key.native.parse_keyfile(file, pass);
key.native.parse_keyfile(file, pass, Mbedtls.getDefaultCtrDrbg());
}
if (code != 0) {
throw(mbedtls.Error.strerror(code));
@ -51,7 +51,7 @@ class Key {
var code = if (isPublic) {
key.native.parse_public_key(data);
} else {
key.native.parse_key(data);
key.native.parse_key(data, null, Mbedtls.getDefaultCtrDrbg());
}
if (code != 0) {
throw(mbedtls.Error.strerror(code));

View File

@ -0,0 +1,41 @@
package sys.thread;
@:coreApi class Condition {
final cond:eval.luv.Condition;
final mutex:eval.luv.Mutex;
public function new():Void {
cond = eval.luv.Condition.init().resolve();
mutex = eval.luv.Mutex.init(true).resolve();
eval.vm.Gc.finalise(destroy, this);
}
static function destroy(cond:Condition):Void {
cond.cond.destroy();
cond.mutex.destroy();
}
public function acquire():Void {
mutex.lock();
}
public function tryAcquire():Bool {
return mutex.tryLock().isOk();
}
public function release():Void {
mutex.unlock();
}
public function wait():Void {
cond.wait(mutex);
}
public function signal():Void {
cond.signal();
}
public function broadcast():Void {
cond.broadcast();
}
}

View File

@ -3,12 +3,23 @@ package sys.thread;
import eval.luv.Loop;
import eval.luv.Async;
import eval.luv.Timer as LuvTimer;
import haxe.MainLoop;
/**
When an event loop has an available event to execute.
**/
@:coreApi
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);
}
@ -27,37 +38,47 @@ private class RegularEvent {
}
}
/**
An event loop implementation used for `sys.thread.Thread`
**/
@:coreApi
class EventLoop {
@:allow(eval.luv.Loop)
final handle:Loop;
final mutex = new Mutex();
final oneTimeEvents = new Array<Null<()->Void>>();
var oneTimeEventsIdx = 0;
final wakeup:Async;
var promisedEventsCount = 0;
var pending:Array<()->Void> = [];
var looping = false;
var started:Bool = false;
var isMainThread:Bool;
static var CREATED : Bool;
public function new():Void {
isMainThread = !CREATED;
CREATED = true;
handle = Loop.init().resolve();
wakeup = Async.init(handle, consumePending).resolve();
wakeup.unref();
}
/**
Schedule event for execution every `intervalMs` milliseconds in current loop.
**/
public function repeat(event:()->Void, intervalMs:Int):EventHandler {
var e = new RegularEvent(event);
mutex.acquire();
pending.push(() -> {
e.timer = LuvTimer.init(handle).resolve();
e.timer.start(e.run, intervalMs, intervalMs < 1 ? 1 : intervalMs).resolve();
});
e.timer = LuvTimer.init(handle).resolve();
e.timer.start(e.run, intervalMs, intervalMs < 1 ? 1 : intervalMs).resolve();
mutex.release();
wakeup.send();
return e;
}
/**
Prevent execution of a previously scheduled event in current loop.
**/
public function cancel(eventHandler:EventHandler):Void {
mutex.acquire();
(eventHandler:RegularEvent).event = noop;
@ -71,6 +92,11 @@ class EventLoop {
}
static final noop = function() {}
/**
Notify this loop about an upcoming event.
This makes the thread stay alive and wait for as many events as the number of
times `.promise()` was called. These events should be added via `.runPromised()`.
**/
public function promise():Void {
mutex.acquire();
++promisedEventsCount;
@ -79,6 +105,9 @@ class EventLoop {
wakeup.send();
}
/**
Execute `event` as soon as possible.
**/
public function run(event:()->Void):Void {
mutex.acquire();
pending.push(event);
@ -86,6 +115,9 @@ class EventLoop {
wakeup.send();
}
/**
Add previously promised `event` for execution.
**/
public function runPromised(event:()->Void):Void {
mutex.acquire();
--promisedEventsCount;
@ -96,7 +128,7 @@ class EventLoop {
}
function refUnref():Void {
if(promisedEventsCount > 0) {
if (promisedEventsCount > 0 || (isMainThread && haxe.MainLoop.hasEvents())) {
wakeup.ref();
} else {
wakeup.unref();
@ -104,37 +136,68 @@ class EventLoop {
}
public function progress():NextEventTime {
//TODO: throw if loop is already running
if((handle:Loop).run(NOWAIT)) {
if (started) throw "Event loop already started";
if (handle.run(NOWAIT)) {
return AnyTime(null);
} else {
return Never;
}
}
/**
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 {
//TODO: throw if loop is already running
if(timeout == null) {
if (started) throw "Event loop already started";
if(timeout != null) {
var timer = LuvTimer.init(handle).resolve();
timer.start(() -> {
timer.stop().resolve();
timer.close(() -> {});
}, Std.int(timeout * 1000));
return (handle:Loop).run(ONCE);
return handle.run(ONCE);
} else {
return (handle:Loop).run(ONCE);
return handle.run(ONCE);
}
}
/**
Execute all pending events.
Wait and execute as many events as the number of times `promise()` was called.
Runs until all repeating events are cancelled and no more events are expected.
Depending on a target platform this method may be non-reentrant. It must
not be called from event callbacks.
**/
public function loop():Void {
//TODO: throw if loop is already running
if (started) throw "Event loop already started";
started = true;
consumePending();
(handle:Loop).run(DEFAULT);
handle.run(DEFAULT);
}
function consumePending(?_:Async):Void {
mutex.acquire();
var p = pending;
pending = [];
mutex.release();
for(fn in p) fn();
if (started && isMainThread) {
var next = @:privateAccess MainLoop.tick();
if (haxe.MainLoop.hasEvents()) wakeup.send();
refUnref();
}
}
}
}

View File

@ -0,0 +1,36 @@
package sys.thread;
@:coreApi class Semaphore {
final native:eval.luv.Semaphore;
public function new(value:Int):Void {
native = eval.luv.Semaphore.init(value).resolve();
eval.vm.Gc.finalise(destroy, this);
}
static function destroy(sem:Semaphore):Void {
sem.native.destroy();
}
public function acquire():Void {
native.wait();
}
public function tryAcquire(?timeout:Float):Bool {
if (timeout == null) {
return native.tryWait().isOk();
} else {
var t = Sys.time() + timeout;
while (Sys.time() < t) {
if (native.tryWait().isOk()) {
return true;
}
}
return false;
}
}
public function release():Void {
native.post();
}
}