static aligned_t consumer(void *arg) { uint64_t me; iprintf("consumer locking id(%p)\n", &id); qthread_syncvar_readFE(&me, &id); iprintf("consumer id's status became: %u\n", qthread_syncvar_status(&id)); iprintf("consumer unlocking id(%p), result is %lu\n", &id, (unsigned long)me); me++; qthread_syncvar_writeEF(&id, &me); for (uint64_t i = 0; i < iterations; ++i) { iprintf("consumer readFE on x\n"); qthread_syncvar_readFE(NULL, &x); } iprintf("thread %i exiting\n", (int)(uintptr_t)arg); return 0; }
void chpl_sync_waitEmptyAndLock(chpl_sync_aux_t *s, int32_t lineno, chpl_string filename) { PROFILE_INCR(profile_sync_waitEmptyAndLock, 1); if (blockreport) { about_to_block(lineno, filename); } chpl_sync_lock(s); while (s->is_full != 0) { chpl_sync_unlock(s); qthread_syncvar_readFE(NULL, &(s->signal_empty)); chpl_sync_lock(s); } }
static aligned_t producer(void *arg) { uint64_t me; iprintf("producer locking id(%p)\n", &id); qthread_syncvar_readFE(&me, &id); iprintf("producer unlocking id(%p), result is %lu\n", &id, (unsigned long)me); me++; qthread_syncvar_writeEF(&id, &me); for (uint64_t i = 0; i < iterations; ++i) { iprintf("producer x's status is: %s (expect empty)\n", qthread_syncvar_status(&x) ? "full" : "empty"); iprintf("producer filling x(%p)\n", &x); qthread_syncvar_writeEF_const(&x, i); } iprintf("thread %i exiting\n", (int)(uintptr_t)arg); return 0; }
// walk up the barrier -- waits for neighbor lock at each level of the tree // when both arrive the lower thread number climbs up the tree and the // higher number waits for the down walk to release. When all of the nodes arrive // Thread 0 starts the walk down (after executing functions to resync for loop // implementation). Any node that is waiting release at a level other than the // leaves, releases its subtree static void qtb_internal_up(qt_barrier_t *b, int myLock, int64_t val, int level) { /*{{{ */ // compute neighbor node at this level int mask = 1 << level; int pairedLock = myLock ^ mask; char debug = b->barrierDebug; assert(b->activeSize > 1); if (debug) { printf("on lock %d paired with %d level %d val %ld\n", myLock, pairedLock, level, (long int)val); } if (pairedLock >= b->activeSize) { // my pair is out of range don't wait for it qthread_syncvar_writeEF(&b->upLock[myLock], &dummy); qthread_syncvar_readFE(NULL, &b->downLock[myLock]); if (debug) { printf("released (no pair) lock %d level %d val %ld\n", myLock, level, (long int)val); } if (level != 0) { qtb_internal_down(b, myLock, level); // everyone is here and I have people to release } return; // done } if (pairedLock < myLock) { // I'm higher -- wait for release qthread_syncvar_writeEF(&b->upLock[myLock], &dummy); if (debug) { printf ("about to wait on lock %d paired with %d level %d val %ld\n", myLock, pairedLock, level, (long int)val); } qthread_syncvar_readFE(NULL, &b->downLock[myLock]); if (debug) { printf("released lock %d level %d val %ld\n", myLock, level, (long int)val); } if (level != 0) { qtb_internal_down(b, myLock, level); // everyone is here and I have people to release } return; // done } else { // I'm lower -- wait for pair and continue up if (debug) { printf("wait lock %d for %d level %d val %ld\n", myLock, pairedLock, level, (long int)val); } qthread_syncvar_readFE(NULL, &b->upLock[pairedLock]); if (debug) { printf("continue on %d level %d val %ld\n", myLock, level, (long int)val); } } if ((level + 1 < b->doneLevel) || (myLock != 0)) { // not done? yes qtb_internal_up(b, myLock, val, level + 1); } else { // done -- start release // myLock == 0 here -- don't need to fill either because Zero never waits on them // qthread_syncvar_writeEF(&b->upLock[myLock],&dummy); // qthread_syncvar_writeEF(&b->downLock[myLock],&dummy); if (debug) { printf("\t start down lock %d level %d \n", myLock, level); } qtb_internal_down(b, myLock, level); // everyone is here } } /*}}} */
int main(int argc, char *argv[]) { aligned_t *t[2]; uint64_t x_value; uint64_t pairs; assert(qthread_initialize() == 0); pairs = qthread_num_shepherds() * 6; CHECK_VERBOSE(); NUMARG(iterations, "ITERATIONS"); NUMARG(pairs, "PAIRS"); t[0] = calloc(pairs, sizeof(aligned_t)); t[1] = calloc(pairs, sizeof(aligned_t)); iprintf("%i threads...\n", qthread_num_shepherds()); iprintf("Initial value of x: %lu\n", (unsigned long)x.u.w); qthread_syncvar_empty(&id); qthread_syncvar_writeF_const(&id, 1); iprintf("id = 0x%lx\n", (unsigned long)id.u.w); { uint64_t tmp = 0; qthread_syncvar_readFF(&tmp, &id); assert(tmp == 1); } iprintf("x's status is: %s (want full (and nowait))\n", qthread_syncvar_status(&x) ? "full" : "empty"); assert(qthread_syncvar_status(&x) == 1); qthread_syncvar_readFE(NULL, &x); iprintf("x's status became: %s (want empty (and nowait))\n", qthread_syncvar_status(&x) ? "full" : "empty"); assert(qthread_syncvar_status(&x) == 0); for (unsigned int i = 0; i < pairs; ++i) { qthread_fork(consumer, (void *)(uintptr_t)i, &(t[0][i])); } for (unsigned int i = 0; i < pairs; ++i) { qthread_fork(producer, (void *)(uintptr_t)(i + pairs), &(t[1][i])); } for (unsigned int i = 0; i < pairs; ++i) { qthread_readFF(NULL, &(t[0][i])); qthread_readFF(NULL, &(t[1][i])); } iprintf("shouldn't be blocking on x (current status: %s)\n", qthread_syncvar_status(&x) ? "full" : "empty"); qthread_syncvar_fill(&x); iprintf("shouldn't be blocking on x (current status: %s)\n", qthread_syncvar_status(&x) ? "full" : "empty"); qthread_syncvar_readFF(&x_value, &x); assert(qthread_syncvar_status(&x) == 1); free(t[0]); free(t[1]); if (x_value == iterations - 1) { iprintf("Success! x==%lu\n", (unsigned long)x_value); return 0; } else { fprintf(stderr, "Final value of x=%lu, expected %lu\n", (unsigned long)x_value, (unsigned long)(iterations - 1)); return -1; } }