From 3f39ac27a03ba8f6d4e7be40ea5f8075aef6dc2f Mon Sep 17 00:00:00 2001 From: IonutParau Date: Thu, 5 Feb 2026 16:55:54 +0100 Subject: [PATCH] better signal semantics and windows mutexes --- rewrite/neonucleus.c | 53 +++++++++++++++++++++++++++++++++++++++++--- rewrite/neonucleus.h | 14 ++++++++++++ 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/rewrite/neonucleus.c b/rewrite/neonucleus.c index 633999e..b161f06 100644 --- a/rewrite/neonucleus.c +++ b/rewrite/neonucleus.c @@ -60,7 +60,7 @@ typedef struct nn_Lock nn_Lock; #endif #ifdef NN_WINDOWS -#include +#include #endif #endif @@ -348,7 +348,19 @@ static void nn_defaultLock(void *state, nn_LockRequest *req) { return; } #elif defined(NN_THREAD_WINDOWS) -#error "Windows locks are not supported yet" + switch(req->action) { + case NN_LOCK_CREATE:; + req->lock = CreateMutex(NULL, false, NULL); + case NN_LOCK_DESTROY:; + CloseHandle(req->lock); + return; + case NN_LOCK_LOCK:; + WaitForSingleObject(req->lock, INFINITE); + return; + case NN_LOCK_UNLOCK:; + ReleaseMutex(req->lock); + return; + } #endif #endif @@ -1249,6 +1261,41 @@ int nn_countValueCost(nn_Computer *computer, size_t values) { return total; } +size_t nn_countSignalCostValue(nn_Value value) { + size_t total = 2; + switch(value.type) { + case NN_VAL_NULL: + case NN_VAL_BOOL: + total += 4; + break; + case NN_VAL_NUM: + case NN_VAL_USERDATA: + total += 8; + break; + case NN_VAL_STR: + // 2+1 + if(value.string->len == 0) total++; + else total += value.string->len; + break; + case NN_VAL_TABLE: + total += 2; + for(size_t i = 0; i < value.table->len * 2; i++) { + total += nn_countSignalCostValue(value.table->vals[i]); + } + break; + } + return total; +} + +size_t nn_countSignalCost(nn_Computer *computer, size_t values) { + size_t total = 0; + for(size_t i = 0; i < values; i++) { + nn_Value val = computer->callstack[computer->stackSize - values + i]; + total += nn_countSignalCostValue(val); + } + return total; +} + size_t nn_countSignals(nn_Computer *computer) { return computer->signalCount; } @@ -1258,7 +1305,7 @@ nn_Exit nn_pushSignal(nn_Computer *computer, size_t valueCount) { if(computer->signalCount == NN_MAX_SIGNALS) return NN_ELIMIT; if(computer->stackSize < valueCount) return NN_EBELOWSTACK; - int cost = nn_countValueCost(computer, valueCount); + int cost = nn_countSignalCost(computer, valueCount); if(cost == -1) return NN_EBADSTATE; if(cost > NN_MAX_SIGNALSIZE) return NN_ELIMIT; diff --git a/rewrite/neonucleus.h b/rewrite/neonucleus.h index 1644755..0c867e6 100644 --- a/rewrite/neonucleus.h +++ b/rewrite/neonucleus.h @@ -459,8 +459,22 @@ nn_Exit nn_dumptable(nn_Computer *computer, size_t idx, size_t *len); // computes the cost of the top [values] values using the same algorithm as // the modem. // It will return -1 if the values are invalid. +// The algorithm is as mentioned in https://ocdoc.cil.li/component:modem +// and is as follows: +// - Every value adds a 2 byte overhead +// - Numbers add another 8 bytes, true/false/null another 4 bytes, strings as +// many bytes as they contain, except empty strings count as 1 byte. int nn_countValueCost(nn_Computer *computer, size_t values); +// computes the signal cost. +// This is a slightly modified version of value cost, except it allows +// tables and userdata. +// All values are always valid. +// For userdata and tables: +// - Userdata adds another 8 bytes overhead like numbers do. +// - Tables add yet another 2 byte overhead for their terminator, and the sum of all of the size of the keys and values they contain as per this algorithm. +size_t nn_countSignalCost(nn_Computer *computer, size_t values); + // Returns the amount of signals stored size_t nn_countSignals(nn_Computer *computer); // Pops [valueCount] values from the call stack and pushes them as a signal.