Messages in this thread | | | Date | Fri, 26 Nov 1999 20:21:11 +0100 (CET) | From | Ingo Molnar <> | Subject | Re: spin_unlock optimization(i386) |
| |
> > if you want to trigger the bug, then you must _both_ read and write data > > from one cpu. If one cpu writes data, and one cpu reads data, then > > you'll never trigger the problem. > > yep, thats another type of causality violation, will try to generate a > testcase. [i think i have one, i'm checking it now]
ok, the attached causal.c generates (the i believe simplest) such a testcase. It's the basic causality test done on two CPUs, where both CPUs are observers and 'creators' as well. Run it with:
./causal 0 2
to get the causality violation. [to speed up the triggering of a violation on a >2CPU box, run it twice]
'./causal 1 2' does the stores via LOCK-ed instructions and i have not managed to trigger the violation.
-- 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; int lock = 0;
#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory") #define inc(x) __asm__ __volatile__ ("incl %0": "=m"(x): :"memory") #define lock_inc(x) __asm__ __volatile__ ("lock; incl %0": "=m"(x): :"memory")
volatile int data1 = 0, data2 = 0; volatile int data3 = 0, data4 = 0;
static int test_locking(int cpu) { int a, b, i = 0;
switch (cpu) { case 0: for (;;) { i++; if (lock) { lock_inc(data3); lock_inc(data4); } else { inc(data3); inc(data4); } if (i > 1000000000) { data4 = 0; data3 = 0; i = 0; } b = data2; a = data1; if (a < b) { printf("<%d> %d %d\n", i, a, b); return 1; } } case 1: for (;;) { i++; if (lock) { lock_inc(data1); lock_inc(data2); } else { inc(data1); inc(data2); } if (i > 1000000000) { data2 = 0; data1 = 0; i = 0; } b = data4; a = data3; if (a < b) { printf("<%d> %d %d\n", i, a, b); return 1; } } default: 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 != 3) { printf("usage: causal <LOCK:0/1> <kids:3-8>\n"); exit(0); } lock = atol(argv[1]); numthreads = atol(argv[2]);
for (i = 0; i < numthreads; i++) { start_thread(i); } return (0); }
| |