Commit 3ce55f06 authored by Kevin Wolf's avatar Kevin Wolf

kernel2: lio_pipe() implementiert

+ kernel2: Kernelinterne Funktion, um eine (uni- oder bidirektionale)
  Pipe zu erstellen
Signed-off-by: Kevin Wolf's avatarKevin Wolf <kevin@tyndur.org>
parent 1c5fab86
......@@ -57,4 +57,7 @@ __attribute__((noreturn)) void panic(char* message, ...);
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define DIV_ROUND_UP(x, align) (((x) + (align) + 1) / (align))
#define ROUND_UP(x, align) (DIV_ROUND_UP(x, align) * (align))
#endif
......@@ -56,6 +56,18 @@ struct lio_resource* lio_get_resource(const char* path, int follow_symlinks);
int lio_probe_service(struct lio_resource* res,
struct lio_probe_service_result* probe_data);
/**
* Erstellt eine neue Pipe und gibt einen Stream auf beide Enden zurück
*
* @param bidirectional Wenn false, dann kann auf writer nur geschrieben und
* auf reader nur gelesen werden. Wenn true, dann funktioniert auch die andere
* Richtung.
*
* @return 0 bei Erfolg, -errno im Fehlerfall
*/
int lio_pipe(struct lio_stream **reader, struct lio_stream **writer,
bool bidirectional);
/**
* Oeffnet einen Stream zu einer Ressource
*
......
......@@ -225,6 +225,74 @@ struct lio_resource* lio_get_resource(const char* path, int follow_symlinks)
return lio_do_get_resource(path, follow_symlinks, 0);
}
/**
* Erstellt eine neue Pipe und gibt einen Stream auf beide Enden zurück
*
* @param bidirectional Wenn false, dann kann auf writer nur geschrieben und
* auf reader nur gelesen werden. Wenn true, dann funktioniert auch die andere
* Richtung.
*
* @return 0 bei Erfolg, -errno im Fehlerfall
*/
int lio_pipe(struct lio_stream **reader, struct lio_stream **writer,
bool bidirectional)
{
struct lio_resource* res_reader = lio_create_pipe();
struct lio_resource* res_writer = lio_create_pipe();
struct lio_stream* s;
int ret;
*reader = NULL;
*writer = NULL;
if (!res_reader || !res_writer) {
ret = -ENOMEM;
goto fail;
}
s = malloc(sizeof(*s));
if (s == NULL) {
ret = -ENOMEM;
goto fail;
}
*s = (struct lio_stream) {
.res = res_reader,
.res_read = res_reader,
.res_write = res_writer,
.flags = LIO_READ | (bidirectional ? LIO_WRITE : 0),
.eof = false,
};
*reader = s;
s = malloc(sizeof(*s));
if (s == NULL) {
ret = -ENOMEM;
goto fail;
}
*s = (struct lio_stream) {
.res = res_writer,
.res_read = res_writer,
.res_write = res_reader,
.flags = LIO_WRITE | (bidirectional ? LIO_READ : 0),
.eof = false,
};
*writer = s;
res_reader->ref = 2;
res_writer->ref = 2;
return 0;
fail:
free(*reader);
free(*writer);
lio_destroy_pipe(res_reader);
lio_destroy_pipe(res_writer);
return ret;
}
/**
* Oeffnet einen Stream zu einer Ressource
*
......@@ -293,6 +361,7 @@ struct lio_stream* lio_open(struct lio_resource* res, int flags)
res->excl_stream = s;
}
res->ref++;
return s;
fail:
......@@ -653,13 +722,22 @@ int lio_close(struct lio_stream* s)
// Sicherstellen, dass lio_open() den Stream nicht rausrückt, während wir
// ihn gerade schließen
s->flags = 0;
s->res->excl_stream = NULL;
BUG_ON(s->res_read->ref <= 0);
s->res_read->ref--;
if (s->res_read != s->res_write) {
BUG_ON(s->res_write->excl_stream);
BUG_ON(s->res_write->ref <= 0);
s->res_write->ref--;
}
if (s->res->tree->service->lio_ops.close) {
s->res->tree->service->lio_ops.close(s);
s->res = NULL;
}
s->res->excl_stream = NULL;
free(s);
return 0;
}
......
......@@ -162,6 +162,9 @@ struct lio_resource {
*/
list_t* children;
/** Referenzzähler */
int ref;
/** Größe der Ressource in Bytes */
uint64_t size;
......@@ -260,6 +263,10 @@ void lio_init_resource(struct lio_resource* res);
*/
void lio_destroy_resource(struct lio_resource* res);
/* Pipe-Funktionen */
struct lio_resource* lio_create_pipe(void);
void lio_destroy_pipe(struct lio_resource* res);
/** Loest einen Pfad in eine Ressource auf */
struct lio_resource* lio_do_get_resource(const char* path, int follow_symlinks,
int depth);
......
/*
* Copyright (c) 2009 The tyndur Project. All rights reserved.
*
* This code is derived from software contributed to the tyndur Project
* by Antoine Kaufmann.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the tyndur Project
* and its contributors.
* 4. Neither the name of the tyndur Project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "kernel.h"
#include "lostio_int.h"
#include "kprintf.h"
static struct lio_service service;
static struct lio_tree tree = {
.service = &service,
.source = NULL,
};
struct pipehandle {
/* Die Größe der Ressource wird automatisch von LIO angepasst, aber die
* allozierte Puffergröße ist eine separate Sache. */
uint64_t bufsize;
uint8_t* data;
};
static int pipe_read(struct lio_resource* res, uint64_t offset, size_t bytes,
void* buf)
{
struct pipehandle* ph = res->opaque;
BUG_ON(res->size != ph->bufsize);
if (offset >= res->size) {
return -EINVAL;
}
bytes = MIN(bytes, res->size - offset);
memcpy(buf, ph->data + offset, bytes);
/* TODO Puffer verkleinern: Alles vor offset kann weggeworfen werden */
return 0;
}
static int pipe_write(struct lio_resource* res, uint64_t offset,
size_t bytes, void* buf)
{
struct pipehandle* ph = res->opaque;
BUG_ON(offset + bytes > res->size);
if (offset + bytes > ph->bufsize) {
uint64_t new_size;
void* new_buf;
new_size = offset + bytes;
new_buf = realloc(ph->data, new_size);
if (new_buf == NULL) {
return -ENOMEM;
}
ph->bufsize = new_size;
ph->data = new_buf;
lio_resource_update_size(res, new_size);
}
memcpy(ph->data + offset, buf, bytes);
return 0;
}
struct lio_resource* lio_create_pipe(void)
{
struct lio_resource* res = lio_create_resource();
struct pipehandle *ph = malloc(sizeof(*ph));
*ph = (struct pipehandle) {
.bufsize = 0,
.data = NULL,
};
res->tree = &tree;
res->size = 0;
res->blocksize = 1;
res->readable = true;
res->writable = true;
res->moredata = true;
res->opaque = ph;
return res;
}
void lio_destroy_pipe(struct lio_resource* res)
{
struct pipehandle* ph = res->opaque;
free(ph->data);
free(ph);
lio_destroy_resource(res);
}
void pipe_close(struct lio_stream* s)
{
if (s->res_read->ref == 0) {
lio_destroy_pipe(s->res_read);
}
if (s->res_write->ref == 0) {
lio_destroy_pipe(s->res_write);
}
}
static struct lio_service service = {
.name = "internal_pipes",
.lio_ops = {
.read = pipe_read,
.write = pipe_write,
.close = pipe_close,
},
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment