mirror of https://gitlab.com/nakst/essence
remove event sinks
This commit is contained in:
parent
d8906e84ab
commit
751b4652c1
|
@ -317,8 +317,6 @@ define ES_ERROR_FILE_TOO_FRAGMENTED (-54)
|
|||
define ES_ERROR_DRIVE_FULL (-55)
|
||||
define ES_ERROR_COULD_NOT_RESOLVE_SYMBOL (-56)
|
||||
define ES_ERROR_ALREADY_EMBEDDED (-57)
|
||||
define ES_ERROR_EVENT_SINK_OVERFLOW (-58)
|
||||
define ES_ERROR_EVENT_SINK_DUPLICATE (-59)
|
||||
define ES_ERROR_UNSUPPORTED_CONVERSION (-60)
|
||||
define ES_ERROR_SOURCE_EMPTY (-61)
|
||||
define ES_ERROR_UNSUPPORTED_EXECUTABLE (-62)
|
||||
|
@ -342,8 +340,6 @@ define ES_CURRENT_PROCESS ((EsHandle) (0x11))
|
|||
|
||||
define ES_WAIT_NO_TIMEOUT (-1)
|
||||
define ES_MAX_WAIT_COUNT (8)
|
||||
define ES_MAX_EVENT_FORWARD_COUNT (4) // The maximum number of event sinks an event can be forwarded to.
|
||||
define ES_MAX_EVENT_SINK_BUFFER_SIZE (256) // The maximum number of events an event sink can capture. TODO Make this configurable in EsEventSinkCreate?
|
||||
|
||||
define ES_MAX_DIRECTORY_CHILD_NAME_LENGTH (256)
|
||||
|
||||
|
@ -779,12 +775,8 @@ private enum EsSyscallType {
|
|||
// Processing.
|
||||
|
||||
ES_SYSCALL_EVENT_CREATE
|
||||
ES_SYSCALL_EVENT_FORWARD
|
||||
ES_SYSCALL_EVENT_RESET
|
||||
ES_SYSCALL_EVENT_SET
|
||||
ES_SYSCALL_EVENT_SINK_CREATE
|
||||
ES_SYSCALL_EVENT_SINK_POP
|
||||
ES_SYSCALL_EVENT_SINK_PUSH
|
||||
ES_SYSCALL_PROCESS_CRASH
|
||||
ES_SYSCALL_PROCESS_CREATE
|
||||
ES_SYSCALL_PROCESS_GET_STATE
|
||||
|
@ -2218,14 +2210,9 @@ function size_t EsPipeWrite(EsHandle pipe, const void *buffer, size_t bytes);
|
|||
// Synchronisation and timing.
|
||||
|
||||
function EsHandle EsEventCreate(bool autoReset);
|
||||
function void EsEventForward(EsHandle event, EsHandle eventSink, EsGeneric data); // TODO Forwarding process/thread killed events.
|
||||
function void EsEventReset(EsHandle event);
|
||||
function void EsEventSet(EsHandle event);
|
||||
|
||||
function EsHandle EsEventSinkCreate(bool ignoreDuplicates);
|
||||
function EsError EsEventSinkPop(EsHandle eventSink, EsGeneric *data); // Returns ES_ERROR_EVENT_NOT_SET if empty, and ES_ERROR_EVENT_SINK_OVERFLOW if data lost.
|
||||
function EsError EsEventSinkPush(EsHandle eventSink, EsGeneric data); // Returns ES_ERROR_EVENT_SINK_DUPLICATE if duplicate, and ES_ERROR_EVENT_SINK_OVERFLOW if data lost.
|
||||
|
||||
function void EsMutexAcquire(EsMutex *mutex);
|
||||
function void EsMutexDestroy(EsMutex *mutex);
|
||||
function void EsMutexRelease(EsMutex *mutex);
|
||||
|
|
|
@ -737,23 +737,6 @@ EsError EsConnectionRead(EsConnection *connection, void *_buffer, size_t bufferB
|
|||
return ES_SUCCESS;
|
||||
}
|
||||
|
||||
void EsEventForward(EsHandle event, EsHandle eventSink, EsGeneric data) {
|
||||
EsSyscall(ES_SYSCALL_EVENT_FORWARD, event, eventSink, data.u, 0);
|
||||
}
|
||||
|
||||
EsHandle EsEventSinkCreate(bool ignoreDuplicates) {
|
||||
return EsSyscall(ES_SYSCALL_EVENT_SINK_CREATE, ignoreDuplicates, 0, 0, 0);
|
||||
}
|
||||
|
||||
EsError EsEventSinkPop(EsHandle eventSink, EsGeneric *data) {
|
||||
EsGeneric unused; if (!data) data = &unused;
|
||||
return EsSyscall(ES_SYSCALL_EVENT_SINK_POP, eventSink, (uintptr_t) data, 0, 0);
|
||||
}
|
||||
|
||||
EsError EsEventSinkPush(EsHandle eventSink, EsGeneric data) {
|
||||
return EsSyscall(ES_SYSCALL_EVENT_SINK_PUSH, eventSink, data.u, 0, 0);
|
||||
}
|
||||
|
||||
size_t EsGameControllerStatePoll(EsGameControllerState *buffer) {
|
||||
return EsSyscall(ES_SYSCALL_GAME_CONTROLLER_STATE_POLL, (uintptr_t) buffer, 0, 0, 0);
|
||||
}
|
||||
|
|
|
@ -190,7 +190,6 @@ enum KernelObjectType : uint32_t {
|
|||
#endif
|
||||
KERNEL_OBJECT_PIPE = 0x00000200, // A pipe through which data can be sent between processes, blocking when full or empty.
|
||||
KERNEL_OBJECT_EMBEDDED_WINDOW = 0x00000400, // An embedded window object, referencing its container Window.
|
||||
KERNEL_OBJECT_EVENT_SINK = 0x00002000, // An event sink. Events can be forwarded to it, allowing waiting on many objects.
|
||||
KERNEL_OBJECT_CONNECTION = 0x00004000, // A network connection.
|
||||
KERNEL_OBJECT_DEVICE = 0x00008000, // A device.
|
||||
};
|
||||
|
@ -267,15 +266,11 @@ void KMutexRelease(KMutex *mutex);
|
|||
void KMutexAssertLocked(KMutex *mutex);
|
||||
|
||||
struct KEvent { // Waiting and notifying. Can wait on multiple at once. Can be set and reset with interrupts disabled.
|
||||
volatile bool autoReset; // This should be first field in the structure,
|
||||
// so that the type of KEvent can be easily declared with {autoReset}.
|
||||
volatile bool autoReset; // This should be first field in the structure, so that the type of KEvent can be easily declared with {autoReset}.
|
||||
volatile uintptr_t state;
|
||||
|
||||
K_PRIVATE
|
||||
|
||||
LinkedList<Thread> blockedThreads;
|
||||
volatile size_t handles;
|
||||
struct EventSinkTable *sinkTable;
|
||||
};
|
||||
|
||||
bool KEventSet(KEvent *event, bool schedulerAlreadyLocked = false, bool maybeAlreadySet = false);
|
||||
|
|
|
@ -34,23 +34,6 @@ struct Pipe {
|
|||
size_t Access(void *buffer, size_t bytes, bool write, bool userBlockRequest);
|
||||
};
|
||||
|
||||
struct EventSink {
|
||||
KEvent available;
|
||||
KSpinlock spinlock; // Take after the scheduler's spinlock.
|
||||
volatile size_t handles;
|
||||
uintptr_t queuePosition;
|
||||
size_t queueCount;
|
||||
bool overflow, ignoreDuplicates;
|
||||
EsGeneric queue[ES_MAX_EVENT_SINK_BUFFER_SIZE];
|
||||
|
||||
EsError Push(EsGeneric data);
|
||||
};
|
||||
|
||||
struct EventSinkTable {
|
||||
EventSink *sink;
|
||||
EsGeneric data;
|
||||
};
|
||||
|
||||
struct MessageQueue {
|
||||
bool SendMessage(void *target, EsMessage *message); // Returns false if the message queue is full.
|
||||
bool SendMessage(_EsMessageWithObject *message); // Returns false if the message queue is full.
|
||||
|
@ -210,14 +193,6 @@ bool OpenHandleToObject(void *object, KernelObjectType type, uint32_t flags, boo
|
|||
KMutexRelease(&pipe->mutex);
|
||||
} break;
|
||||
|
||||
case KERNEL_OBJECT_EVENT_SINK: {
|
||||
EventSink *sink = (EventSink *) object;
|
||||
KSpinlockAcquire(&sink->spinlock);
|
||||
if (!sink->handles) hadNoHandles = true;
|
||||
else sink->handles++;
|
||||
KSpinlockRelease(&sink->spinlock);
|
||||
} break;
|
||||
|
||||
case KERNEL_OBJECT_CONNECTION: {
|
||||
NetConnection *connection = (NetConnection *) object;
|
||||
hadNoHandles = 0 == __sync_fetch_and_add(&connection->handles, 1);
|
||||
|
@ -275,16 +250,6 @@ void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags) {
|
|||
KMutexRelease(&objectHandleCountChange);
|
||||
|
||||
if (destroy) {
|
||||
if (event->sinkTable) {
|
||||
for (uintptr_t i = 0; i < ES_MAX_EVENT_FORWARD_COUNT; i++) {
|
||||
if (event->sinkTable[i].sink) {
|
||||
CloseHandleToObject(event->sinkTable[i].sink, KERNEL_OBJECT_EVENT_SINK, 0);
|
||||
}
|
||||
}
|
||||
|
||||
EsHeapFree(event->sinkTable, sizeof(EventSinkTable) * ES_MAX_EVENT_FORWARD_COUNT, K_FIXED);
|
||||
}
|
||||
|
||||
EsHeapFree(event, sizeof(KEvent), K_FIXED);
|
||||
}
|
||||
} break;
|
||||
|
@ -386,18 +351,6 @@ void CloseHandleToObject(void *object, KernelObjectType type, uint32_t flags) {
|
|||
}
|
||||
} break;
|
||||
|
||||
case KERNEL_OBJECT_EVENT_SINK: {
|
||||
EventSink *sink = (EventSink *) object;
|
||||
KSpinlockAcquire(&sink->spinlock);
|
||||
bool destroy = sink->handles == 1;
|
||||
sink->handles--;
|
||||
KSpinlockRelease(&sink->spinlock);
|
||||
|
||||
if (destroy) {
|
||||
EsHeapFree(sink, sizeof(EventSink), K_FIXED);
|
||||
}
|
||||
} break;
|
||||
|
||||
case KERNEL_OBJECT_CONNECTION: {
|
||||
NetConnection *connection = (NetConnection *) object;
|
||||
unsigned previous = __sync_fetch_and_sub(&connection->handles, 1);
|
||||
|
|
|
@ -314,55 +314,6 @@ void KSemaphoreSet(KSemaphore *semaphore, uintptr_t u) {
|
|||
KMutexRelease(&semaphore->mutex);
|
||||
}
|
||||
|
||||
EsError EventSink::Push(EsGeneric data) {
|
||||
EsError result = ES_SUCCESS;
|
||||
|
||||
KSpinlockAssertLocked(&scheduler.lock);
|
||||
|
||||
KSpinlockAcquire(&spinlock);
|
||||
|
||||
if (queueCount == ES_MAX_EVENT_SINK_BUFFER_SIZE) {
|
||||
overflow = true;
|
||||
result = ES_ERROR_EVENT_SINK_OVERFLOW;
|
||||
KernelLog(LOG_VERBOSE, "Event Sinks", "push overflow", "Push %d into %x.\n", data.i, this);
|
||||
} else {
|
||||
bool ignored = false;
|
||||
|
||||
if (ignoreDuplicates) {
|
||||
uintptr_t index = queuePosition;
|
||||
|
||||
for (uintptr_t i = 0; i < queueCount; i++) {
|
||||
if (queue[index] == data) {
|
||||
ignored = true;
|
||||
result = ES_ERROR_EVENT_SINK_DUPLICATE;
|
||||
KernelLog(LOG_VERBOSE, "Event Sinks", "push ignored", "Push %d into %x.\n", data.i, this);
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
|
||||
if (index == ES_MAX_EVENT_SINK_BUFFER_SIZE) {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignored) {
|
||||
uintptr_t writeIndex = queuePosition + queueCount;
|
||||
if (writeIndex >= ES_MAX_EVENT_SINK_BUFFER_SIZE) writeIndex -= ES_MAX_EVENT_SINK_BUFFER_SIZE;
|
||||
if (writeIndex >= ES_MAX_EVENT_SINK_BUFFER_SIZE) KernelPanic("EventSink::Push - Invalid event sink (%x) queue.\n", this);
|
||||
KernelLog(LOG_VERBOSE, "Event Sinks", "push", "Push %d into %x at %d (%d/%d).\n", data.i, this, writeIndex, queuePosition, queueCount);
|
||||
queue[writeIndex] = data;
|
||||
queueCount++;
|
||||
KEventSet(&available, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
KSpinlockRelease(&spinlock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool KEventSet(KEvent *event, bool schedulerAlreadyLocked, bool maybeAlreadySet) {
|
||||
if (event->state && !maybeAlreadySet) {
|
||||
KernelLog(LOG_ERROR, "Synchronisation", "event already set", "KEvent::Set - Attempt to set a event that had already been set\n");
|
||||
|
@ -377,13 +328,6 @@ bool KEventSet(KEvent *event, bool schedulerAlreadyLocked, bool maybeAlreadySet)
|
|||
volatile bool unblockedThreads = false;
|
||||
|
||||
if (!event->state) {
|
||||
if (event->sinkTable) {
|
||||
for (uintptr_t i = 0; i < ES_MAX_EVENT_FORWARD_COUNT; i++) {
|
||||
if (!event->sinkTable[i].sink) continue;
|
||||
event->sinkTable[i].sink->Push(event->sinkTable[i].data);
|
||||
}
|
||||
}
|
||||
|
||||
event->state = true;
|
||||
|
||||
if (scheduler.started) {
|
||||
|
|
|
@ -806,7 +806,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_WAIT) {
|
|||
SYSCALL_READ(handles, argument0, argument1 * sizeof(EsHandle));
|
||||
|
||||
for (uintptr_t i = 0; i < argument1; i++) {
|
||||
KernelObjectType typeMask = KERNEL_OBJECT_PROCESS | KERNEL_OBJECT_THREAD | KERNEL_OBJECT_EVENT | KERNEL_OBJECT_EVENT_SINK;
|
||||
KernelObjectType typeMask = KERNEL_OBJECT_PROCESS | KERNEL_OBJECT_THREAD | KERNEL_OBJECT_EVENT;
|
||||
status[i] = currentProcess->handleTable.ResolveHandle(&_objects[i], handles[i], typeMask);
|
||||
|
||||
if (status[i] == RESOLVE_HANDLE_FAILED) {
|
||||
|
@ -825,10 +825,6 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_WAIT) {
|
|||
events[i] = &((Thread *) object)->killedEvent;
|
||||
} break;
|
||||
|
||||
case KERNEL_OBJECT_EVENT_SINK: {
|
||||
events[i] = &((EventSink *) object)->available;
|
||||
} break;
|
||||
|
||||
case KERNEL_OBJECT_EVENT: {
|
||||
events[i] = (KEvent *) object;
|
||||
} break;
|
||||
|
@ -1464,111 +1460,6 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_PIPE_WRITE) {
|
|||
SYSCALL_RETURN(pipe->Access((void *) argument1, argument2, true, true), false);
|
||||
}
|
||||
|
||||
SYSCALL_IMPLEMENT(ES_SYSCALL_EVENT_SINK_CREATE) {
|
||||
EventSink *sink = (EventSink *) EsHeapAllocate(sizeof(EventSink), true, K_FIXED);
|
||||
|
||||
if (!sink) {
|
||||
SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false);
|
||||
}
|
||||
|
||||
sink->ignoreDuplicates = argument0;
|
||||
sink->handles = 1;
|
||||
|
||||
SYSCALL_RETURN(currentProcess->handleTable.OpenHandle(sink, 0, KERNEL_OBJECT_EVENT_SINK), false);
|
||||
}
|
||||
|
||||
SYSCALL_IMPLEMENT(ES_SYSCALL_EVENT_FORWARD) {
|
||||
SYSCALL_HANDLE(argument0, KERNEL_OBJECT_EVENT, event, KEvent);
|
||||
SYSCALL_HANDLE(argument1, KERNEL_OBJECT_EVENT_SINK, sink, EventSink);
|
||||
EsGeneric data = argument2;
|
||||
|
||||
bool error = false, limitExceeded = false;
|
||||
|
||||
KMutexAcquire(&eventForwardMutex);
|
||||
|
||||
if (!event->sinkTable) {
|
||||
event->sinkTable = (EventSinkTable *) EsHeapAllocate(sizeof(EventSinkTable) * ES_MAX_EVENT_FORWARD_COUNT, true, K_FIXED);
|
||||
|
||||
if (!event->sinkTable) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!error) {
|
||||
limitExceeded = true;
|
||||
|
||||
for (uintptr_t i = 0; i < ES_MAX_EVENT_FORWARD_COUNT; i++) {
|
||||
if (!event->sinkTable[i].sink) {
|
||||
if (!OpenHandleToObject(sink, KERNEL_OBJECT_EVENT_SINK, 0, false)) {
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
KSpinlockAcquire(&scheduler.lock);
|
||||
event->sinkTable[i].sink = sink;
|
||||
event->sinkTable[i].data = data;
|
||||
KSpinlockRelease(&scheduler.lock);
|
||||
|
||||
limitExceeded = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KMutexRelease(&eventForwardMutex);
|
||||
|
||||
if (limitExceeded) {
|
||||
SYSCALL_RETURN(ES_FATAL_ERROR_OUT_OF_RANGE, true);
|
||||
} else if (error) {
|
||||
SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false);
|
||||
} else {
|
||||
SYSCALL_RETURN(0, false);
|
||||
}
|
||||
}
|
||||
|
||||
SYSCALL_IMPLEMENT(ES_SYSCALL_EVENT_SINK_POP) {
|
||||
SYSCALL_HANDLE(argument0, KERNEL_OBJECT_EVENT_SINK, sink, EventSink);
|
||||
|
||||
bool empty = false, overflow = false;
|
||||
EsGeneric data = {};
|
||||
|
||||
KSpinlockAcquire(&sink->spinlock);
|
||||
|
||||
if (!sink->queueCount) {
|
||||
if (sink->overflow) {
|
||||
overflow = true;
|
||||
sink->overflow = false;
|
||||
} else {
|
||||
empty = true;
|
||||
}
|
||||
} else {
|
||||
data = sink->queue[sink->queuePosition];
|
||||
sink->queuePosition++;
|
||||
sink->queueCount--;
|
||||
|
||||
if (sink->queuePosition == ES_MAX_EVENT_SINK_BUFFER_SIZE) {
|
||||
sink->queuePosition = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sink->queueCount && !sink->overflow) {
|
||||
KEventReset(&sink->available); // KEvent::Reset doesn't take the scheduler lock, so this won't deadlock!
|
||||
}
|
||||
|
||||
KSpinlockRelease(&sink->spinlock);
|
||||
|
||||
SYSCALL_WRITE(argument1, &data, sizeof(EsGeneric));
|
||||
SYSCALL_RETURN(overflow ? ES_ERROR_EVENT_SINK_OVERFLOW : empty ? ES_ERROR_EVENT_NOT_SET : ES_SUCCESS, false);
|
||||
}
|
||||
|
||||
SYSCALL_IMPLEMENT(ES_SYSCALL_EVENT_SINK_PUSH) {
|
||||
SYSCALL_HANDLE(argument0, KERNEL_OBJECT_EVENT_SINK, sink, EventSink);
|
||||
KSpinlockAcquire(&scheduler.lock);
|
||||
EsError result = sink->Push(argument1);
|
||||
KSpinlockRelease(&scheduler.lock);
|
||||
SYSCALL_RETURN(result, false);
|
||||
}
|
||||
|
||||
SYSCALL_IMPLEMENT(ES_SYSCALL_DOMAIN_NAME_RESOLVE) {
|
||||
SYSCALL_PERMISSION(ES_PERMISSION_NETWORKING);
|
||||
|
||||
|
|
|
@ -131,13 +131,9 @@ EsPipeRead=129
|
|||
EsListViewInsert=130
|
||||
EsListViewRemove=131
|
||||
EsEventCreate=132
|
||||
EsEventForward=133
|
||||
EsBufferFormat=134
|
||||
EsEventReset=135
|
||||
EsEventSet=136
|
||||
EsEventSinkCreate=137
|
||||
EsEventSinkPop=138
|
||||
EsEventSinkPush=139
|
||||
EsMutexAcquire=140
|
||||
EsMutexDestroy=141
|
||||
EsMutexRelease=142
|
||||
|
|
Loading…
Reference in New Issue