1/** 2 * \file 3 * \brief Semaphore API Implementation 4 */ 5 6/* 7 * Copyright (c) 2011, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <barrelfish/barrelfish.h> 16 17#include <if/octopus_defs.h> 18#include <if/octopus_thc.h> 19 20#include <octopus/init.h> 21#include <octopus/getset.h> 22#include <octopus/trigger.h> 23#include <octopus/lock.h> 24#include <octopus/semaphores.h> 25 26#include "common.h" 27 28static uint32_t get_next_id(void) 29{ 30 uint64_t id = 0; 31 char* lock_record = NULL; 32 char* record = NULL; 33 34 // Find a valid ID for our next semaphore 35 36 // This lock makes sure that we don't 37 // have concurrent access to sem.ids 38 errval_t err = oct_lock("sem.lock", &lock_record); 39 assert(err_is_ok(err)); 40 41 err = oct_get(&record, "sem.ids { current_id: _ }"); 42 if (err_is_ok(err)) { 43 err = oct_read(record, "_ { current_id: %d }", &id); 44 assert(err_is_ok(err)); 45 } 46 else if (err_no(err) == OCT_ERR_NO_RECORD) { 47 err = oct_set("sem.ids { current_id: 0 }"); 48 assert(err_is_ok(err)); 49 } 50 else { 51 assert(!"Should not happen."); 52 } 53 54 id += 1; 55 56 err = oct_set("sem.ids { current_id: %lu }", id); 57 assert(err_is_ok(err)); 58 59 err = oct_unlock(lock_record); 60 free(lock_record); 61 free(record); 62 assert(err_is_ok(err)); 63 64 return id; 65} 66 67errval_t oct_sem_new(uint32_t* id, size_t value) 68{ 69 // Find a valid ID for our next semaphore 70 *id = get_next_id(); 71 //debug_printf("oct_sem_new id is: %d\n", *id); 72 73 errval_t err = SYS_ERR_OK; 74 for (size_t i=0; i < value; i++) { 75 err = oct_sem_post(*id); 76 if (err_is_fail(err)) { 77 return err; 78 } 79 } 80 81 return err; 82} 83 84errval_t oct_sem_post(uint32_t id) 85{ 86 return oct_mset(SET_SEQUENTIAL, "sem.%"PRIu32". { sem: %"PRIu32" }", id, id); 87} 88 89errval_t oct_sem_wait(uint32_t id) 90{ 91 errval_t err = SYS_ERR_OK; 92 octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD, 93 octopus_BINDING_RPC, OCT_ON_SET, NULL, NULL); 94 struct octopus_thc_client_binding_t* cl = oct_get_thc_client(); 95 96 char query[100]; 97 snprintf(query, 99, "r'sem\\.%"PRIu32"\\.[0-9]+' { sem: %"PRIu32" }", id, id); 98 99 char lock_name[100]; 100 snprintf(lock_name, 99, "sem.%"PRIu32"", id); 101 102 // XXX: The current implementation suffers from a herd effect, 103 // may be worth it to use locks for this critical section 104 while (1) { 105 struct octopus_get_response__rx_args reply; 106 cl->call_seq.get(cl, query, t, reply.output, &reply.tid, &err); 107 108 if (err_is_ok(err)) { 109 errval_t del_err = oct_del(reply.output); 110 111 if (err_is_ok(del_err)) { 112 break; // Decreased successfully 113 } 114 else if (err_no(del_err) == OCT_ERR_NO_RECORD) { 115 continue; // Need to start over 116 } 117 else { 118 err = del_err; 119 break; // Unexpected error 120 } 121 } 122 else if (err_no(err) == OCT_ERR_NO_RECORD) { 123 // No record found, wait until one is posted 124 cl->recv.trigger(cl, NULL, NULL, NULL, NULL, NULL); 125 } 126 else { 127 break; // Unexpected error 128 } 129 } 130 131 return err; 132} 133 134errval_t oct_sem_trywait(uint32_t id) 135{ 136 errval_t err = SYS_ERR_OK; 137 138 char* result = NULL; 139 140 err = oct_get(&result, "r'sem\\.%d\\.[0-9]+' { sem: %d }", id, id); 141 if (err_is_ok(err)) { 142 err = oct_del(result); 143 } 144 else if (err_no(err) == OCT_ERR_NO_RECORD) { 145 // Return with no record error to caller 146 } 147 148 free(result); 149 return err; 150 151} 152