This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

port system revised



This message may be of interest to people writing network servers in
Guile.


> We have found that guile provokes a problem with communicating over
> sockets, which we believe is due to a problem in solaris libc. Below
> is a patch that implements a workaround.
> 
> The problem has been seen on both solaris 2.5.1 (with and without
> patches) and solaris 2.6. We are working on the x86 platform. We have
> not been able to test this on sparc or solaris 2.4.
> 
> The problem appears also under the latest snapshot (19980804).

In a previous message, I explained that this bug was due to the fact
that the C library stdio routines, which Guile uses to implement its
ports, can't handle mixed reads and writes on a port, unless you make
some odd intervening calls to irrelevant functions --- fseek, fflush,
etc.  Your server reads from a socket, and then writes to it.

When I tried to fix this, I found that the port system had a few
blemishes that prevented me from doing so.  I've fixed them, and then
fixed this bug.  The changes are pretty large (about 44k context
diff), and who knows what snapshot they fit into exactly, so I'd
recommend you freshen your sources via CVS or FTP.

In the long run, I'd like to make Guile not depend on stdio, for
various reasons.

Thanks for the bug report!



1998-10-09  Jim Blandy  <jimb@zwingli.cygnus.com>

	* fports.h (scm_setbuf0, scm_setvbuf, scm_setfileno,
	scm_evict_ports, scm_open_file, scm_stdio_to_port): Get rid of
	SCM_P macro.

	Do magic to mix reads and writes on stdio FILE-based ports.
	* fports.c (FPORT_READ_SAFE, FPORT_WRITE_SAFE, FPORT_ALL_OKAY):
	New macros.
	(pre_read, pre_write): New functions.
	(local_fgetc, local_fgets, local_ffwrite, local_fputc,
	local_fputs): Call them.
	(local_fflush): Mark the port as ready for reading and writing.
	(scm_stdio_to_port): Set the FPORT_READ_SAFE, FPORT_WRITE_SAFE
	flags on new port objects.  This might not be accurate --- who
	knows what state the FILE * is in when we get it --- but it won't
	do extraneous calls to fflush or fseek, so it's no worse than the
	behavior before this change.
	* ports.h: Add comment.

	Centralize the creation of port objects based on stdio FILE * in
	fports.c; don't just throw them together anywhere.
	* fports.c (scm_stdio_to_port): Make NAME a SCM value, which is
	what the rest of Guile wants.  Don't set the revealed count;
	that's only appropriate for stdin, stdout, stderr.
	(scm_standard_stream_to_port): This function does set the revealed
	count.
	* init.c (scm_init_standard_ports): Use	scm_standard_stream_to_port,
	not scm_stdio_to_port.
	* filesys.c (scm_open): Call scm_stdio_to_port; don't write it out.
	* fports.c (scm_open_file): Same.
	* posix.c (scm_pipe): Same.
	* socket.c (scm_sock_fd_to_port): Same.
	* ioext.c (scm_fdopen): Same.
	(scm_freopen): Moved from here to...
	* fports.c (scm_freopen): ... here.  This is really something that
	munges the internals of an fport, so it should go here.
	* fports.h (scm_stdio_to_port): Adjust prototype.
	(scm_standard_stream_to_port, scm_freopen): New protoypes.
	* ioext.h (scm_freopen): Prototype removed.

	* filesys.c (set_element, get_element): This can work on both pipe
	and file ports, so use SCM_FPORTP to typecheck, instead of testing
	for scm_tc16_fport.

	* scmconfig.h.in: Regenerated.

	Change the definition of the functions in scm_ptobfuns so that
	they get passed the port object, not the port's stream.
	* ports.h (scm_ptobfuns): Rename all `stream' arguments to `port'.
	* gc.c (scm_gc_sweep): Pass the port itself to the free function.
	* genio.c (scm_putc, scm_puts, scm_lfwrite, scm_fflush, scm_getc):
	Pass the port itself to the scm_ptobs function.
	* ports.c (scm_close_port, scm_force_output, scm_flush_all_ports,
	scm_generic_fgets): Same.
	(putc_void_port, puts_void_port, write_void_port, flush_void_port,
	getc_void_port, fgets_void_port, close_void_port): Just change the
	argument names; these functions don't really do anything.
	* fports.c (local_fgetc, local_fgets, local_fclose, local_fflush,
	local_fputc, local_fputs, local_ffwrite, local_pclose): Take the
	port as an argument, and use SCM_STREAM to get the stdio FILE *.
	Also, use prototyped definitions, and get rid of the extra
	declarations.
	(scm_fptob, scm_pipob): We don't need casts here any more.
	* strports.c (prinstpt): Use prototype declarations.
	(stputc, stwrite, stputs, stgetc): Take the port as an argument,
	and use SCM_STREAM to get the string info.  Also, use prototyped
	definitions, and get rid of the extra declarations.
	* vports.c (sfputc, sfwrite, sfputs, sfflush, sfgetc, sfclose,
	noop0): Same.

	* ports.h (scm_ptobfuns): Replace uses of SCM_P with a straight
	prototype; it's okay (preferred, even!) to use ANSI C in Guile.
	
	* fports.c (local_fgetc, local_fgets): Renamed from scm_fgetc and
	scm_fgets, for consistency.
	(scm_fptop, scm_pipob): References updated.