# 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