| // author: Marc Orr |
| |
| #include <pthread.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #define NUM_TRIES 1000 |
| |
| // Make sure that flags and wait sit in different cache lines |
| volatile int flags[10]; |
| volatile int wait[10]; |
| |
| pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
| |
| void *DoWork1(void *threadid) |
| { |
| flags[0] = flags[0] + 1; |
| wait[0] = 0; |
| pthread_exit(0); |
| } |
| |
| void *DoWork2(void *threadid) |
| { |
| pthread_mutex_lock (&mutex); |
| flags[0] = flags[0] + 1; |
| pthread_mutex_unlock (&mutex); |
| pthread_exit(0); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // Program main |
| //////////////////////////////////////////////////////////////////////////////// |
| int main( int argc, char** argv) |
| { |
| // stuff for thread |
| pthread_t threads[1]; |
| |
| // initialize global variables |
| flags[0] = 0; |
| wait[0] = 1; |
| |
| // monitor (via gcc intrinsic) |
| __builtin_ia32_monitor ((void *)&flags, 0, 0); |
| |
| // invalidate flags in this cpu's cache |
| pthread_create(&threads[0], NULL, DoWork1, NULL); |
| while (wait[0]); |
| |
| // launch thread to invalidate address being monitored |
| pthread_create(&threads[0], NULL, DoWork2, NULL); |
| |
| // wait for other thread to modify flags |
| int mwait_cnt = 0; |
| do { |
| pthread_mutex_lock (&mutex); |
| if (flags[0] != 2) { |
| pthread_mutex_unlock (&mutex); |
| __builtin_ia32_mwait(0, 0); |
| } else { |
| pthread_mutex_unlock (&mutex); |
| } |
| mwait_cnt++; |
| } while (flags[0] != 2 && mwait_cnt < NUM_TRIES); |
| |
| // test may hang if mwait is not working |
| if (flags[0]==2) { |
| printf("mwait regression PASSED, flags[0] = %d\n", flags[0]); |
| } else { |
| printf("mwait regression FAILED, flags[0] = %d\n", flags[0]); |
| } |
| |
| return 0; |
| } |