Path: blob/main/sys/contrib/ck/src/ck_barrier_tournament.c
48266 views
/*1* Copyright 2011-2015 Samy Al Bahra.2* Copyright 2011 David Joseph.3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include <ck_barrier.h>28#include <ck_pr.h>2930#include "ck_internal.h"3132/*33* This is a tournament barrier implementation. Threads are statically34* assigned roles to perform for each round of the barrier. Winners35* move on to the next round, while losers spin in their current rounds36* on their own flags. During the last round, the champion of the tournament37* sets the last flag that begins the wakeup process.38*/3940enum {41CK_BARRIER_TOURNAMENT_BYE,42CK_BARRIER_TOURNAMENT_CHAMPION,43CK_BARRIER_TOURNAMENT_DROPOUT,44CK_BARRIER_TOURNAMENT_LOSER,45CK_BARRIER_TOURNAMENT_WINNER46};4748void49ck_barrier_tournament_subscribe(struct ck_barrier_tournament *barrier,50struct ck_barrier_tournament_state *state)51{5253state->sense = ~0;54state->vpid = ck_pr_faa_uint(&barrier->tid, 1);55return;56}5758void59ck_barrier_tournament_init(struct ck_barrier_tournament *barrier,60struct ck_barrier_tournament_round **rounds,61unsigned int nthr)62{63unsigned int i, k, size, twok, twokm1, imod2k;6465ck_pr_store_uint(&barrier->tid, 0);66barrier->size = size = ck_barrier_tournament_size(nthr);6768for (i = 0; i < nthr; ++i) {69/* The first role is always CK_BARRIER_TOURNAMENT_DROPOUT. */70rounds[i][0].flag = 0;71rounds[i][0].role = CK_BARRIER_TOURNAMENT_DROPOUT;72for (k = 1, twok = 2, twokm1 = 1; k < size; ++k, twokm1 = twok, twok <<= 1) {73rounds[i][k].flag = 0;7475imod2k = i & (twok - 1);76if (imod2k == 0) {77if ((i + twokm1 < nthr) && (twok < nthr))78rounds[i][k].role = CK_BARRIER_TOURNAMENT_WINNER;79else if (i + twokm1 >= nthr)80rounds[i][k].role = CK_BARRIER_TOURNAMENT_BYE;81}8283if (imod2k == twokm1)84rounds[i][k].role = CK_BARRIER_TOURNAMENT_LOSER;85else if ((i == 0) && (twok >= nthr))86rounds[i][k].role = CK_BARRIER_TOURNAMENT_CHAMPION;8788if (rounds[i][k].role == CK_BARRIER_TOURNAMENT_LOSER)89rounds[i][k].opponent = &rounds[i - twokm1][k].flag;90else if (rounds[i][k].role == CK_BARRIER_TOURNAMENT_WINNER ||91rounds[i][k].role == CK_BARRIER_TOURNAMENT_CHAMPION)92rounds[i][k].opponent = &rounds[i + twokm1][k].flag;93}94}9596ck_pr_store_ptr(&barrier->rounds, rounds);97return;98}99100unsigned int101ck_barrier_tournament_size(unsigned int nthr)102{103104return (ck_internal_log(ck_internal_power_2(nthr)) + 1);105}106107void108ck_barrier_tournament(struct ck_barrier_tournament *barrier,109struct ck_barrier_tournament_state *state)110{111struct ck_barrier_tournament_round **rounds = ck_pr_load_ptr(&barrier->rounds);112int round = 1;113114if (barrier->size == 1)115return;116117for (;; ++round) {118switch (rounds[state->vpid][round].role) {119case CK_BARRIER_TOURNAMENT_BYE:120break;121case CK_BARRIER_TOURNAMENT_CHAMPION:122/*123* The CK_BARRIER_TOURNAMENT_CHAMPION waits until it wins the tournament; it then124* sets the final flag before the wakeup phase of the barrier.125*/126while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense)127ck_pr_stall();128129ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense);130goto wakeup;131case CK_BARRIER_TOURNAMENT_DROPOUT:132/* NOTREACHED */133break;134case CK_BARRIER_TOURNAMENT_LOSER:135/*136* CK_BARRIER_TOURNAMENT_LOSERs set the flags of their opponents and wait until137* their opponents release them after the tournament is over.138*/139ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense);140while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense)141ck_pr_stall();142143goto wakeup;144case CK_BARRIER_TOURNAMENT_WINNER:145/*146* CK_BARRIER_TOURNAMENT_WINNERs wait until their current opponent sets their flag; they then147* continue to the next round of the tournament.148*/149while (ck_pr_load_uint(&rounds[state->vpid][round].flag) != state->sense)150ck_pr_stall();151break;152}153}154155wakeup:156for (round -= 1 ;; --round) {157switch (rounds[state->vpid][round].role) {158case CK_BARRIER_TOURNAMENT_BYE:159break;160case CK_BARRIER_TOURNAMENT_CHAMPION:161/* NOTREACHED */162break;163case CK_BARRIER_TOURNAMENT_DROPOUT:164goto leave;165break;166case CK_BARRIER_TOURNAMENT_LOSER:167/* NOTREACHED */168break;169case CK_BARRIER_TOURNAMENT_WINNER:170/*171* Winners inform their old opponents the tournament is over172* by setting their flags.173*/174ck_pr_store_uint(rounds[state->vpid][round].opponent, state->sense);175break;176}177}178179leave:180ck_pr_fence_memory();181state->sense = ~state->sense;182return;183}184185186