niXforums Forum Index
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   PreferencesPreferences   Log in to check your private messagesLog in to check your private messages   Log inLog in 
·  nixdoc.net ·  man pages ·  Linux HOWTOs ·  FreeBSD Tips ·  Forums
navigation Forum index » Programming » Unix internals
perform read from shared file descriptor
Post new topic   Reply to topic Page 1 of 1 [3 Posts] View previous topic :: View next topic
Author Message
Valenti Alessandro
*nix forums beginner


Joined: 23 Feb 2006
Posts: 2

PostPosted: Wed Mar 01, 2006 10:39 am    Post subject: Re: perform read from shared file descriptor Reply with quote

In my opinion the read function should also move the file offset
"exactly" for the amount of read characters but also the Posix
specification says nothing about the required behaviour.
I know that probably no one needs to read from a shared file descriptor,
but it is interesting for me understand why some OS protects the file
offset change and why some others does not.

Many thanks to Paul for the detailed explaination of Linux model.

Bye


Paul Pluzhnikov wrote:
....
Quote:
Since there is no semaphore, the parent and child start reading at
the same offset, but then "race" in updating the file offset. This
race may result in either of the processes reading the same data
more then once, and all kinds of other nastiness.

It is somewhat surprising that both APUE and SUSv3 (AFAICT) are
silent on what exactly is supposed to happen when reading shared
file in this manner.

You can also observe [1] the same race in a single multi-threaded
process, where threads read from a *single* file descriptor.

[1] At least on Linux and Solaris 9; on Solaris 10 I got
Sum(N(threadX)) == N(file)
Back to top
Paul Pluzhnikov
*nix forums Guru


Joined: 25 Mar 2005
Posts: 512

PostPosted: Mon Feb 27, 2006 12:39 am    Post subject: Re: perform read from shared file descriptor Reply with quote

Valenti Alessandro <avalenti@unimo.it> writes:

Quote:
I'm experiencing a strange behaviour using standard unix processes.

It's only strange if you make incorrect assumptions.

Quote:
This should be, at least in my intentions, a trivial example about
"how to not use" file descriptors" by showing to my students that if
the child reads some character from a file, then the same characters
will not be read from the father and vice versa.

What this example actually shows is that for _read_ access, the
*shared* part of the descriptor (the file offset) is not
protected against simultaneous access, and so all you can really
say is that N(file) <= N(child) + N(parent) (where N is the size
of file or number of bytes that child/parent can read).

Quote:
When I start running the executable on a medium sized file
(e.g. /bin/bash), I've seen that the sum of the number of read
characters does not match the file size but it is sometimes a little
bigger on Solaris or very greater on Linux 2.4 and 2.6.

I have confirmed this (even on small files) on several versions of
Linux, Solaris, and AIX 5.1, but not on HP-UX 11.11, nor on
Solaris 10 (where N(file) == N(child) + N(parent)).

You can see this in the Linux kernel code:

linux-2.6.11.6/mm/filemap.c:

ssize_t
generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{ ...
ret = __generic_file_aio_read(&kiocb, &local_iov, 1, ppos);
... error checks ...
}

ssize_t generic_file_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{ ...
down(&inode->i_sem);
ret = __generic_file_write_nolock(file, &local_iov, 1, ppos);
up(&inode->i_sem);
... error checks ...
}

Note the absence of semaphore for the read operation.

Since there is no semaphore, the parent and child start reading at
the same offset, but then "race" in updating the file offset. This
race may result in either of the processes reading the same data
more then once, and all kinds of other nastiness.

It is somewhat surprising that both APUE and SUSv3 (AFAICT) are
silent on what exactly is supposed to happen when reading shared
file in this manner.

You can also observe [1] the same race in a single multi-threaded
process, where threads read from a *single* file descriptor.

[1] At least on Linux and Solaris 9; on Solaris 10 I got
Sum(N(threadX)) == N(file)

Cheers,
--
In order to understand recursion you must first understand recursion.
Remove /-nsp/ for email.
Back to top
Valenti Alessandro
*nix forums beginner


Joined: 23 Feb 2006
Posts: 2

PostPosted: Thu Feb 23, 2006 2:19 pm    Post subject: perform read from shared file descriptor Reply with quote

Dear all,
I'm experiencing a strange behaviour using standard unix processes. I
was working on a simple example for my students as to show them what
happens when You perform concurrent read operation from two different
processes (child and father) on a file opened before of the fork().

This should be, at least in my intentions, a trivial example about "how
to not use" file descriptors" by showing to my students that if the
child reads some character from a file, then the same characters will
not be read from the father and vice versa.
When I start running the executable on a medium sized file (e.g.
/bin/bash), I've seen that the sum of the number of read characters does
not match the file size but it is sometimes a little bigger on Solaris
or very greater on Linux 2.4 and 2.6.

Here my trivial code:

/* file: es71.c
* job: uso della fork
*/
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
char msg[256];
int fd;
int main(int argc, char **argv) {
pid_t fr; /* fork return value */
int st; /* spazio per l'exit value */
int count; /* contatore di read */
char ch; /* spazio per la read */
fd=open(argv[1],O_RDONLY);
if (fd<0) return(-1);
fr=fork();
switch (fr) {
case 0: /* figlio */
count=0;
for (;Wink {
switch (read(fd,&ch,1)) {
case 1:
count++;
break;
case 0:

snprintf(msg,sizeof(msg),"Figlio conta %d\n",count);
write(1,msg,strlen(msg));
return(4); /* exit
value del figlio */
default:

snprintf(msg,sizeof(msg),"Errore figlio");
write(1,msg,strlen(msg));
return(4); /* exit
value del figlio */
}
}
break;
case -1: /* errore, nessun nuovo processo */
snprintf(msg,sizeof(msg),"Errore in fork\n");
write(1,msg,strlen(msg));
break;
default: /* padre */
count=0;
for (;Wink {
switch (read(fd,&ch,1)) {
case 1:
count++;
break;
case 0:

snprintf(msg,sizeof(msg),"Padre conta %d\n",count);
write(1,msg,strlen(msg));
return(4); /* exit
value del figlio */
default:

snprintf(msg,sizeof(msg),"Errore padre");
write(1,msg,strlen(msg));
return(4); /* exit
value del figlio */
}
}
}
return(0);
}
/* end */

Any opinion should be appreciated.
Back to top
Google

Back to top
Display posts from previous:   
Post new topic   Reply to topic Page 1 of 1 [3 Posts] View previous topic :: View next topic
The time now is Sat Nov 22, 2008 11:27 am | All times are GMT
navigation Forum index » Programming » Unix internals
Jump to:  

Similar Topics
Topic Author Forum Replies Last Post
No new posts database Share Memory Limit (2 GB ) in a Instance is tota... sadanjan@gmail.com IBM DB2 0 Fri Jul 21, 2006 12:57 pm
No new posts Running php file everyday on scheduled time sachin PHP 1 Fri Jul 21, 2006 12:49 pm
No new posts Regarding thesaurus iso file Srikanth modules 0 Fri Jul 21, 2006 10:42 am
No new posts how can i get a file descriptor not used? mars system 0 Fri Jul 21, 2006 7:41 am
No new posts small GTK "Open file" dialog David Siroky Debian 0 Fri Jul 21, 2006 7:30 am

Teen Chat | MPAA | Home Loan | Free phpBB forum | Remortgages
Copyright © 2004-2005 DeniX Solutions SRL
 
Other DeniX Solutions sites: Unix/Linux blog |  electronics forum |  medicine forum |  science forum | 
Privacy Policy


Powered by phpBB © 2001, 2005 phpBB Group
[ Time: 0.2397s ][ Queries: 20 (0.1465s) ][ GZIP on - Debug on ]