diff --git a/lib/modules/Stdio.pmod/module.pmod b/lib/modules/Stdio.pmod/module.pmod index 90ff4195a5f99bbc03bbcf0cf70a4e5c4f27cece..1c63c97b0e1e29b369f71e71c4fb38bdb3bd3491 100644 --- a/lib/modules/Stdio.pmod/module.pmod +++ b/lib/modules/Stdio.pmod/module.pmod @@ -1,4 +1,4 @@ -// $Id: module.pmod,v 1.44 1999/04/16 14:04:42 grubba Exp $ +// $Id: module.pmod,v 1.45 1999/04/19 18:33:52 grubba Exp $ import String; @@ -236,6 +236,7 @@ class File return 1; } + // FIXME: No way to specify the maximum to read. static void __stdio_read_callback() { #if defined(__STDIO_DEBUG) && !defined(__NT__) @@ -690,6 +691,9 @@ static class nb_sendfile static int reader_awake; static int writer_awake; + static int blocking_to; + static int blocking_from; + /* Reader */ static void reader_done() @@ -697,7 +701,7 @@ static class nb_sendfile from->set_nonblocking(0,0,0); from = 0; if (trailers) { - to_write += (trailers - ({""})); + to_write += trailers; } if (sizeof(to_write)) { start_writer(); @@ -709,6 +713,21 @@ static class nb_sendfile reader_done(); } + static void do_read() + { + string more_data = from->read(65536, 1); + if (more_data == "") { + // EOF. + from = 0; + if (trailers) { + to_write += (trailers - ({ "" })); + trailers = 0; + } + } else { + to_write += ({ more_data }); + } + } + static void read_cb(mixed ignored, string data) { if (len > 0) { @@ -722,12 +741,26 @@ static class nb_sendfile } else { to_write += ({ data }); } - if (sizeof(to_write) > READER_HALT) { - // Go to sleep. - from->set_nonblocking(0,0,0); - reader_awake = 0; + if (blocking_to) { + while(sizeof(to_write)) { + if (!do_write()) { + // Connection closed or Disk full. + writer_done(); + return; + } + } + if (!from) { + writer_done(); + return; + } + } else { + if (sizeof(to_write) > READER_HALT) { + // Go to sleep. + from->set_nonblocking(0,0,0); + reader_awake = 0; + } + start_writer(); } - start_writer(); } static void start_reader() @@ -759,7 +792,7 @@ static class nb_sendfile cb(sent, @a); } - static void write_cb(mixed ignored) + static int do_write() { int bytes = to->write(to_write); @@ -772,30 +805,42 @@ static class nb_sendfile to_write[n] = to_write[n][bytes..]; to_write = to_write[n..]; - if (sizeof(to_write) < READER_RESTART) { - start_reader(); - } - return; + return 1; } else { bytes -= sizeof(to_write[n]); if (!bytes) { to_write = to_write[n+1..]; - if (sizeof(to_write) < READER_RESTART) { - if (!sizeof(to_write)) { - // Go to sleep. - to->set_nonblocking(0,0,0); - writer_awake = 0; - if (!from) { - // Done! - writer_done(); - return; - } - } - start_reader(); + return 1; + } + } + } + // Not reached, but... + return 1; + } else { + // Premature end of file! + return 0; + } + } + + static void write_cb(mixed ignored) + { + if (do_write()) { + if (from) { + if (blocking_from) { + do_read(); + } else { + if (sizeof(to_write) < READER_RESTART) { + if (!sizeof(to_write)) { + // Go to sleep. + to->set_nonblocking(0,0,0); + writer_awake = 0; } - return; + start_reader(); } } + } else if (!sizeof(to_write)) { + // Done. + writer_done(); } } else { // Premature end of file! @@ -811,6 +856,20 @@ static class nb_sendfile } } + /* Blocking */ + static void do_blocking() + { + if (from && (sizeof(to_write) < READER_RESTART)) { + do_read(); + } + if (sizeof(to_write) && do_write()) { + call_out(do_blocking, 0); + } else { + from = 0; + writer_done(); + } + } + /* Starter */ void create(array(string) hd, @@ -849,14 +908,41 @@ static class nb_sendfile callback = cb; args = a; + blocking_to = ((!to->set_nonblocking) || + (to->mode && !(to->mode() & PROP_NONBLOCK))); + + if (blocking_to && to->set_blocking) { + to->set_blocking(); + } + if (from) { + blocking_from = ((!from->set_nonblocking) || + (from->mode && !(from->mode() & PROP_NONBLOCK))); + if (off >= 0) { from->seek(off); } - start_reader(); + if (blocking_from) { + if (from->set_blocking) { + from->set_blocking(); + } + } else { + start_reader(); + } } - if (sizeof(to_write)) { - start_writer(); + + if (blocking_to) { + if (!from || blocking_from) { + // Can't use the reader to push data. + + // Could have a direct call to do_blocking here, + // but then the callback would be called from the wrong context. + call_out(do_blocking, 0); + } + } else { + if (sizeof(to_write)) { + start_writer(); + } } } }