1// author: Marc Orr
2
3#include <pthread.h>
4#include <stdio.h>
5#include <stdlib.h>
6
7#define NUM_TRIES   1000
8
9// Make sure that flags and wait sit in different cache lines
10volatile int flags[10];
11volatile int wait[10];
12
13pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
14
15void *DoWork1(void *threadid)
16{
17    flags[0] = flags[0] + 1;
18    wait[0] = 0;
19    pthread_exit(0);
20}
21
22void *DoWork2(void *threadid)
23{
24    pthread_mutex_lock (&mutex);
25    flags[0] = flags[0] + 1;
26    pthread_mutex_unlock (&mutex);
27    pthread_exit(0);
28}
29
30////////////////////////////////////////////////////////////////////////////////
31// Program main
32////////////////////////////////////////////////////////////////////////////////
33int main( int argc, char** argv)
34{
35    // stuff for thread
36    pthread_t threads[1];
37
38    // initialize global variables
39    flags[0] = 0;
40    wait[0] = 1;
41
42    // monitor (via gcc intrinsic)
43    __builtin_ia32_monitor ((void *)&flags, 0, 0);
44
45    // invalidate flags in this cpu's cache
46    pthread_create(&threads[0], NULL, DoWork1, NULL);
47    while (wait[0]);
48
49    // launch thread to invalidate address being monitored
50    pthread_create(&threads[0], NULL, DoWork2, NULL);
51
52    // wait for other thread to modify flags
53    int mwait_cnt = 0;
54    do {
55        pthread_mutex_lock (&mutex);
56        if (flags[0] != 2) {
57            pthread_mutex_unlock (&mutex);
58            __builtin_ia32_mwait(0, 0);
59        } else {
60            pthread_mutex_unlock (&mutex);
61        }
62        mwait_cnt++;
63    } while (flags[0] != 2 && mwait_cnt < NUM_TRIES);
64
65    // test may hang if mwait is not working
66    if (flags[0]==2) {
67        printf("mwait regression PASSED, flags[0] = %d\n", flags[0]);
68    } else {
69        printf("mwait regression FAILED, flags[0] = %d\n", flags[0]);
70    }
71
72    return 0;
73}
74