Messages in this thread | | | Date | Fri, 26 Nov 1999 11:34:05 +0100 (CET) | From | Ingo Molnar <> | Subject | Re: spin_unlock optimization(i386) |
| |
On Thu, 25 Nov 1999, Erich Boleyn wrote:
> > for (;;) { for (;;) { > > i++; a = i; > > j++; b = j; > > } if (a < b) > > BUG() > > } > > > > if your theory is true, then 'BUG()' should trigger sooner or later, > > correct?
> No.
(duh! it was late here, so ...)
> To make this work correctly in the face of both Processor Ordering > and pauses in the process execution, the second loop should actually say: > > for (;;) { > b = j; > a = i; > if (a < b) > BUG(); > } > > With Weak Ordering, this could fail, since you may have not gotten > all the updates to "i" yet.
yes, this was my intention. The attached code fixes this bug and now it works just fine without any causality violations with 8 threads running on 8 CPUs. (1 'creator' and 7 'observers')
(thanks for the help, this thread was/is very informative.)
-- mingo
/* * Linux SMP memory model and SMP causality tester, Ingo Molnar * * Copyright (C) 1999, Ingo Molnar <mingo@redhat.com> */
#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <sys/wait.h> #include <linux/unistd.h>
volatile static int started = 0; static int numthreads;
#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
volatile int data1 = 0, filler03[8], data2 = 0;
static int test_locking(int cpu) { int a, b, count = 0;
if (cpu < 1) { for (;;) { data1++; data2++; } } else { for (;;) { count++; b = data2; a = data1; if (a < b) { printf("<%d> %d %d\n", count, a, b); return 1; } } } }
void test_causality (int cpu) { asm volatile ("lock; incl %0":"=m"(started)); while (numthreads != started) mb();
test_locking(cpu);
printf("<thread%d> BROKE causality! Weakly ordered memory?\n", cpu); exit(0); }
static void start_thread(int cpu) { char *newstack = (char *) malloc(10000) + 5000;
*newstack = cpu; __asm__ __volatile__( "int $0x80 \n\t" /* Linux/i386 system call */ "testl %0,%0 \n\t" /* check return value */ "jne 1f \n\t" /* jump if parent */ "call *%2 \n\t" /* start subthread function */ "movl %1,%0 \n\t" "int $0x80 \n\t" /* exit system call: exit subthread */ "1: \n\t" : :"a" (__NR_clone),"i" (__NR_exit), "r" (test_causality), "b" (0xaf00 | SIGCHLD), "c" (newstack)); return; }
int main (int argc, char * * argv) { int i;
if (argc != 2) { printf("usage: causal <kids>\n"); exit(0); } numthreads = atol(argv[1]);
for (i = 0; i<numthreads; i++) { start_thread(i); } return (0); }
| |