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