lkml.org 
[lkml]   [1999]   [Nov]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: 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);
}

\
 
 \ /
  Last update: 2005-03-22 13:55    [W:0.107 / U:0.244 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site