From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: ludovic.courtes@laas.fr (Ludovic =?iso-8859-1?Q?Court=E8s?=) Newsgroups: gmane.lisp.guile.devel Subject: Re: Unbuffered socket I/O Date: Thu, 01 Mar 2007 11:44:01 +0100 Organization: LAAS-CNRS Message-ID: <87bqjd6y6m.fsf@laas.fr> References: <87mz34ol6r.fsf@laas.fr> <87abz13kxl.fsf@zip.com.au> <877iu59fm8.fsf@laas.fr> <87slcsfqk4.fsf@zip.com.au> <87fy8qlik1.fsf@laas.fr> <874pp69ex0.fsf@zip.com.au> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Trace: sea.gmane.org 1172745856 8852 80.91.229.12 (1 Mar 2007 10:44:16 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Thu, 1 Mar 2007 10:44:16 +0000 (UTC) To: Guile-Devel Original-X-From: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Thu Mar 01 11:44:08 2007 Return-path: Envelope-to: guile-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1HMila-0002jb-F6 for guile-devel@m.gmane.org; Thu, 01 Mar 2007 11:44:06 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1HMilb-0005Zd-VH for guile-devel@m.gmane.org; Thu, 01 Mar 2007 05:44:08 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1HMilX-0005ZO-VG for guile-devel@gnu.org; Thu, 01 Mar 2007 05:44:03 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1HMilW-0005ZC-A4 for guile-devel@gnu.org; Thu, 01 Mar 2007 05:44:02 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1HMilW-0005Z9-1R for guile-devel@gnu.org; Thu, 01 Mar 2007 05:44:02 -0500 Original-Received: from laas.laas.fr ([140.93.0.15]) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_3DES_EDE_CBC_SHA:24) (Exim 4.52) id 1HMilV-0005qU-6h for guile-devel@gnu.org; Thu, 01 Mar 2007 05:44:01 -0500 Original-Received: from messiaen.laas.fr (messiaen [IPv6:2001:660:6602:0:230:65ff:fed4:9d20]) by laas.laas.fr (8.13.8/8.13.8) with SMTP id l21AhvbQ018309 for ; Thu, 1 Mar 2007 11:43:57 +0100 (MET) Original-Received: by messiaen.laas.fr (sSMTP sendmail emulation); Thu, 01 Mar 2007 11:44:02 +0100 X-URL: http://www.laas.fr/~lcourtes/ X-Revolutionary-Date: 11 =?iso-8859-1?Q?Vent=F4se?= an 215 de la =?iso-8859-1?Q?R=E9volution?= X-PGP-Key-ID: 0xEB1F5364 X-PGP-Key: http://www.laas.fr/~lcourtes/ludovic.asc X-PGP-Fingerprint: 821D 815D 902A 7EAB 5CEE D120 7FBA 3D4F EB1F 5364 X-OS: powerpc-unknown-linux-gnu Mail-Followup-To: Guile-Devel In-Reply-To: <874pp69ex0.fsf@zip.com.au> (Kevin Ryde's message of "Thu, 01 Mar 2007 07:59:39 +1100") User-Agent: Gnus/5.110006 (No Gnus v0.6) Emacs/21.4 (gnu/linux) X-Spam-Score: 0.306 () MAILTO_TO_SPAM_ADDR,NO_RELAYS X-Scanned-By: MIMEDefang at CNRS-LAAS on IPv6:2001:660:6602::2 X-detected-kernel: Solaris 10 (beta) X-BeenThere: guile-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Developers list for Guile, the GNU extensibility library" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Errors-To: guile-devel-bounces+guile-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.devel:6584 Archived-At: --=-=-= Hi, Attached is an updated patch. Ok to apply? Kevin Ryde writes: >> Besides, how about applying the change I originally proposed to HEAD? > > No, principally because unbuffered is an advertised feature. Hey, it's only advertised as long as we advertise it! ;-) I mean, if we start nitpicking about such changes in HEAD, then we'll never implement a Unicode-capable port I/O interface, will we? :-) > Even if > it was year zero you'd probably still choose them to start unbuffered, > since there's various ways to do comms and it can be up to an > application how much might be desirable. For block operations for > instance it's certainly not wanted. The thing is that port buffering in Guile does not necessarily have a direct relationship to OS-level buffering. This is clear for input, where one can have unbuffered OS-level file descriptor and where port-level input buffering only impacts performance, not semantics. Conversely, port-level output buffering does have a visible impact from the outside world. Thanks for your comments! Ludovic. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename*=us-ascii''%2c%2csocket-buffering-2.diff Content-Description: The improved patch. --- orig/doc/ref/posix.texi +++ mod/doc/ref/posix.texi @@ -472,6 +472,21 @@ @end defvar @end deffn +@deffn {Scheme Procedure} setvbuf-input port size +@deffnx {C Function} scm_setvbuf_input (port, size) +Use a @var{size}-byte input buffer for @var{port}, which must be a +file or socket port. Note that buffered data is lost if the input +buffer contains more than @var{size} bytes. Thus, it may be necessary +to call @code{drain-input} prior to @code{setvbuf-input}. +@end deffn + +@deffn {Scheme Procedure} setvbuf-output port size +@deffnx {C Function} scm_setvbuf_output (port, size) +Use a @var{size}-byte output buffer for @var{port}, which must be a +file or socket port. The current output buffer may be flushed as a +result of this operation. +@end deffn + @deffn {Scheme Procedure} fcntl port/fd cmd [value] @deffnx {C Function} scm_fcntl (object, cmd, value) Apply @var{cmd} on @var{port/fd}, either a port or file descriptor. --- orig/libguile/fports.c +++ mod/libguile/fports.c @@ -86,14 +86,20 @@ scm_t_bits scm_tc16_fport; +static void fport_flush (SCM port); + +/* Hints passed to the GC allocation functions for port buffers and file + ports. */ +static const char gc_port_buffer_hint[] = "port buffer"; +static const char gc_file_port_hint[] = "file port"; /* default buffer size, used if the O/S won't supply a value. */ static const size_t default_buffer_size = 1024; -/* create FPORT buffer with specified sizes (or -1 to use default size or - 0 for no buffer. */ +/* Create FPORT buffer with specified sizes (or -1 to use default size or + 0 for no buffer). */ static void -scm_fport_buffer_add (SCM port, long read_size, int write_size) +scm_fport_buffer_add (SCM port, long read_size, long write_size) #define FUNC_NAME "scm_fport_buffer_add" { scm_t_port *pt = SCM_PTAB_ENTRY (port); @@ -118,7 +124,7 @@ if (SCM_INPUT_PORT_P (port) && read_size > 0) { - pt->read_buf = scm_gc_malloc (read_size, "port buffer"); + pt->read_buf = scm_gc_malloc (read_size, gc_port_buffer_hint); pt->read_pos = pt->read_end = pt->read_buf; pt->read_buf_size = read_size; } @@ -130,7 +136,7 @@ if (SCM_OUTPUT_PORT_P (port) && write_size > 0) { - pt->write_buf = scm_gc_malloc (write_size, "port buffer"); + pt->write_buf = scm_gc_malloc (write_size, gc_port_buffer_hint); pt->write_pos = pt->write_buf; pt->write_buf_size = write_size; } @@ -208,15 +214,140 @@ pt->read_buf_size = pt->saved_read_buf_size; } if (pt->read_buf != &pt->shortbuf) - scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer"); + scm_gc_free (pt->read_buf, pt->read_buf_size, gc_port_buffer_hint); if (pt->write_buf != &pt->shortbuf) - scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer"); + scm_gc_free (pt->write_buf, pt->write_buf_size, gc_port_buffer_hint); scm_fport_buffer_add (port, csize, csize); return SCM_UNSPECIFIED; } #undef FUNC_NAME +SCM_DEFINE (scm_setvbuf_input, "setvbuf-input", 2, 0, 0, + (SCM port, SCM size), + "Use a @var{size}-byte input buffer for @var{port}, which " + "must be a file or socket port. Note that buffered data " + "is lost if the input buffer contains more than @var{size} " + "bytes. Thus, it may be necessary to call " + "@code{drain-input} prior to @code{setvbuf-input}.") +#define FUNC_NAME s_scm_setvbuf_input +{ + scm_t_port *pt; + size_t c_size; + + SCM_VALIDATE_FPORT (1, port); + c_size = scm_to_size_t (size); + + pt = SCM_PTAB_ENTRY (port); + + if (pt->read_buf_size != c_size) + { + size_t c_offset, c_end; + unsigned char *new_buf; + + c_end = pt->read_end - pt->read_buf; + c_offset = pt->read_pos - pt->read_buf; + + if (c_offset > c_size) + /* Discard all the buffered input. */ + c_offset = c_end = 0; + + if (c_size == 0) + { + new_buf = &pt->shortbuf, c_size = 1; + if (pt->read_buf != &pt->shortbuf) + scm_gc_free (pt->read_buf, pt->read_buf_size, + gc_port_buffer_hint); + } + else + { + if (pt->read_buf != &pt->shortbuf) + new_buf = scm_gc_realloc (pt->read_buf, + pt->read_buf_size, c_size, + gc_port_buffer_hint); + else + new_buf = scm_gc_malloc (c_size, gc_port_buffer_hint); + } + + pt->read_buf = new_buf; + pt->read_end = new_buf + c_end; + pt->read_pos = new_buf + c_offset; + pt->read_buf_size = c_size; + + if ((pt->read_buf_size == 0) && (pt->write_buf_size == 0)) + SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUF0); + else + SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0); + } + + return SCM_UNSPECIFIED; +} +#undef FUNC_NAME + +SCM_DEFINE (scm_setvbuf_output, "setvbuf-output", 2, 0, 0, + (SCM port, SCM size), + "Use a @var{size}-byte output buffer for @var{port}, which " + "must be a file or socket port. The current output buffer " + "may be flushed as a result of this operation.") +#define FUNC_NAME s_scm_setvbuf_output +{ + scm_t_port *pt; + size_t c_size; + + SCM_VALIDATE_FPORT (1, port); + c_size = scm_to_size_t (size); + + pt = SCM_PTAB_ENTRY (port); + + if (pt->write_buf_size != c_size) + { + size_t c_offset, c_end; + unsigned char *new_buf; + + do_it: + c_end = pt->write_end - pt->write_buf; + c_offset = pt->write_pos - pt->write_buf; + + if (c_offset > c_size) + { + /* Flush the output buffer so that it can be shrunk. */ + fport_flush (port); + goto do_it; + } + + if (c_size == 0) + { + new_buf = &pt->shortbuf, c_size = 1; + if (pt->write_buf != &pt->shortbuf) + scm_gc_free (pt->write_buf, pt->write_buf_size, + gc_port_buffer_hint); + } + else + { + if (pt->write_buf != &pt->shortbuf) + new_buf = scm_gc_realloc (pt->write_buf, + pt->write_buf_size, c_size, + gc_port_buffer_hint); + else + new_buf = scm_gc_malloc (c_size, gc_port_buffer_hint); + } + + pt->write_buf = new_buf; + pt->write_end = new_buf + c_end; + pt->write_pos = new_buf + c_offset; + pt->write_buf_size = c_size; + + if ((pt->read_buf_size == 0) && (pt->write_buf_size == 0)) + SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) | SCM_BUF0); + else + SCM_SET_CELL_WORD_0 (port, SCM_CELL_WORD_0 (port) & ~SCM_BUF0); + } + + return SCM_UNSPECIFIED; +} +#undef FUNC_NAME + + /* Move ports with the specified file descriptor to new descriptors, * resetting the revealed count to 0. */ @@ -459,7 +590,8 @@ pt = SCM_PTAB_ENTRY(port); { scm_t_fport *fp - = (scm_t_fport *) scm_gc_malloc (sizeof (scm_t_fport), "file port"); + = (scm_t_fport *) scm_gc_malloc (sizeof (scm_t_fport), + gc_file_port_hint); fp->fdes = fdes; pt->rw_random = SCM_FDES_RANDOM_P (fdes); @@ -583,8 +715,6 @@ } #endif /* !__MINGW32__ */ -static void fport_flush (SCM port); - /* fill a port's read-buffer with a single read. returns the first char or EOF if end of file. */ static int @@ -892,10 +1022,10 @@ if (pt->read_buf == pt->putback_buf) pt->read_buf = pt->saved_read_buf; if (pt->read_buf != &pt->shortbuf) - scm_gc_free (pt->read_buf, pt->read_buf_size, "port buffer"); + scm_gc_free (pt->read_buf, pt->read_buf_size, gc_port_buffer_hint); if (pt->write_buf != &pt->shortbuf) - scm_gc_free (pt->write_buf, pt->write_buf_size, "port buffer"); - scm_gc_free (fp, sizeof (*fp), "file port"); + scm_gc_free (pt->write_buf, pt->write_buf_size, gc_port_buffer_hint); + scm_gc_free (fp, sizeof (*fp), gc_file_port_hint); return rv; } --- orig/libguile/fports.h +++ mod/libguile/fports.h @@ -49,6 +49,8 @@ SCM_API SCM scm_setbuf0 (SCM port); SCM_API SCM scm_setvbuf (SCM port, SCM mode, SCM size); +SCM_API SCM scm_setvbuf_input (SCM port, SCM size); +SCM_API SCM scm_setvbuf_output (SCM port, SCM size); SCM_API void scm_evict_ports (int fd); SCM_API SCM scm_open_file (SCM filename, SCM modes); SCM_API SCM scm_fdes_to_port (int fdes, char *mode, SCM name); --=-=-= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Guile-devel mailing list Guile-devel@gnu.org http://lists.gnu.org/mailman/listinfo/guile-devel --=-=-=--