1 /* Unit tester for ring buffer code in mce.c */ 2 #define DEFINE_PER_CPU(a,b) a b 3 #define __get_cpu_var(x) x 4 #define barrier() asm volatile("" ::: "memory") 5 #define rmb() barrier() 6 #define wmb() barrier() 7 8 /* 9 * Simple lockless ring to communicate PFNs from the exception handler with the 10 * process context work function. This is vastly simplified because there's 11 * only a single reader and a single writer. 12 */ 13 #define MCE_RING_SIZE 16 /* we use one entry less */ 14 15 struct mce_ring { 16 unsigned short start; 17 unsigned short end; 18 unsigned long ring[MCE_RING_SIZE]; 19 }; 20 static DEFINE_PER_CPU(struct mce_ring, mce_ring); 21 mce_ring_empty(void)22static int mce_ring_empty(void) 23 { 24 struct mce_ring *r = &__get_cpu_var(mce_ring); 25 26 return r->start == r->end; 27 } 28 mce_ring_get(unsigned long * pfn)29static int mce_ring_get(unsigned long *pfn) 30 { 31 struct mce_ring *r = &__get_cpu_var(mce_ring); 32 33 if (r->start == r->end) 34 return 0; 35 *pfn = r->ring[r->start]; 36 r->start = (r->start + 1) % MCE_RING_SIZE; 37 return 1; 38 } 39 mce_ring_add(unsigned long pfn)40static int mce_ring_add(unsigned long pfn) 41 { 42 struct mce_ring *r = &__get_cpu_var(mce_ring); 43 unsigned next; 44 45 next = (r->end + 1) % MCE_RING_SIZE; 46 if (next == r->start) 47 return -1; 48 r->ring[r->end] = pfn; 49 wmb(); 50 r->end = next; 51 return 0; 52 } 53 54 #include <stdio.h> 55 #include <assert.h> 56 #include <pthread.h> 57 thread(void * arg)58void *thread(void *arg) 59 { 60 long i = 0; 61 for (;;) { 62 if (mce_ring_add(i) >= 0) 63 i++; 64 } 65 } 66 main(void)67int main(void) 68 { 69 long k; 70 71 pthread_t thr; 72 pthread_create(&thr, NULL, thread, NULL); 73 74 k = 0; 75 for (;;) { 76 while (!mce_ring_empty()) { 77 unsigned long pfn; 78 int r = mce_ring_get(&pfn); 79 assert(r != 0); 80 if (pfn != k) 81 printf("got %lu expected %lu delta %ld\n", pfn, k, k-pfn); 82 k++; 83 } 84 } 85 86 return 0; 87 } 88