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