smp: channel (WIP)
This commit is contained in:
parent
97e834b8af
commit
219bf76535
98
smp/channel.c
Normal file
98
smp/channel.c
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
|
||||||
|
#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);
|
63
smp/channel.h
Normal file
63
smp/channel.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "condiction.h"
|
||||||
|
|
||||||
|
#include "../main.h"
|
||||||
|
#include "../util/queue.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Channel is a one-way data channel across threads, with a fix-sized buffer.
|
||||||
|
typedef struct {
|
||||||
|
queue_Queue * queue; // internal buffer of data
|
||||||
|
void * buffer; // buffer for at least one piece of data
|
||||||
|
vector_Vector *send, *recv; // __smp_Channel_Waiter, for send and receive to wait on, and notify the other
|
||||||
|
uintptr_t objSize; // size in bytes of the underlying object, 0 if destroyed
|
||||||
|
intptr_t waitcnt; // (unused) >0: Send is waiting; <0: Recv is waiting; ==0: Nobody is waiting
|
||||||
|
} smp_Channel;
|
||||||
|
|
||||||
|
// Create allocates a new Channel.
|
||||||
|
smp_Channel *smp_Channel_Create(uintptr_t objectSize, uintptr_t bufferSize);
|
||||||
|
|
||||||
|
// Destroy frees a Channel.
|
||||||
|
void smp_Channel_Destroy(smp_Channel *chan);
|
||||||
|
|
||||||
|
// Send sends COUNT objects pointed at DATA down the channel.
|
||||||
|
//
|
||||||
|
// It waits if there are no one to receive it, and the buffer is already full.
|
||||||
|
// It will always return COUNT, unless the struct is destroyed.
|
||||||
|
//
|
||||||
|
// Returns the number of objects sent.
|
||||||
|
uintptr_t smp_Channel_Send(smp_Channel *chan, void *data, uintptr_t count);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
11
smp/channel_internal.h
Normal file
11
smp/channel_internal.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "channel.h"
|
||||||
|
|
||||||
|
|
||||||
|
// __smp_Channel_Waiter goes into Channel.send/recv
|
||||||
|
typedef struct {
|
||||||
|
void * buffer;
|
||||||
|
uintptr_t count; // object count, NOT bytes
|
||||||
|
smp_Condition *cond;
|
||||||
|
} __smp_Channel_Waiter;
|
Loading…
Reference in New Issue
Block a user