1/** 2 * \file 3 * \brief Barrier client API implementation 4 * 5 * Implementation of a double barrier using the get/set API. 6 */ 7 8/* 9 * Copyright (c) 2011, ETH Zurich. 10 * All rights reserved. 11 * 12 * This file is distributed under the terms in the attached LICENSE file. 13 * If you do not find this file, copies can be found by writing to: 14 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group. 15 */ 16 17#include <barrelfish/barrelfish.h> 18 19#include <if/octopus_defs.h> 20#include <if/octopus_thc.h> 21 22#include <octopus/init.h> 23#include <octopus/barrier.h> 24#include <octopus/getset.h> 25#include <octopus/trigger.h> 26 27#include "common.h" 28 29/** 30 * \brief Client enters a barrier. Blocks until all clients have entered the 31 * barrier. 32 * 33 * Each client creates a (sequential record) based on the provided name. 34 * Once a client sees the specified amount (wait_for) of records it 35 * creates a record that wakes up all waiting clients. 36 * 37 * \param[in] name Name of the barrier. 38 * \param[out] barrier_record Record created for each client. 39 * \param[in] wait_for Number of clients entering the barrier. 40 */ 41errval_t oct_barrier_enter(const char* name, char** barrier_record, size_t wait_for) 42{ 43 errval_t err; 44 errval_t exist_err; 45 char** names = NULL; 46 uint64_t mode = 0; 47 octopus_trigger_id_t tid; 48 size_t current_barriers = 0; 49 octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD, octopus_BINDING_RPC, 50 OCT_ON_SET, NULL, NULL); 51 52 err = oct_set_get(SET_SEQUENTIAL, barrier_record, 53 "%s_ { barrier: '%s' }", name, name); 54 *barrier_record = strdup(*barrier_record); 55 if (*barrier_record == NULL) { 56 return LIB_ERR_MALLOC_FAIL; 57 } 58 err = oct_get_names(&names, ¤t_barriers, "_ { barrier: '%s' }", 59 name); 60 oct_free_names(names, current_barriers); 61 if (err_is_fail(err)) { 62 return err; 63 } 64 //debug_printf("current_barriers: %lu wait_for: %lu\n", current_barriers, 65 // wait_for); 66 67 if (current_barriers != wait_for) { 68 struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); 69 err = cl->call_seq.exists(cl, name, t, &tid, &exist_err); 70 if (err_is_fail(err)) { 71 return err; 72 } 73 err = exist_err; 74 75 if (err_is_ok(err)) { 76 // Barrier already exists 77 } 78 if (err_no(err) == OCT_ERR_NO_RECORD) { 79 // Wait until barrier record is created 80 err = cl->recv.trigger(cl, NULL, NULL, &mode, NULL, NULL); 81 assert(mode & OCT_REMOVED); 82 83 err = SYS_ERR_OK; 84 } 85 else { 86 // Some other error happend, return it 87 } 88 } 89 else { 90 // We are the last to enter the barrier, 91 // wake up the others 92 err = oct_set(name); 93 } 94 95 return err; 96} 97 98/** 99 * \brief Leave a barrier. Blocks until all involved parties have 100 * called oct_barrier_leave(). 101 * 102 * Client deletes its barrier record. In case the client 103 * was the last one we delete the special record which 104 * wakes up all other clients. 105 * 106 * \param barrier_record Clients own record as provided by 107 * oct_barrier_enter. 108 */ 109errval_t oct_barrier_leave(const char* barrier_record) 110{ 111 errval_t exist_err; 112 errval_t err; 113 char* rec_name = NULL; 114 char* barrier_name = NULL; 115 char** names = NULL; 116 size_t remaining_barriers = 0; 117 uint64_t mode = 0; 118 octopus_trigger_id_t tid; 119 octopus_trigger_t t = oct_mktrigger(SYS_ERR_OK, octopus_BINDING_RPC, 120 OCT_ON_DEL, NULL, NULL); 121 122 //debug_printf("leaving: %s\n", barrier_record); 123 err = oct_read(barrier_record, "%s { barrier: %s }", &rec_name, 124 &barrier_name); 125 if (err_is_ok(err)) { 126 err = oct_del(rec_name); 127 if (err_is_fail(err)) { 128 goto out; 129 } 130 131 err = oct_get_names(&names, &remaining_barriers, "_ { barrier: '%s' }", 132 barrier_name); 133 oct_free_names(names, remaining_barriers); 134 135 //debug_printf("remaining barriers is: %lu\n", remaining_barriers); 136 137 if (err_is_ok(err)) { 138 struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); 139 err = cl->call_seq.exists(cl, barrier_name, t, &tid, &exist_err); 140 if (err_is_fail(err)) { 141 goto out; 142 } 143 err = exist_err; 144 145 if (err_is_ok(err)) { 146 // Wait until everyone has left the barrier 147 err = cl->recv.trigger(cl, NULL, NULL, &mode, NULL, NULL); 148 assert(mode & OCT_REMOVED); 149 } 150 else if (err_no(err) == OCT_ERR_NO_RECORD) { 151 // barrier already deleted 152 err = SYS_ERR_OK; 153 } 154 } 155 else if (err_no(err) == OCT_ERR_NO_RECORD) { 156 // We are the last one to leave the barrier, 157 // wake-up all others 158 err = oct_del("%s", barrier_name); 159 } 160 else { 161 // Just return the error 162 } 163 } 164 165out: 166 free(rec_name); 167 free(barrier_name); 168 return err; 169} 170