renaming defines
[barrelfish] / lib / octopus / client / semaphores.c
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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13  */
14
15 #include <barrelfish/barrelfish.h>
16
17 #include <octopus/init.h>
18 #include <octopus/getset.h>
19 #include <octopus/trigger.h>
20 #include <octopus/lock.h>
21 #include <octopus/semaphores.h>
22
23 #include "common.h"
24
25 static uint32_t get_next_id(void)
26 {
27     uint64_t id = 0;
28     char* lock_record = NULL;
29     char* record = NULL;
30
31     // Find a valid ID for our next semaphore
32
33     // This lock makes sure that we don't
34     // have concurrent access to sem.ids
35     errval_t err = oct_lock("sem.lock", &lock_record);
36     assert(err_is_ok(err));
37
38     err = oct_get(&record, "sem.ids { current_id: _ }");
39     if (err_is_ok(err)) {
40         err = oct_read(record, "_ { current_id: %d }", &id);
41         assert(err_is_ok(err));
42     }
43     else if (err_no(err) == OCT_ERR_NO_RECORD) {
44         err = oct_set("sem.ids { current_id: 0 }");
45         assert(err_is_ok(err));
46     }
47     else {
48         assert(!"Should not happen.");
49     }
50
51     id += 1;
52
53     err = oct_set("sem.ids { current_id: %lu }", id);
54     assert(err_is_ok(err));
55
56     err = oct_unlock(lock_record);
57     free(lock_record);
58     free(record);
59     assert(err_is_ok(err));
60
61     return id;
62 }
63
64 errval_t oct_sem_new(uint32_t* id, size_t value)
65 {
66     // Find a valid ID for our next semaphore
67     *id = get_next_id();
68     //debug_printf("oct_sem_new id is: %d\n", *id);
69
70     errval_t err = SYS_ERR_OK;
71     for (size_t i=0; i < value; i++) {
72         err = oct_sem_post(*id);
73         if (err_is_fail(err)) {
74             return err;
75         }
76     }
77
78     return err;
79 }
80
81 errval_t oct_sem_post(uint32_t id)
82 {
83     return oct_mset(SET_SEQUENTIAL, "sem.%d. { sem: %d }", id, id);
84 }
85
86 errval_t oct_sem_wait(uint32_t id)
87 {
88     errval_t err = SYS_ERR_OK;
89     char* result = NULL;
90     octopus_trigger_id_t tid;
91     octopus_trigger_t t = oct_mktrigger(OCT_ERR_NO_RECORD,
92             octopus_BINDING_RPC, OCT_ON_SET, NULL, NULL);
93     struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
94
95     char query[100];
96     snprintf(query, 99, "r'sem\\.%d\\.[0-9]+' { sem: %d }", id, id);
97
98     char lock_name[100];
99     snprintf(lock_name, 99, "sem.%d", id);
100
101     // XXX: The current implementation suffers from a herd effect,
102     // may be worth it to use locks for this critical section
103     while (1) {
104         cl->call_seq.get(cl, query, t, &result, &tid, &err);
105
106         if (err_is_ok(err)) {
107             errval_t del_err = oct_del(result);
108             free(result);
109             result = NULL;
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                 break; // Unexpected error
119             }
120         }
121         else if (err_no(err) == OCT_ERR_NO_RECORD) {
122             // No record found, wait until one is posted
123             char* trigger_result = NULL;
124             uint64_t fn, mode, state;
125             cl->recv.trigger(cl, &tid, &fn, &mode, &trigger_result, &state);
126             free(trigger_result);
127         }
128         else {
129             break; // Unexpected error
130         }
131     }
132
133     free(result);
134     return err;
135 }
136
137 errval_t oct_sem_trywait(uint32_t id)
138 {
139     errval_t err = SYS_ERR_OK;
140
141     char* result = NULL;
142
143     err = oct_get(&result, "r'sem\\.%d\\.[0-9]+' { sem: %d }", id, id);
144     if (err_is_ok(err)) {
145         err = oct_del(result);
146     }
147     else if (err_no(err) == OCT_ERR_NO_RECORD) {
148         // Return with no record error to caller
149     }
150
151     free(result);
152     return err;
153
154 }