Home | History | Annotate | Download | only in tests
      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 #undef PLAT_x86_darwin
     26 #undef PLAT_amd64_darwin
     27 #undef PLAT_x86_linux
     28 #undef PLAT_amd64_linux
     29 #undef PLAT_ppc32_linux
     30 #undef PLAT_ppc64_linux
     31 #undef PLAT_arm_linux
     32 #undef PLAT_arm64_linux
     33 #undef PLAT_s390x_linux
     34 #undef PLAT_mips32_linux
     35 #undef PLAT_mips64_linux
     36 #undef PLAT_x86_solaris
     37 #undef PLAT_amd64_solaris
     38 
     39 #if defined(__APPLE__) && defined(__i386__)
     40 #  define PLAT_x86_darwin 1
     41 #elif defined(__APPLE__) && defined(__x86_64__)
     42 #  define PLAT_amd64_darwin 1
     43 #elif defined(__linux__) && defined(__i386__)
     44 #  define PLAT_x86_linux 1
     45 #elif defined(__linux__) && defined(__x86_64__)
     46 #  define PLAT_amd64_linux 1
     47 #elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
     48 #  define PLAT_ppc32_linux 1
     49 #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__)
     50 #  define PLAT_ppc64_linux 1
     51 #elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__)
     52 #  define PLAT_arm_linux 1
     53 #elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__)
     54 #  define PLAT_arm64_linux 1
     55 #elif defined(__linux__) && defined(__s390x__)
     56 #  define PLAT_s390x_linux 1
     57 #elif defined(__linux__) && defined(__mips__)
     58 #if (__mips==64)
     59 #  define PLAT_mips64_linux 1
     60 #else
     61 #  define PLAT_mips32_linux 1
     62 #endif
     63 #elif defined(__sun__) && defined(__i386__)
     64 #  define PLAT_x86_solaris 1
     65 #elif defined(__sun__) && defined(__x86_64__)
     66 #  define PLAT_amd64_solaris 1
     67 #endif
     68 
     69 
     70 #if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \
     71     || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin) \
     72     || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris)
     73 #  define INC(_lval,_lqual)	     \
     74       __asm__ __volatile__ ( \
     75       "lock ; incl (%0)" : /*out*/ : /*in*/"r"(&(_lval)) : "memory", "cc" )
     76 #elif defined(PLAT_ppc32_linux) || defined(PLAT_ppc64_linux)
     77 #  define INC(_lval,_lqual)		  \
     78    __asm__ __volatile__(                  \
     79       "1:\n"                              \
     80       "        lwarx 15,0,%0\n"           \
     81       "        addi 15,15,1\n"            \
     82       "        stwcx. 15,0,%0\n"          \
     83       "        bne- 1b\n"                 \
     84       : /*out*/ : /*in*/ "b"(&(_lval))    \
     85       : /*trash*/ "r15", "cr0", "memory"  \
     86    )
     87 #elif defined(PLAT_arm_linux)
     88 #  define INC(_lval,_lqual) \
     89   __asm__ __volatile__( \
     90       "1:\n"                                 \
     91       "        ldrex r8, [%0, #0]\n"         \
     92       "        add   r8, r8, #1\n"           \
     93       "        strex r9, r8, [%0, #0]\n"     \
     94       "        cmp   r9, #0\n"               \
     95       "        bne   1b\n"                   \
     96       : /*out*/ : /*in*/ "r"(&(_lval))       \
     97       : /*trash*/ "r8", "r9", "cc", "memory" \
     98   );
     99 #elif defined(PLAT_arm64_linux)
    100 #  define INC(_lval,_lqual) \
    101   __asm__ __volatile__( \
    102       "1:\n"                                 \
    103       "        ldxr  w8, [%0, #0]\n"         \
    104       "        add   w8, w8, #1\n"           \
    105       "        stxr  w9, w8, [%0, #0]\n"     \
    106       "        cmp   w9, #0\n"               \
    107       "        bne   1b\n"                   \
    108       : /*out*/ : /*in*/ "r"(&(_lval))       \
    109       : /*trash*/ "x8", "x9", "cc", "memory" \
    110   );
    111 #elif defined(PLAT_s390x_linux)
    112 #  define INC(_lval,_lqual) \
    113    __asm__ __volatile__( \
    114       "1: l     0,%0\n"                            \
    115       "   lr    1,0\n"                             \
    116       "   ahi   1,1\n"                             \
    117       "   cs    0,1,%0\n"                          \
    118       "   jl    1b\n"                              \
    119       : "+m" (_lval) :: "cc", "0","1" \
    120    )
    121 #elif defined(PLAT_mips32_linux) || defined(PLAT_mips64_linux)
    122 #  define INC(_lval,_lqual)                         \
    123      __asm__ __volatile__ (                         \
    124       "L1xyzzy1" _lqual":\n"                        \
    125       "        move  $t0, %0\n"                     \
    126       "        ll    $t1, 0($t0)\n"                 \
    127       "        addiu $t1, $t1, 1\n"                 \
    128       "        sc    $t1, 0($t0)\n"                 \
    129       "        beqz  $t1, L1xyzzy1" _lqual          \
    130       : /*out*/ : /*in*/ "r"(&(_lval))              \
    131       : /*trash*/ "t0", "t1", "memory"              \
    132         )
    133 #else
    134 #  error "Fix Me for this platform"
    135 #endif
    136 
    137 
    138 
    139 #define LIMIT 10
    140 
    141 volatile int x = 0;
    142 
    143 void* child_fn ( void* arg )
    144 {
    145    int q = 0;
    146    int oldx = 0;
    147    struct timespec ts = { 0, 1000 * 1000 };
    148 
    149    while (1) {
    150       q = (x >= LIMIT);
    151       if (x != oldx) {
    152          oldx = x;
    153          printf("child: new value %d\n", oldx);
    154          fflush(stdout);
    155       }
    156       if (q) break;
    157       nanosleep(&ts, 0);
    158    }
    159    return NULL;
    160 }
    161 
    162 int main ( void )
    163 {
    164    pthread_t child;
    165    int i;
    166 
    167    if (pthread_create(&child, NULL, child_fn, NULL)) {
    168       perror("pthread_create");
    169       exit(1);
    170    }
    171 
    172    for (i = 0; i < LIMIT; i++) {
    173       INC(x, "main");
    174       if (i == 5) sleep(1); /* make sure child doesn't starve */
    175    }
    176 
    177    if (pthread_join(child, NULL)) {
    178       perror("pthread join");
    179       exit(1);
    180    }
    181 
    182    printf("done, x = %d\n", x);
    183 
    184    return 0;
    185 }
    186