This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Thread-, Signal- and Cancellation-safety documentation


On Jun  1, 2013, Alexandre Oliva <aoliva@redhat.com> wrote:

> What must not happen is for mem synch primitives, called by users, to
> fail to propagate effects of posix API calls executed locally to be
> published to global memory, and make effects of API calls executed in
> other threads before their latest mem synch primitives visible to the
> local thread.  Other than that, all bets are off.

Now, bringing that back to the topic that matters to the project I'm on,
and trying to show that the guarantees you're looking for are not
given by posix, consider this:

char a, b; // globals
int pipefd[2]; // the two ends of a pipe internal to this process

thread1 {
  a = 42;
  b = 6 * 9;
  write (pipefd[1], &b, 1);
}

thread2 {
  read (pipefd[0], &a, 1);
  printf ("%i\n", a);
}


Now, obviously there's a happens-before relationship between the write
and the read, right?  However, since neither read nor write are memory
synchronization operations, nothing in posix guarantees that the write
to a in thread1 won't prevail over the write to a implied by the read
call in thread2: in the absence of a memory sync operation, it is a data
race, that invokes undefined behavior, even when there's an obvious
happens-before.

Now, both read and write are thread safe, so it follows that being
thread safe doesn't offer ordering guarantees, not even when a
happens-before is present!

How could this be possible?  Well, precisely because the internal
implementation of the read and write calls could use internal mechanisms
that, in spite of flushing the data in the write buffer all the way to
the read buffer in another thread, does not guarantee that any other
data is flushed.

Now, using streams rather than file descriptors would not make any
difference as far as ordering guarantees are concerned: in spite of the
obvious happens-before, no memory synchronization is guaranteed.
Indeed, nothing in posix precludes the FILE* to be fake pointers used
just as identifiers, or pointers to memory accessible only to the
kernel, as long as the stream manipulating interfaces behave as
specified; they could all be atomic system calls, or they could use any
form of magic (or sufficiently advanced technology ;-) to implement
behavior that meets the specification while ensuring consistency of the
internal data structures even in the presence of concurrent calls.

Even the availability of explicit stream locking (flockfile) does not
bring memory synchronization with it, so in spite of mutual exclusion,
ordering is not guaranteed.  I don't see any requirement that would
render non-compliant an implementation of stream write operations that,
given multiple writes within a flockfile/funlockfile pair, queued them
up in memory local to the thread, getting them all ordered and written
out at subsequent explicit mem sync calls, or implicitly.

Any evidence that this is not so?

-- 
Alexandre Oliva, freedom fighter    http://FSFLA.org/~lxoliva/
You must be the change you wish to see in the world. -- Gandhi
Be Free! -- http://FSFLA.org/   FSF Latin America board member
Free Software Evangelist      Red Hat Brazil Compiler Engineer


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