9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* [9fans] Why does pread(2) modify the channel offset?
@ 2015-06-21 10:44 Anthony Martin
  2015-06-21 12:35 ` Charles Forsyth
  0 siblings, 1 reply; 2+ messages in thread
From: Anthony Martin @ 2015-06-21 10:44 UTC (permalink / raw)
  To: 9fans

[-- Attachment #1: Type: text/plain, Size: 2160 bytes --]

During the investigation of a failure in the Go test suite,
I was led to the following question:

  Why does pread(2) modify the channel offset?

When pread and pwrite were added to the kernel in Feb 2001,
neither of them modified the underlying channel offset for
a given file descriptor. This was also the behavior when the
4th Edition was released. Fast forward to a year later in
May 2003. The code was reorganized slightly and pread began
modifying the channel offset.

I think this change was inadvertent because pwrite remained
the same (i.e. not modifying the offset) and because it means
that you can't mix calls to read and pread on the same file
descriptor without confusion. Mixing calls is very uncommon,
though, so nobody noticed at the time. A new test was added
to the Go test suite that does this and it instantly caused
the Plan 9 builder to fail.

I've attached a small program that shows the problem. It's
output looks like this:

  % 8c -FTVw test.c && 8l -o test test.c
  % ./test
  0: init       -> offset = 0
  1: write 1    -> offset = 1
  2: pwrite 1 0 -> offset = 1
  3: seek 0     -> offset = 0
  4: read 1     -> offset = 1
  5: pread 1 0  -> offset = 2
  %

The pread in step five clearly affects the file offset.

However, the documentation gives the impression that both
pread and pwrite should update the channel offset. Note the
first sentence in the following passage from pread(2):

  Pread and Pwrite are equivalent to a seek(2) to offset fol-
  lowed by a read or write.  By combining the operations in a
  single atomic call, they more closely match the 9P protocol
  (see intro(5)) and, more important, permit multiprocess pro-
  grams to execute multiple concurrent read and write opera-
  tions on the same file descriptor without interference.

That leaves us with two options:

  1. the docs are correct and pwrite is wrong, or

  2. the docs are incorrect and pread is wrong.

I think the latter is more likely. (Note, also, that all of
the modern Unix variants have APIs that assume the offset
is unchanged after a pread or pwrite).

Thoughts?

  Anthony

[-- Attachment #2: test.c --]
[-- Type: text/plain, Size: 994 bytes --]

#include <u.h>
#include <libc.h>

void
run(int step, int fd)
{
	vlong ret, off;
	char buf[1], *msg;

	msg = nil;
	switch(step){
	case 0:
		ret = 0;
		msg = "init";
		break;
	case 1:
		ret = write(fd, buf, 1);
		msg = "write 1";
		break;
	case 2:
		ret = pwrite(fd, buf, 1, 0);
		msg = "pwrite 1 0";
		break;
	case 3:
		ret = seek(fd, 0, 0);
		msg = "seek 0";
		break;
	case 4:
		ret = read(fd, buf, 1);
		msg = "read 1";
		break;
	case 5:
		ret = pread(fd, buf, 1, 0);
		msg = "pread 1 0";
		break;
	}
	if(ret == -1)
		sysfatal("%s failed: %r", msg);
	off = seek(fd, 0, 1);
	if(off < 0)
		sysfatal("seek failed: %r");
	print("%d: %-10s -> offset = %lld\n", step, msg, off);
}

char *tmpfile = "/tmp/foo.6e907b64";

void
main(void)
{
	int fd, i;

	if((fd = create(tmpfile, ORDWR, 0600)) < 0)
		sysfatal("create failed: %r");
	for(i = 0; i <= 5; i++)
		run(i, fd);
	close(fd);
	if(remove(tmpfile) < 0)
		sysfatal("remove failed: %r");
}

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [9fans] Why does pread(2) modify the channel offset?
  2015-06-21 10:44 [9fans] Why does pread(2) modify the channel offset? Anthony Martin
@ 2015-06-21 12:35 ` Charles Forsyth
  0 siblings, 0 replies; 2+ messages in thread
From: Charles Forsyth @ 2015-06-21 12:35 UTC (permalink / raw)
  To: Fans of the OS Plan 9 from Bell Labs

[-- Attachment #1: Type: text/plain, Size: 383 bytes --]

On 21 June 2015 at 11:44, Anthony Martin <ality@pbrane.org> wrote:

> Thoughts?


As with programming language specifications, when it says "equivalent" it
is ignoring any subtle differences.

Neither call is supposed to change the offset, although it wasn't noticed
for the reason you gave.
One exception is reading directories, where pread should act the same as
read.

[-- Attachment #2: Type: text/html, Size: 766 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2015-06-21 12:35 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-21 10:44 [9fans] Why does pread(2) modify the channel offset? Anthony Martin
2015-06-21 12:35 ` Charles Forsyth

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).