helos1/smp/channel.c
2021-11-14 19:25:18 +08:00

99 lines
2.6 KiB
C

#include "channel.h"
#include "../interrupt/interrupt.h"
#include "../memory/memory.h"
#include "kthread.h"
#include "string.h"
smp_Channel *smp_Channel_Create(uintptr_t objectSize, uintptr_t bufferSize) {
smp_Channel *c = kMalloc(sizeof(smp_Channel));
c->objSize = objectSize;
c->buffer = kMalloc(objectSize);
c->send = smp_Condition_Create();
c->recv = smp_Condition_Create();
if (bufferSize) {
c->queue = kMalloc(sizeof(queue_Queue));
queue_InitBuffered(c->queue, kMalloc(objectSize * bufferSize), objectSize * bufferSize);
} else
c->queue = NULL;
return c;
}
// Destroy frees a Channel.
// TODO This is unsafe, dont use while there are someone waiting on it
void smp_Channel_Destroy(smp_Channel *c) {
c->objSize = 0;
smp_Condition_NotifyAll(c->send, 0);
smp_Condition_NotifyAll(c->recv, 0);
kFree(c->queue->data);
kFree(c->queue);
kFree(c->buffer);
kFree(c);
}
static inline uintptr_t __smp_Channel_SendUnbuffered(smp_Channel *c, void *data, uintptr_t count) {
uintptr_t sent = 0;
}
uintptr_t smp_Channel_Send(smp_Channel *c, void *data, uintptr_t count) {
uintptr_t sent = 0;
int i = 0;
if (c->queue) {
// Fill the queue first
INTERRUPT_DISABLE;
while (i < count && queue_Space(c->queue))
queue_Push(c->queue, data + i++ * c->objSize, c->objSize);
INTERRUPT_RESTORE;
// Notify the waiting crew
smp_Condition_NotifyAll(c->recv, 0);
smp_thread_Yield();
}
sent = i;
// If there are leftovers:
for (; i < count; i++) {
smp_Condition_Wait(c->send);
INTERRUPT_DISABLE;
memcpy(c->buffer, data + i * c->objSize, c->objSize);
INTERRUPT_RESTORE;
smp_Condition_NotifyOne(c->recv, (void *)1);
smp_thread_Yield();
}
return sent;
}
// TrySend attempts sending COUNT objects pointed at DATA down the channel.
//
// It gives up if there are no one to receive the data, and the buffer if already full.
//
// Returns the number of objects sent.
uintptr_t smp_Channel_TrySend(smp_Channel *chan, void *data, uintptr_t count);
// Receive reveices at most MAXCOUNT objects, writing them into the buffer DATA.
//
// It returns at once if there are some data, not necessrily filling the entire buffer.
// It waits if there are no data available, it will not return 0 (unless the struct is destroyed).
//
// Returns the number of objects received.
uintptr_t smp_Channel_Receive(smp_Channel *chan, void *data, uintptr_t maxcount);
// TryReceive attempts receiving at most MAXCOUNT objects.
//
// If there are no data available, it returns 0.
//
// Returns the number of objects received.
uintptr_t smp_Channel_TryReceive(smp_Channel *chan, void *data, uintptr_t maxcount);