Mailinglist Archive: opensuse-programming (52 mails)

< Previous Next >
Re: [suse-programming-e] The meaning of atomic in write()
  • From: Jerry Feldman <gaf@xxxxxxx>
  • Date: Sat, 1 Apr 2006 08:56:37 -0500
  • Message-id: <20060401085637.207f5076@xxxxxxxxxxx>
On Sat, 1 Apr 2006 17:33:00 +0800
Verdi March <cincaipatron@xxxxxxx> wrote:

> yep, the lesson that I learned. Initially I expect that 'atomic'
> covers both the location pointer and the 'no interleaving of bytes
> up to a certain size'. Turns out that the first is not.
>
> And the occurrance of the race condition varies among platforms.
> I used a shell script that repeatedly executes the program. The shell
> script stops until the race condition occurs. On SUSE 9.3 and FC4
> (64-bit Opteron), the race condition can occur pretty fast, while on
> SunOS it does not occur (but maybe it's because I didn't run the
> script long enough).
The location pointer should be atomic. I did not run a recent stress
test on the 2.6 kernel. One of the problems is that you used streamIO,
where the buffering is both in user space and underneath in kernel
space. The system calls, open(2), dup(2), write(2), close(2) are
atomic. And as I mentioned, they refer to the same single kernel open
file structure. But, the streamIO functions are library functions and
are not guaranteed to be atomic. There are a number of methods in Linux
to guarantee atomicity. You can use file locking, fcntl(2), flock(2),
lockf(3):

child:
flock(2) // set the lock
fprintf(3)
fflush(3)
flock(2) // release the lock
...
Parent does the same thing.

You still have a race condition as to whose data is going to be written
first, but that is an application decision.

Another way is to write your own function using the vsprintf(3)
function. I know that using a fixed size buffer here is unsafe, but I'm
using it for the example. In the function, below, by using write(2) you
are bypassing the stream's file structure (and its own location
pointer).

int myprintf(FILE *stream, const char *fmt, ...)
{
va_list lp;
va_start(lp, fmt);
int rc;
size_t wrc;
char buf[some size];
rc = vsprintf(buf, lp); /* move stuff into buf */
(check rc to make sure vsprintf succeeded)
wrc = write(fileno(stream), buf, strlen(buf));
(check wrc)
return 0;
}
--
Jerry Feldman <gaf@xxxxxxx>
Boston Linux and Unix user group
http://www.blu.org PGP key id:C5061EA9
PGP Key fingerprint:053C 73EC 3AC1 5C44 3E14 9245 FB00 3ED5 C506 1EA9
< Previous Next >
List Navigation
Follow Ups
References