#include #include #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif /* memory barriers (for newer x86 and x86_64) */ #define mb() asm volatile ("mfence" ::: "memory") #define rmb() asm volatile ("lfence" ::: "memory") #define wmb() asm volatile ("sfence" ::: "memory") pthread_mutexattr_t fast_mutexattr; typedef struct os_event_struct os_event_struct_t; typedef os_event_struct_t* os_event_t; struct os_event_struct { pthread_mutex_t os_mutex; unsigned long is_set; unsigned long signal_count; pthread_cond_t cond_var; }; os_event_t event; unsigned long ut_delay( unsigned long delay ); void os_event_reset(); void os_event_wait(); void os_event_set(); /*=============================*/ void os_event_mutex_enter(); void os_event_mutex_exit(); /*=============================*/ unsigned long ut_rnd_ulint_counter = 65654363; #define UT_RND1 151117737 #define UT_RND2 119785373 unsigned long ut_always_false = FALSE; volatile unsigned long lock_word; unsigned long lock_counter; unsigned long some_wait; int thread_main(int thread_num); int main( int argc, char *argv[] ) { int t_num; pthread_t thread[2]; unsigned long old_counter; some_wait = 100; /* lock holding period */ /* init event */ pthread_mutexattr_init(&fast_mutexattr); pthread_mutexattr_settype(&fast_mutexattr, PTHREAD_MUTEX_ADAPTIVE_NP); event = (os_event_t) malloc(sizeof(struct os_event_struct)); pthread_mutex_init(&(event->os_mutex), &fast_mutexattr); pthread_cond_init(&(event->cond_var), NULL); event->is_set = FALSE; event->signal_count = 0; /* init flags */ lock_word = 0; lock_counter = 0; old_counter = lock_counter; /* exec thread */ for (t_num=0; t_num < 2; t_num++) { pthread_create( &thread[t_num], NULL, (void *)thread_main, (void *)t_num ); } while(1) { printf("counter: %d\n", lock_counter); old_counter = lock_counter; sleep(5); if (lock_counter == old_counter) { printf("counter: %d\n", lock_counter); printf("signals: %d\n", event->signal_count); printf("freezed..\n"); exit(1); } } } int thread_main( int thread_num ) { unsigned long from_word, to_word; unsigned long rnd, i; switch(thread_num) { case 0: /* thread_num == 0 */ from_word = 0; to_word = 1; break; default: /* thread_num == 1*/ from_word = 1; to_word = 0; } while(1) { loop: i = 0; mb(); /* by way of precaution against memory ordering */ while (lock_word != from_word && i < 20) { rnd = (ut_rnd_ulint_counter = UT_RND1 * ut_rnd_ulint_counter + UT_RND2) % 6; ut_delay(rnd); i++; mb(); /* by way of precaution against memory ordering */ } mb(); /* by way of precaution against memory ordering */ if (lock_word == from_word) { /* succcess */ lock_counter++; /* exec something... */ ut_delay(some_wait); /* unlock */ lock_word = to_word; os_event_set(); continue; } os_event_reset(); /*=============================*/ os_event_mutex_enter(); /*=============================*/ mb(); /* by way of precaution against memory ordering */ if (lock_word == from_word) { /*=====================*/ os_event_mutex_exit(); /*=====================*/ /* succcess */ lock_counter++; /* exec something... */ ut_delay(some_wait); /* unlock */ lock_word = to_word; os_event_set(); continue; } else { /* failure */ os_event_wait(); goto loop; } } } void os_event_reset() { pthread_mutex_lock(&(event->os_mutex)); if (!event->is_set) { /* Do nothing */ } else { event->is_set = FALSE; } pthread_mutex_unlock(&(event->os_mutex)); } void os_event_wait() { unsigned long old_signal_count; /*==============================================*/ /* we should lock before (os_event_mutex_enter) */ /* pthread_mutex_lock(&(event->os_mutex)); */ /*==============================================*/ old_signal_count = event->signal_count; for (;;) { if (event->is_set == TRUE || event->signal_count != old_signal_count) { pthread_mutex_unlock(&(event->os_mutex)); /* Ok, we may return */ return; } pthread_cond_wait(&(event->cond_var), &(event->os_mutex)); } } void os_event_set() { pthread_mutex_lock(&(event->os_mutex)); if (event->is_set) { /* Do nothing */ } else { event->is_set = TRUE; event->signal_count += 1; pthread_cond_broadcast(&(event->cond_var)); } pthread_mutex_unlock(&(event->os_mutex)); } void os_event_mutex_enter() { pthread_mutex_lock(&(event->os_mutex)); } void os_event_mutex_exit() { pthread_mutex_unlock(&(event->os_mutex)); } unsigned long ut_delay( unsigned long delay ) { unsigned long i,j; j = 0; for (i = 0; i < delay * 50; i++) { j += i; } if (ut_always_false) { ut_always_false = j; } return(j); }