[comp.sys.encore] File buffers

anand@cmx.npac.syr.edu (Rangachari Anand) (08/02/88)

  This is a problem that others have surely faced on multiprocessors
  such as the Multimax. Consider a program which forks a number of 
  child processes each of which need to do I/O from a given file. If the 
  fscanf and fprintf functions are used, the buffering action seems to
  load a block of the file into a buffer which is in the private memory 
  of a process. Then when other processes attempt to read from the
  same file, they load blocks of the file into their respective buffers.
  Thus they cant read the file in the correct sequence.

  I have managed to write my programs in such a way that they always use the
  same process to do all the I/O which is a nuisance. I tried to use
  the setbuff call to use a shared buffer but that did not seem to work.
  Any suggestions?


                                            Thanks
                                           R. Anand
  Internet: anand@amax.npac.syr.edu
  Bitnet:   ranand@sunrise

jeff@Alliant.COM (Jeff Collins) (08/03/88)

In article <585@cmx.npac.syr.edu> anand@cmx.npac.syr.edu (Rangachari Anand) writes:
>
>  This is a problem that others have surely faced on multiprocessors
>  such as the Multimax. Consider a program which forks a number of 
>  child processes each of which need to do I/O from a given file. If the 
>  fscanf and fprintf functions are used, the buffering action seems to
>  load a block of the file into a buffer which is in the private memory 
>  of a process. Then when other processes attempt to read from the
>  same file, they load blocks of the file into their respective buffers.
>  Thus they cant read the file in the correct sequence.

	Yes this is definately a problem.  Given the buffering syntax
of stdio, there is really no way to do what you want.  The only
suggestions that I would have would be to use read(2)/write(2)
directly (ie. eliminate the buffering).  This is fairly painfull as
you don't get the functionality of fscanf and fprintf.  Perhaps you
can do an sprintf(3) into a string, then write(2) the string to the
file.  Reading may be more difficult because you probably don't know
the length to read until after you have read it.

	The other possible alternative is to change the stdio
libraries so that the buffers use shared memory.  I wouldn't think
that this would be a trivial solution, and is probably not something
that you would want to do yourself - but it is an idea.

	Jeff Collins

jb@CS.BROWN.EDU (08/04/88)

I'm not exactly sure how things are behaving, but I'd guess that the
problem is that while the buffer was shared, the file pointer was
not shared.

To fix this problem, after you do the fopen(), copy the entire file
pointer (FILE  *) into a new copy in a block of shared memory.  Set
the buffer by patching the copied structure to be in shared memory
as well.  (Copying after the setbuf call would probably work as well.)
Use this new file pointer instead of the one returned by fopen for
all subsequent i/o.  Don't forget that this is a shared data
structure and that mutual exclusion is needed around calls to fprintf
and fscanf (or any other routines in stdio).

This hack should work, but is totally nonstandard.  It assumes some
knowledge of how stdio works and is outside what is docummented.  Use
at your own risk.

				Jim

paradis@encore.UUCP (Jim Paradis) (08/05/88)

In article <2185@alliant.Alliant.COM> jeff@alliant.UUCP (Jeff Collins) writes:
>Given the buffering syntax of stdio, there is really no way to do 
>what you want.  The only suggestions that I would have would be to 
>use read(2)/write(2) directly (ie. eliminate the buffering). 
>
>	The other possible alternative is to change the stdio
>libraries so that the buffers use shared memory.  I wouldn't think
>that this would be a trivial solution, and is probably not something
>that you would want to do yourself - but it is an idea.

Hi, Jeff!

There IS a third way... it's not pretty, but it gets the job done
without having to change the I/O libraries:

	(1) Create a region of shared memory that's at least
	BUFSIZ + sizeof(FILE) long.

	(2) After opening the file, copy the FILE object into
	the shared memory region, and refer to it ONLY by the
	shared-memory address from now on.

	(3) Use setbuf(3) to place the buffer associated with
	the FILE object into shared memory.

	(4) Put spinlocks around all of your stdio calls so
	that you don't accidentally step all over yourself.

Note, of course, that this scheme has the {feature|bug} that
this file object is COMPLETELY shared among all processes;
therefore, if one process changes the state of the object
(e.g. moves the file pointer), that change is seen by all
other processes.  Standard parallel programming practices apply;
if you change the state of the object and a future operation
depends on the state you produced (e.g. fseek followed by fread),
then you must lock the ENTIRE section of code until such time as
you no longer depend on the object having a particular state. 


-- 
Jim Paradis, Encore Computer
(.signature undergoing renovations. Please pardon our appearance.)