On Wed, 19 Dec 2007, Bruce Evans wrote:

On Wed, 19 Dec 2007, Warner Losh wrote:

imp         2007-12-19 04:30:11 UTC

 FreeBSD src repository

 Modified files:
   lib/libc/stdtime     localtime.c
 Log:
 Reduce lock contention for simple cases.

# this really should be done with pthread_once, but I've debugged this code.

 Reviewed by: arch@

Reviewers weren't happy with this.  I now think that the only bug in
it is that it unnecesarily depends i386 memory semantics (that writes
are not reordered).  There should be a write barrier before the flag
is set, to ensure that the writes which initialize things occur before
the write that sets the flag.

it also depends on the compiler not reordering writes.  But gcc does,
and I think is permitted to, reorder writes:

%%%
int x;
int y;

main()
{
        x = 1;
        y = 2;
        x = 3;
}
%%%

compiles to:

%%%
        .file   "z.c"
        .text
        .p2align 2,,3
.globl main
        .type   main, @function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        andl    $-16, %esp
        movl    $2, y
        movl    $3, x
        leave
        ret
        .size   main, .-main
        .comm   x,4,4
        .comm   y,4,4
        .ident  "GCC: (GNU) 3.3.3 [FreeBSD] 20031106"
%%%

Moving the first assignment to x to after the assignment to y and then
optimizing away the first assigment are is permitted since neither x
nor y is volatile and their are no function calls that might access x
or y.  It is done since it is easy to see that it is valid -- there
are obviously no function calls and no pointers to cause aliasing
problems.  C has a rule that writes that the program must operate
as if writes are done at sequence points, and there is a sequence
point on every semicolon in the above, so it takes some analysis
to see that the transformation is valid.  Writes may be reordered
even across function calls, but usually aren't because the function
is not visible or the analysis is too hard.

Signal handlers also cannot access x or y, especially to read
them and act on their value, since signal handlers are only permitted
to assign (write) to variables of type sig_atomic_t.

Similarly if x is only assigned to once.  The same things that permit
removing the first of the 2 assignments to x in the above permit
doing the assignments in any order.

With normal locking, this problem is handled magically by the implicit
write barrier in mutex unlock.  The write barrier first causes all
writes to be flushed in some order.  With i386 memory semantics, this
order is the same as the compiler decided to use, which may be quite
different from the program order, but any differences don't matter
because the rendevous at the lock prevents anything else looking at
any of the variables until they have all been written.  Then the lock
is released, and the write order doesn't matter because everything has
been written before anything looks at the variables.

Bruce
_______________________________________________
cvs-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/cvs-all
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to