source: mainline/generic/src/synch/futex.c@ 9aa72b4

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9aa72b4 was 9aa72b4, checked in by Jakub Jermar <jakub@…>, 19 years ago

Basic futex. Prototype implementation.

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/*
2 * Copyright (C) 2006 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * Kernel backend for futexes.
31 * Deallocation of orphaned kernel-side futex structures is not currently implemented.
32 * Timeouting futexes are currently not implemented.
33 */
34
35#include <synch/futex.h>
36#include <synch/rwlock.h>
37#include <synch/synch.h>
38#include <mm/frame.h>
39#include <mm/page.h>
40#include <mm/slab.h>
41#include <genarch/mm/page_pt.h>
42#include <genarch/mm/page_ht.h>
43#include <adt/hash_table.h>
44#include <adt/list.h>
45#include <arch.h>
46#include <align.h>
47#include <panic.h>
48#include <errno.h>
49#include <print.h>
50
51#define FUTEX_HT_SIZE 1024 /* keep it a power of 2 */
52
53static void futex_initialize(futex_t *futex);
54
55static index_t futex_ht_hash(__native *key);
56static bool futex_ht_compare(__native *key, count_t keys, link_t *item);
57static void futex_ht_remove_callback(link_t *item);
58
59/** Read-write lock protecting global futex hash table. */
60static rwlock_t futex_ht_lock;
61
62/** Futex hash table. */
63static hash_table_t futex_ht;
64
65/** Futex hash table operations. */
66static hash_table_operations_t futex_ht_ops = {
67 .hash = futex_ht_hash,
68 .compare = futex_ht_compare,
69 .remove_callback = futex_ht_remove_callback
70};
71
72/** Initialize futex subsystem. */
73void futex_init(void)
74{
75 rwlock_initialize(&futex_ht_lock);
76 hash_table_create(&futex_ht, FUTEX_HT_SIZE, 1, &futex_ht_ops);
77}
78
79/** Initialize kernel futex structure.
80 *
81 * @param futex Kernel futex structure.
82 */
83void futex_initialize(futex_t *futex)
84{
85 waitq_initialize(&futex->wq);
86 link_initialize(&futex->ht_link);
87 futex->paddr = 0;
88}
89
90/** Sleep in futex wait queue.
91 *
92 * @param uaddr Userspace address of the futex counter.
93 *
94 * @return One of ESYNCH_OK_ATOMIC and ESYNCH_OK_BLOCKED. See synch.h.
95 * If there is no physical mapping for uaddr ENOENT is returned.
96 */
97__native sys_futex_sleep(__address uaddr)
98{
99 futex_t *futex;
100 __address paddr;
101 link_t *item;
102 pte_t *t;
103
104 /*
105 * Find physical address of futex counter.
106 */
107 page_table_lock(AS, true);
108 t = page_mapping_find(AS, ALIGN_DOWN(uaddr, PAGE_SIZE));
109 if (!t || !PTE_VALID(t) || !PTE_PRESENT(t)) {
110 page_table_unlock(AS, true);
111 return (__native) ENOENT;
112 }
113 paddr = PFN2ADDR(PTE_GET_FRAME(t)) + (uaddr - ALIGN_DOWN(uaddr, PAGE_SIZE));
114 page_table_unlock(AS, true);
115
116 /*
117 * Find the respective futex structure
118 * or allocate new one if it does not exist already.
119 */
120 rwlock_read_lock(&futex_ht_lock);
121 item = hash_table_find(&futex_ht, &paddr);
122 if (item) {
123 futex = hash_table_get_instance(item, futex_t, ht_link);
124 rwlock_read_unlock(&futex_ht_lock);
125 } else {
126 /*
127 * Upgrade to writer is not currently supported,
128 * Therefore, it is necessary to release the read lock
129 * and reacquire it as a writer.
130 */
131 rwlock_read_unlock(&futex_ht_lock);
132
133 rwlock_write_lock(&futex_ht_lock);
134 /*
135 * Detect possible race condition by searching
136 * the hash table once again with write access.
137 */
138 item = hash_table_find(&futex_ht, &paddr);
139 if (item) {
140 futex = hash_table_get_instance(item, futex_t, ht_link);
141 rwlock_write_unlock(&futex_ht_lock);
142 } else {
143 futex = (futex_t *) malloc(sizeof(futex_t), 0);
144 futex_initialize(futex);
145 futex->paddr = paddr;
146 hash_table_insert(&futex_ht, &paddr, &futex->ht_link);
147 rwlock_write_unlock(&futex_ht_lock);
148 }
149 }
150
151 return (__native) waitq_sleep(&futex->wq);
152}
153
154/** Wakeup one thread waiting in futex wait queue.
155 *
156 * @param uaddr Userspace address of the futex counter.
157 *
158 * @return ENOENT if there is no futex associated with the address
159 * or if there is no physical mapping for uaddr.
160 */
161__native sys_futex_wakeup(__address uaddr)
162{
163 futex_t *futex = NULL;
164 __address paddr;
165 link_t *item;
166 pte_t *t;
167
168 /*
169 * Find physical address of futex counter.
170 */
171 page_table_lock(AS, true);
172 t = page_mapping_find(AS, ALIGN_DOWN(uaddr, PAGE_SIZE));
173 if (!t || !PTE_VALID(t) || !PTE_PRESENT(t)) {
174 page_table_unlock(AS, true);
175 return (__native) ENOENT;
176 }
177 paddr = PFN2ADDR(PTE_GET_FRAME(t)) + (uaddr - ALIGN_DOWN(uaddr, PAGE_SIZE));
178 page_table_unlock(AS, true);
179
180 /*
181 * Find the respective futex structure.
182 */
183 rwlock_read_lock(&futex_ht_lock);
184 item = hash_table_find(&futex_ht, &paddr);
185 if (item) {
186 futex = hash_table_get_instance(item, futex_t, ht_link);
187 }
188 rwlock_read_unlock(&futex_ht_lock);
189
190 if (!futex)
191 return (__native) ENOENT;
192
193 waitq_wakeup(&futex->wq, WAKEUP_FIRST);
194
195 return 0;
196}
197
198/** Compute hash index into futex hash table.
199 *
200 * @param key Address where the key (i.e. physical address of futex counter) is stored.
201 *
202 * @return Index into futex hash table.
203 */
204index_t futex_ht_hash(__native *key)
205{
206 return *key & (FUTEX_HT_SIZE-1);
207}
208
209/** Compare futex hash table item with a key.
210 *
211 * @param key Address where the key (i.e. physical address of futex counter) is stored.
212 *
213 * @return True if the item matches the key. False otherwise.
214 */
215bool futex_ht_compare(__native *key, count_t keys, link_t *item)
216{
217 futex_t *futex;
218
219 ASSERT(keys == 1);
220
221 futex = hash_table_get_instance(item, futex_t, ht_link);
222 return *key == futex->paddr;
223}
224
225/** Callback for removal items from futex hash table.
226 *
227 * @param item Item removed from the hash table.
228 */
229void futex_ht_remove_callback(link_t *item)
230{
231 futex_t *futex;
232
233 futex = hash_table_get_instance(item, futex_t, ht_link);
234 free(futex);
235}
Note: See TracBrowser for help on using the repository browser.