You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.6 KiB
134 lines
3.6 KiB
#include "src/kernel/pipe.h"
|
|
#include "src/kernel/process.h"
|
|
#include "src/kernel/stream.h"
|
|
#include "src/lib/memory.h"
|
|
|
|
#define PIPE_BUFFER_SIZE 65536
|
|
|
|
typedef struct {
|
|
char buffer[PIPE_BUFFER_SIZE];
|
|
uint64_t begin;
|
|
uint64_t end;
|
|
uint8_t write_closed;
|
|
uint8_t read_closed;
|
|
} pipe_t;
|
|
|
|
typedef struct {
|
|
stream_t stream;
|
|
pipe_t *pipe;
|
|
} pipe_read_stream_t;
|
|
|
|
typedef struct {
|
|
stream_t stream;
|
|
pipe_t *pipe;
|
|
} pipe_write_stream_t;
|
|
|
|
static uint64_t null_read(__attribute__((unused)) stream_t *self, __attribute__((unused)) uint64_t max,
|
|
__attribute__((unused)) char *to) {
|
|
return 0;
|
|
}
|
|
|
|
static uint64_t null_write(__attribute__((unused)) stream_t *self, __attribute__((unused)) const char *from,
|
|
__attribute__((unused)) uint64_t bytes) {
|
|
return 0;
|
|
}
|
|
|
|
static uint64_t pipe_read(stream_t *self, uint64_t max, char *to) {
|
|
pipe_t *pipe = ((pipe_read_stream_t *)self)->pipe;
|
|
|
|
while (pipe->begin == pipe->end) {
|
|
if (pipe->write_closed) {
|
|
return 0;
|
|
}
|
|
__asm__ volatile("sti");
|
|
process_next();
|
|
__asm__ volatile("cli");
|
|
}
|
|
|
|
uint64_t available = (pipe->end + PIPE_BUFFER_SIZE - pipe->begin) % PIPE_BUFFER_SIZE;
|
|
uint64_t to_read = available < max ? available : max;
|
|
|
|
if (pipe->begin + to_read <= PIPE_BUFFER_SIZE) {
|
|
memory_copy(pipe->buffer + pipe->begin, to_read, to);
|
|
} else {
|
|
uint64_t chunk = PIPE_BUFFER_SIZE - pipe->begin;
|
|
memory_copy(pipe->buffer + pipe->begin, chunk, to);
|
|
memory_copy(pipe->buffer, to_read - chunk, to + chunk);
|
|
}
|
|
|
|
pipe->begin = (pipe->begin + to_read) % PIPE_BUFFER_SIZE;
|
|
return to_read;
|
|
}
|
|
|
|
static uint64_t pipe_write(stream_t *self, const char *from, uint64_t bytes) {
|
|
pipe_t *pipe = ((pipe_read_stream_t *)self)->pipe;
|
|
|
|
uint64_t written = 0;
|
|
while (written < bytes) {
|
|
while (((pipe->end + 1) % PIPE_BUFFER_SIZE) == pipe->begin) {
|
|
if (pipe->read_closed) {
|
|
return written;
|
|
}
|
|
__asm__ volatile("sti");
|
|
process_next();
|
|
__asm__ volatile("cli");
|
|
}
|
|
|
|
uint64_t available = PIPE_BUFFER_SIZE - (pipe->end + PIPE_BUFFER_SIZE - pipe->begin) % PIPE_BUFFER_SIZE - 1;
|
|
uint64_t to_write = available < bytes - written ? available : bytes - written;
|
|
|
|
if (pipe->end + to_write <= PIPE_BUFFER_SIZE) {
|
|
memory_copy(from, to_write, pipe->buffer + pipe->end);
|
|
} else {
|
|
uint64_t chunk = PIPE_BUFFER_SIZE - pipe->end;
|
|
memory_copy(from, chunk, pipe->buffer + pipe->end);
|
|
memory_copy(from + chunk, to_write - chunk, pipe->buffer);
|
|
}
|
|
|
|
pipe->end = (pipe->end + to_write) % PIPE_BUFFER_SIZE;
|
|
written += to_write;
|
|
}
|
|
|
|
return written;
|
|
}
|
|
|
|
static void read_close(stream_t *self) {
|
|
pipe_t *pipe = ((pipe_read_stream_t *)self)->pipe;
|
|
|
|
pipe->read_closed = 1;
|
|
|
|
if (pipe->read_closed && pipe->write_closed) {
|
|
memory_free(pipe);
|
|
}
|
|
memory_free(self);
|
|
}
|
|
|
|
static void write_close(stream_t *self) {
|
|
pipe_t *pipe = ((pipe_write_stream_t *)self)->pipe;
|
|
|
|
pipe->write_closed = 1;
|
|
|
|
if (pipe->read_closed && pipe->write_closed) {
|
|
memory_free(pipe);
|
|
}
|
|
memory_free(self);
|
|
}
|
|
|
|
void pipe_init(stream_t **write, stream_t **read) {
|
|
pipe_t *pipe = memory_allocate(sizeof(pipe_t));
|
|
|
|
pipe_write_stream_t *ws = memory_allocate(sizeof(pipe_write_stream_t));
|
|
ws->stream.read = null_read;
|
|
ws->stream.write = pipe_write;
|
|
ws->stream.close = write_close;
|
|
ws->pipe = pipe;
|
|
|
|
pipe_read_stream_t *rs = memory_allocate(sizeof(pipe_read_stream_t));
|
|
rs->stream.read = pipe_read;
|
|
rs->stream.write = null_write;
|
|
rs->stream.close = read_close;
|
|
rs->pipe = pipe;
|
|
|
|
*write = (stream_t *)ws;
|
|
*read = (stream_t *)rs;
|
|
}
|
|
|