/* Quick stress test for proxy privatization. */ /* We need to use a TM method that has to enforce privatization safety explicitly. */ /* { dg-set-target-env-var ITM_DEFAULT_METHOD "ml_wt" } */ #include #include #include /* Make them likely to be mapped to different orecs. */ #define ALIGN __attribute__((aligned (256))) /* Don't make these static to work around PR 68591. */ int x ALIGN; int *ptr ALIGN; int *priv_ptr ALIGN; int priv_value ALIGN; int barrier ALIGN = 0; const int iters = 100; static void arrive_and_wait (int expected_value) { int now = __atomic_add_fetch (&barrier, 1, __ATOMIC_ACQ_REL); while (now < expected_value) __atomic_load (&barrier, &now, __ATOMIC_ACQUIRE); } static void __attribute__((transaction_pure,noinline)) delay (int i) { for (volatile int v = 0; v < i; v++); } /* This tries to catch a case in which proxy privatization safety is not ensured by privatization_user. Specifically, it's access to the value of it's transactional snapshot of ptr must read from an uncommitted write by writer; thus, writer must still be active but must have read ptr before proxy can privatize *ptr by assigning to ptr. We try to make this interleaving more likely by delaying the commit of writer and the start of proxy. */ static void *writer (void *dummy __attribute__((unused))) { for (int i = 0; i < iters; i++) { /* Initialize state in each round. */ x = 0; ptr = &x; priv_ptr = NULL; int wrote = 1; arrive_and_wait (i * 6 + 3); /* Interference by another writer. Has a conflict with the proxy privatizer. */ __transaction_atomic { if (ptr != NULL) *ptr = 1; else wrote = 0; delay (2000000); } arrive_and_wait (i * 6 + 6); /* If the previous transaction committed first, wrote == 1 and x == 1; otherwise, if the proxy came first, wrote == 0 and priv_value == 0. */ if (wrote != priv_value) abort (); } return NULL; } static void *proxy (void *dummy __attribute__((unused))) { for (int i = 0; i < iters; i++) { arrive_and_wait (i * 6 + 3); delay(1000000); __transaction_atomic { /* Hand-off to privatization-user and its read-only transaction and subsequent use of privatization. */ priv_ptr = ptr; ptr = NULL; } arrive_and_wait (i * 6 + 6); } return NULL; } static void *privatization_user (void *dummy __attribute__((unused))) { for (int i = 0; i < iters; i++) { arrive_and_wait (i * 6 + 3); /* Spin until we have gotten a pointer from the proxy. Then access the value pointed to nontransactionally. */ int *p = NULL; while (p == NULL) __transaction_atomic { p = priv_ptr; } priv_value = *p; arrive_and_wait (i * 6 + 6); } return NULL; } int main() { pthread_t p[3]; pthread_create (p+0, NULL, writer, NULL); pthread_create (p+1, NULL, proxy, NULL); pthread_create (p+2, NULL, privatization_user, NULL); for (int i = 0; i < 3; ++i) pthread_join (p[i], NULL); return 0; }