SMP barrier is reusable
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 8 Apr 2009 22:58:02 +0000 (15:58 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 8 Apr 2009 22:58:02 +0000 (15:58 -0700)
can now be called multiple times (resets itself) after having been
initialized.  also renamed to barrier_all.

kern/atomic.c
kern/atomic.h
kern/testing.c

index 59f0bf3..c376380 100644 (file)
@@ -2,27 +2,37 @@
 #include <kern/apic.h>
 
 // byte per cpu, as mentioned below
-void init_barrier(barrier_t cpu_array)
+void init_barrier_all(barrier_t* cpu_barrier)
 {
        extern uint8_t num_cpus;
        uint8_t i;
+       cpu_barrier->ready = 0;
        for(i = 0; i < num_cpus; i++)
-               cpu_array[i] = 1;
+               cpu_barrier->cpu_array[i] = 1;
 }
 
 // primitive barrier function.  all cores call this.
-// should change this to use bits and lock bit ops.
+// consider changing this to use bits and lock bit ops.
 // currently uses a byte per core, and assumes it was 
-// initialized by a core such that up num_cpus entries
+// initialized by a core such that num_cpus entries
 // are all 1
-void barrier(barrier_t cpu_array)
+void barrier_all(barrier_t* cpu_barrier)
 {
        extern uint8_t num_cpus;
        uint8_t i;
+       uint8_t local_ready = cpu_barrier->ready;
 
-       cpu_array[lapic_get_id()] = 0;
-       for(i = 0; i < num_cpus; i++) {
-               while(cpu_array[i]) 
+       cpu_barrier->cpu_array[lapic_get_id()] = 0;
+       if (lapic_get_id())
+               while(cpu_barrier->ready == local_ready)
                        cpu_relax();
+       else {
+               for(i = 0; i < num_cpus; i++) {
+                       while(cpu_barrier->cpu_array[i]) 
+                               cpu_relax();
+                       cpu_barrier->cpu_array[i] = 1;
+               }
+               // if we need to wmb(), it'll be here
+               cpu_barrier->ready++;
        }
 }
index 61472bd..5ec0206 100644 (file)
@@ -21,9 +21,13 @@ static inline void atomic_inc(volatile uint32_t* number);
 static inline void atomic_dec(volatile uint32_t* number);
 
 
-typedef volatile uint8_t barrier_t[MAX_NUM_CPUS];
-void init_barrier(barrier_t COUNT(MAX_NUM_CPUS) cpu_array);
-void barrier(barrier_t COUNT(MAX_NUM_CPUS) cpu_array);
+typedef struct barrier {
+       volatile uint8_t COUNT(MAX_NUM_CPUS) cpu_array[MAX_NUM_CPUS]; 
+    volatile uint8_t ready;
+       } barrier_t;
+
+void init_barrier_all(barrier_t* cpu_barrier);
+void barrier_all(barrier_t* cpu_barrier);
 
 static inline void spin_lock(volatile uint32_t* lock)
 {
index e6f8d5c..1e57fb3 100644 (file)
@@ -98,7 +98,7 @@ barrier_t test_cpu_array;
 void test_barrier(void)
 {
        cprintf("Core 0 initializing barrier\n");
-       init_barrier(test_cpu_array);
+       init_barrier_all(&test_cpu_array);
        cprintf("Core 0 asking all cores to print ids, barrier, rinse, repeat\n");
        all_cores_call(smp_barrier_test_handler, 0);
 }
@@ -147,11 +147,16 @@ void smp_print_info_handler(struct Trapframe *tf)
 void smp_barrier_test_handler(struct Trapframe *tf)
 {
        cprintf("Round 1: Core %d\n", lapic_get_id());
-       barrier(test_cpu_array);
+       barrier_all(&test_cpu_array);
+       barrier_all(&test_cpu_array);
+       barrier_all(&test_cpu_array);
+       barrier_all(&test_cpu_array);
+       barrier_all(&test_cpu_array);
+       barrier_all(&test_cpu_array);
        cprintf("Round 2: Core %d\n", lapic_get_id());
-       // note that if we barrier again, we'll need to reinit it first
-       // uncomment these two to see the barrier not work
-       //barrier(test_cpu_array);
-       //cprintf("Round 3: Core %d\n", lapic_get_id());
+       barrier_all(&test_cpu_array);
+       cprintf("Round 3: Core %d\n", lapic_get_id());
+       // uncomment to see it fucked up
+       //cprintf("Round 4: Core %d\n", lapic_get_id());
 }