# New Ticket Created by  Jürgen Bömmels 
# Please include the string:  [perl #21656]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt2/Ticket/Display.html?id=21656 >


Hello,

Yet another step in PIO:
Enabling read buffering.

The first read will fill the buffer by calling the underlying
read-function. Successive calls just take the data out of the read
buffers. If there is not enough data in the buffer it will refill as
necessary, but it will never call not call the underlying layer more
than once (If the underlying layer cant fullfill the request how can
the buffer-layer do).

I also attach a test file, which was very helpful in writing this. You
might add it to t/src/. But don't forget MANIFEST.

bye
boe



-- attachment  1 ------------------------------------------------------
url: http://rt.perl.org/rt2/attach/53999/40674/872e54/io3.diff

-- attachment  2 ------------------------------------------------------
url: http://rt.perl.org/rt2/attach/53999/40675/6a74eb/io.t

Index: io/io.c
===================================================================
RCS file: /cvs/public/parrot/io/io.c,v
retrieving revision 1.31
diff -u -r1.31 io.c
--- io/io.c	14 Mar 2003 20:20:19 -0000	1.31
+++ io/io.c	23 Mar 2003 00:42:13 -0000
@@ -149,10 +149,8 @@
 
     for (i = 0 ; i < PIO_NR_OPEN; i++) {
         if ( (io = GET_INTERP_IOD(interpreter)->table[i]) ) {
-#if 0
             PIO_flush(interpreter, io);
             PIO_close(interpreter, io);
-#endif
             mem_sys_free(io);
         }
     }
@@ -201,9 +199,7 @@
 #ifdef PIO_OS_STDIO
     PIO_push_layer(interpreter, PIO_base_new_layer(&pio_stdio_layer), NULL);
 #endif
-#if 0
     PIO_push_layer(interpreter, PIO_base_new_layer(&pio_buf_layer), NULL);
-#endif
 
     /* Note: All layer pushes should be done before init calls */
     for (p = GET_INTERP_IO(interpreter); p; p = p->down) {
Index: io/io_buf.c
===================================================================
RCS file: /cvs/public/parrot/io/io_buf.c,v
retrieving revision 1.2
diff -u -r1.2 io_buf.c
--- io/io_buf.c	17 Mar 2003 16:19:20 -0000	1.2
+++ io/io_buf.c	23 Mar 2003 00:42:13 -0000
@@ -55,9 +55,11 @@
 /* Local util functions */
 size_t PIO_buf_writethru(theINTERP, ParrotIOLayer *layer,
                            ParrotIO *io, const void *buffer, size_t len);
+size_t PIO_buf_readthru(theINTERP, ParrotIOLayer *layer,
+                           ParrotIO *io, void *buffer, size_t len);
 
-
-
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
 
 INTVAL
 PIO_buf_init(theINTERP, ParrotIOLayer *layer)
@@ -235,14 +237,95 @@
 PIO_buf_read(theINTERP, ParrotIOLayer *layer, ParrotIO *io,
                void *buffer, size_t len)
 {
-    UNUSED(interpreter);
-    UNUSED(layer);
-    UNUSED(io);
-    UNUSED(buffer);
-    UNUSED(len);
-    return 0;
+    ParrotIOLayer *l = layer;
+    ParrotIOBuf *b;
+    char *out_buf = buffer;
+    size_t current = 0;
+
+    /* write buffer flush */
+    if (io->b.flags & PIO_BF_WRITEBUF) {
+        PIO_buf_flush(interpreter, layer, io);
+    }
+
+    b = &io->b;
+
+    /* read Data from buffer */
+    if (b->flags & PIO_BF_READBUF) {
+        size_t avail = b->endb - b->next;
+
+        current = MIN(avail, len);
+        memcpy(out_buf, b->next, current);
+        b->next += current;
+
+        /* buffer completed */
+        if (current == avail) {
+            io->b.flags &= ~PIO_BF_READBUF;
+            /* XXX: Is the reset of next and endb really necessary ? */
+            io->b.endb = NULL;
+            io->b.next = io->b.startb;
+        }
+
+        if (len == current) {
+            return current;
+        }
+        else {
+            /* more data needed from downlayer */
+            out_buf += current;
+            len -= current;
+        }
+    }
+
+    /* (re)fill the readbuffer */
+    if (!(b->flags & PIO_BF_READBUF)) {
+        size_t got;
+
+        if (len >= io->b.size) {
+            return current + PIO_buf_readthru(interpreter, l, io, buffer, len);
+        }
+
+        got = PIO_buf_readthru(interpreter, l, io, b->startb, b->size);
+        b->endb = b->startb + got;
+        b->next = b->startb;
+
+        io->b.flags |= PIO_BF_READBUF;
+
+        len = MIN(len, got);
+    }
+
+    /* read from the read_buffer */
+    memcpy(out_buf, io->b.next, len);
+    io->b.next += len;
+
+    /* is the buffer is completely empty ? */
+    if (io->b.next == io->b.endb) {
+        io->b.flags &= ~PIO_BF_READBUF;
+        /* XXX: Is the reset of next and encb really necessary ? */
+        io->b.endb = NULL;
+        io->b.next = io->b.startb;
+    }
+    return current + len;
 }
 
+/* XXX: This function is not really io_buf specific */
+size_t
+PIO_buf_readthru (theINTERP, ParrotIOLayer *layer, ParrotIO *io,
+                    void *buffer, size_t len)
+{
+    ParrotIOLayer *l = layer;
+
+    do {
+        l = PIO_DOWNLAYER(layer);
+    } while (l && !l->api->Read);
+
+    if (l) {
+        return (l->api->Read)(interpreter, l, io, buffer, len);
+    }
+    else {
+        /* No underlying read implementation */
+        /* XXX: Handle error here */
+        return 0;
+    }
+}
 
 size_t
 PIO_buf_write(theINTERP, ParrotIOLayer *layer, ParrotIO *io,
#! perl -w

use Parrot::Test tests => 4;
use Test::More;

$/=undef; # slurp mode

TODO: {
    local $TODO="t/src doesn't work on Windows" if $^O =~ /Win32/;
    $TODO=$TODO;  #warnings

    c_output_is(<<'CODE', <<'OUTPUT', "hello world");
#include <parrot/parrot.h>
#include <parrot/io.h>

int
main ()
{
    int dummy_var;
    struct Parrot_Interp *interpreter;

    interpreter = Parrot_new();
    Parrot_init(interpreter, &dummy_var);

    PIO_printf(interpreter, "Hello, World!\n");

    return 0;
}
CODE
Hello, World!
OUTPUT

    c_output_is(<<'CODE', <<'OUTPUT', "write");
#include <parrot/parrot.h>
#include <parrot/io.h>

int
main ()
{
    int dummy_var;
    struct Parrot_Interp *interpreter;
    ParrotIO *io;
    char *p;

    interpreter = Parrot_new();
    Parrot_init(interpreter, &dummy_var);

    io = PIO_STDOUT(interpreter);
    PIO_write(interpreter, io, "Hello, World!\n", 14);

    io = PIO_open(interpreter, "temp.file", ">");
    for (p="Hello, World!\n"; *p; p++) {
        PIO_write (interpreter, io, p, 1);
    }
    PIO_close(interpreter, io);

    return 0;
}
CODE
Hello, World!
OUTPUT

  open FILE, "temp.file";
  is(<FILE>, <<DATA, 'file content');
Hello, World!
DATA
  close FILE;

  c_output_is(<<'CODE', <<'OUTPUT', 'read');
#include <parrot/parrot.h>
#include <parrot/io.h>

int
main ()
{
    int dummy_var;
    struct Parrot_Interp *interpreter;
    ParrotIO *io;
    char buf[1024];
    UINTVAL len;

    interpreter = Parrot_new();
    Parrot_init(interpreter, &dummy_var);

    io = PIO_open(interpreter, "temp.file", "<");
    len = PIO_read(interpreter, io, buf, sizeof(buf));
    PIO_close(interpreter, io);

    buf[len] = '\0';
    PIO_printf(interpreter, "%s", buf);

    io = PIO_open(interpreter, "temp.file", "<");
    /* this is for testing buffers, not for performance */
    PIO_setbuf(interpreter, io, 4);

    do {
        len = PIO_read(interpreter, io, buf, 3);
        buf[len] = '\0';
        PIO_printf(interpreter, "%d: %s\n", len, buf);
    } while (len > 0);

    return 0;
}
CODE
Hello, World!
3: Hel
3: lo,
3:  Wo
3: rld
2: !

0: 
OUTPUT

} # TODO

Reply via email to