renaming defines
[barrelfish] / lib / octopus / client / locking.c
1 /**
2  * \file
3  * \brief Implementation of a synchronous locking API using the octopus Interface.
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 #include <barrelfish/threads.h>
17
18 #include <octopus/init.h>
19 #include <octopus/lock.h>
20 #include <octopus/getset.h>
21 #include <octopus/trigger.h>
22
23 #include "common.h"
24
25 /**
26  * \brief Synchronous locking function.
27  *
28  * The lock function will create a new record based on the lock name
29  * using sequential set mode. This means we create a queue of records
30  * with all parties that want to acquire the lock. The lock owner
31  * is the one with the lowest sequence appended to its name.
32  * Once the lock owner deletes its lock_record the next client in
33  * the queue is notified through triggers.
34  *
35  * \note Once a client holds the lock it can be released using oct_unlock.
36  *
37  * \param[in] lock_name Name to identify the lock.
38  * \param[out] lock_record Your current lock record in the queue.
39  * Client needs to free this.
40  */
41 errval_t oct_lock(const char* lock_name, char** lock_record)
42 {
43     assert(lock_name != NULL);
44
45     errval_t err = SYS_ERR_OK;
46     errval_t exist_err;
47     char** names = NULL;
48     char* record = NULL;
49     char* name = NULL;
50     size_t len = 0;
51     size_t i = 0;
52     bool found = false;
53     uint64_t mode = 0;
54     uint64_t state = 0;
55     uint64_t fn = 0;
56     octopus_trigger_id_t tid;
57     octopus_trigger_t t = oct_mktrigger(SYS_ERR_OK, OCT_ON_DEL,
58             octopus_BINDING_RPC, NULL, NULL);
59
60     err = oct_set_get(SET_SEQUENTIAL, lock_record, "%s_ { lock: '%s' }",
61             lock_name, lock_name);
62     if (err_is_fail(err)) {
63         goto out;
64     }
65     err = oct_read(*lock_record, "%s", &name);
66     if (err_is_fail(err)) {
67         goto out;
68     }
69
70     while (true) {
71         err = oct_get_names(&names, &len, "_ { lock: '%s' }", lock_name);
72         if (err_is_fail(err)) {
73             goto out;
74         }
75
76         //debug_printf("lock queue:\n");
77         found = false;
78         for (i=0; i < len; i++) {
79             //debug_printf("%s\n", names[i]);
80             if (strcmp(names[i], name) == 0) {
81                 found = true;
82                 break;
83             }
84         }
85         assert(found);
86
87         if (i == 0) {
88             // We are the lock owner
89             goto out;
90         }
91         else {
92             // Someone else holds the lock
93             struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
94             //debug_printf("exists for %s...\n", names[i-1]);
95             err = cl->call_seq.exists(cl, names[i-1], t, &tid, &exist_err);
96             if (err_is_fail(err)) {
97                 goto out;
98             }
99
100             if (err_is_ok(exist_err)) {
101                 err = cl->recv.trigger(cl, &tid, &fn, &mode, &record, &state);
102                 assert(err_is_ok(err));
103                 free(record);
104                 assert(mode & OCT_REMOVED);
105             }
106             else if (err_no(exist_err) != OCT_ERR_NO_RECORD) {
107                 err = exist_err;
108                 goto out;
109             }
110         }
111
112         // If we've come here our predecessor deleted his record;
113         // need to re-check that we are really the lock owner now
114
115         oct_free_names(names, len);
116         names = NULL;
117         len = 0;
118     }
119
120
121 out:
122     oct_free_names(names, len);
123     free(name);
124     return err;
125 }
126
127 /**
128  * \brief Synchronous unlock function.
129  *
130  * Deletes the given lock_record in on the server.
131  *
132  * \param[in] lock_record Record provided by oct_lock.
133  */
134 errval_t oct_unlock(const char* lock_record)
135 {
136     assert(lock_record != NULL);
137     errval_t err = SYS_ERR_OK;
138     char* name = NULL;
139
140     err = oct_read(lock_record, "%s", &name);
141     if (err_is_ok(err)) {
142         err = oct_del(name);
143     }
144     //debug_printf("id:%d unlocking: %s\n", id, name);
145
146     free(name);
147     return err;
148 }