sewardj | b411202 | 2007-11-09 22:49:28 +0000 | [diff] [blame^] | 1 | |
| 2 | /* FIXME: this is basically a bad test as it is scheduling- |
| 3 | sensitive. Sometimes the output is: |
| 4 | |
| 5 | child: new value 6 |
| 6 | child: new value 10 |
| 7 | done, x = 10 |
| 8 | |
| 9 | and sometimes |
| 10 | |
| 11 | child: new value 10 |
| 12 | done, x = 10 |
| 13 | */ |
| 14 | |
| 15 | #include <pthread.h> |
| 16 | #include <stdio.h> |
| 17 | #include <stdlib.h> |
| 18 | #include <unistd.h> |
| 19 | |
| 20 | /* Simple test program, no race. Parent writes atomically to a counter |
| 21 | whilst child reads it. When counter reaches a prearranged value, |
| 22 | child joins back to parent. Parent (writer) uses hardware bus lock; |
| 23 | child is only reading and so does not need to use a bus lock. */ |
| 24 | |
| 25 | |
| 26 | #undef PLAT_x86_linux |
| 27 | #undef PLAT_amd64_linux |
| 28 | #undef PLAT_ppc32_linux |
| 29 | #undef PLAT_ppc64_linux |
| 30 | #undef PLAT_ppc32_aix5 |
| 31 | #undef PLAT_ppc64_aix5 |
| 32 | |
| 33 | #if !defined(_AIX) && defined(__i386__) |
| 34 | # define PLAT_x86_linux 1 |
| 35 | #elif !defined(_AIX) && defined(__x86_64__) |
| 36 | # define PLAT_amd64_linux 1 |
| 37 | #elif !defined(_AIX) && defined(__powerpc__) && !defined(__powerpc64__) |
| 38 | # define PLAT_ppc32_linux 1 |
| 39 | #elif !defined(_AIX) && defined(__powerpc__) && defined(__powerpc64__) |
| 40 | # define PLAT_ppc64_linux 1 |
| 41 | #elif defined(_AIX) && defined(__64BIT__) |
| 42 | # define PLAT_ppc64_aix5 1 |
| 43 | #elif defined(_AIX) && !defined(__64BIT__) |
| 44 | # define PLAT_ppc32_aix5 1 |
| 45 | #endif |
| 46 | |
| 47 | |
| 48 | #if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) |
| 49 | # define INC(_lval) \ |
| 50 | __asm__ __volatile__ ( \ |
| 51 | "lock ; incl (%0)" : /*out*/ : /*in*/"r"(&(_lval)) : "memory", "cc" ) |
| 52 | #elif defined(PLAT_ppc32_linux) || defined(PLAT_ppc64_linux) |
| 53 | # define INC(_lval) \ |
| 54 | __asm__ __volatile__( \ |
| 55 | "1:\n" \ |
| 56 | " lwarx 15,0,%0\n" \ |
| 57 | " addi 15,15,1\n" \ |
| 58 | " stwcx. 15,0,%0\n" \ |
| 59 | " bne- 1b" \ |
| 60 | : /*out*/ : /*in*/ "b"(&(_lval)) \ |
| 61 | : /*trash*/ "r15", "cr0", "memory" \ |
| 62 | ) |
| 63 | #else |
| 64 | # error "Fix Me for this platform" |
| 65 | #endif |
| 66 | |
| 67 | |
| 68 | |
| 69 | #define LIMIT 10 |
| 70 | |
| 71 | volatile int x = 0; |
| 72 | |
| 73 | void* child_fn ( void* arg ) |
| 74 | { |
| 75 | int q = 0; |
| 76 | int oldx = 0; |
| 77 | int ctr = 0; |
| 78 | while (1) { |
| 79 | q = (x >= LIMIT); |
| 80 | if (x != oldx) { |
| 81 | oldx = x; |
| 82 | printf("child: new value %d\n", oldx); |
| 83 | fflush(stdout); |
| 84 | } |
| 85 | if (q) break; |
| 86 | /* Make sure the parent doesn't starve. Seems to be a problem |
| 87 | on very slow machines. */ |
| 88 | ctr++; |
| 89 | if (ctr == 2000000) sleep(1); |
| 90 | } |
| 91 | return NULL; |
| 92 | } |
| 93 | |
| 94 | int main ( void ) |
| 95 | { |
| 96 | pthread_t child; |
| 97 | int i; |
| 98 | |
| 99 | if (pthread_create(&child, NULL, child_fn, NULL)) { |
| 100 | perror("pthread_create"); |
| 101 | exit(1); |
| 102 | } |
| 103 | |
| 104 | for (i = 0; i < LIMIT; i++) { |
| 105 | INC(x); |
| 106 | if (i == 5) sleep(1); /* make sure child doesn't starve */ |
| 107 | } |
| 108 | |
| 109 | if (pthread_join(child, NULL)) { |
| 110 | perror("pthread join"); |
| 111 | exit(1); |
| 112 | } |
| 113 | |
| 114 | printf("done, x = %d\n", x); |
| 115 | |
| 116 | return 0; |
| 117 | } |