bool ck_bag_member_spmc(struct ck_bag *bag, void *entry) { struct ck_bag_block *cursor; uint16_t block_index, n_entries; if (bag->head == NULL) return NULL; cursor = ck_pr_load_ptr(&bag->head); while (cursor != NULL) { n_entries = ck_bag_block_count(cursor); for (block_index = 0; block_index < n_entries; block_index++) { if (ck_pr_load_ptr(&cursor->array[block_index]) == entry) return true; } cursor = ck_bag_block_next(ck_pr_load_ptr(&cursor->next)); } return false; }
ph_thread_t *ph_thread_spawn(ph_thread_func func, void *arg) { ph_thread_t *thr = NULL; struct ph_thread_boot_data data; pthread_t pt; ck_backoff_t backoff = CK_BACKOFF_INITIALIZER; data.thr = &thr; data.func = func; data.arg = arg; if (pthread_create(&pt, NULL, ph_thread_boot, &data)) { return NULL; } // semi busy wait for the TLS to be set up ck_pr_fence_load(); while (ck_pr_load_ptr(&thr) == 0) { ck_backoff_eb(&backoff); ck_pr_fence_load(); } return ck_pr_load_ptr(&thr); }
static void *ph_thread_boot(void *arg) { struct ph_thread_boot_data data; ph_thread_t *me; void *retval; /* copy in the boot data from the stack of our creator */ memcpy(&data, arg, sizeof(data)); me = ph_thread_init_myself(true); /* this publishes that we're ready to run to * the thread that spawned us */ ck_pr_store_ptr(data.thr, ck_pr_load_ptr(&me)); ck_pr_fence_store(); retval = data.func(data.arg); ck_epoch_barrier(&me->epoch_record); return retval; }
void ck_barrier_tournament(struct ck_barrier_tournament *barrier, struct ck_barrier_tournament_state *state) { struct ck_barrier_tournament_round **rounds = ck_pr_load_ptr(&barrier->rounds); int round = 1; for (;; ++round) { switch (rounds[state->vpid][round].role) { // MIGHT NEED TO USE CK_PR_LOAD*** case CK_BARRIER_TOURNAMENT_BYE: break; case CK_BARRIER_TOURNAMENT_CHAMPION: /* * The CK_BARRIER_TOURNAMENT_CHAMPION waits until it wins the tournament; it then * sets the final flag before the wakeup phase of the barrier. */ while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense) ck_pr_stall(); ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense); goto wakeup; case CK_BARRIER_TOURNAMENT_DROPOUT: /* NOTREACHED */ break; case CK_BARRIER_TOURNAMENT_LOSER: /* * CK_BARRIER_TOURNAMENT_LOSERs set the flags of their opponents and wait until * their opponents release them after the tournament is over. */ ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense); while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense) ck_pr_stall(); goto wakeup; case CK_BARRIER_TOURNAMENT_WINNER: /* * CK_BARRIER_TOURNAMENT_WINNERs wait until their current opponent sets their flag; they then * continue to the next round of the tournament. */ while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense) ck_pr_stall(); break; } } wakeup: for (round -= 1 ;; --round) { switch (rounds[state->vpid][round].role) { // MIGHT NEED TO USE CK_PR_LOAD*** case CK_BARRIER_TOURNAMENT_BYE: break; case CK_BARRIER_TOURNAMENT_CHAMPION: /* NOTREACHED */ break; case CK_BARRIER_TOURNAMENT_DROPOUT: goto leave; break; case CK_BARRIER_TOURNAMENT_LOSER: /* NOTREACHED */ break; case CK_BARRIER_TOURNAMENT_WINNER: /* * Winners inform their old opponents the tournament is over * by setting their flags. */ ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense); break; } } leave: state->sense = ~state->sense; return; }