source: mainline/uspace/srv/devman/devtree.c@ 22faaf2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 22faaf2 was 5e801dc, checked in by GitHub <noreply@…>, 6 years ago

Indicate and enforce constness of hash table key in certain functions (#158)

The assumption here is that modifying key in the hash/equal functions in something completely unexpected, and not something you would ever want to do intentionally, so it makes sense to disallow it entirely to get that extra level of checking.

  • Property mode set to 100644
File size: 8.5 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
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/** @addtogroup devman
30 * @{
31 */
32
33#include <errno.h>
34#include <io/log.h>
35
36#include "dev.h"
37#include "devtree.h"
38#include "devman.h"
39#include "driver.h"
40#include "fun.h"
41
42/* hash table operations */
43
44static inline size_t handle_key_hash(const void *key)
45{
46 const devman_handle_t *handle = key;
47 return *handle;
48}
49
50static size_t devman_devices_hash(const ht_link_t *item)
51{
52 dev_node_t *dev = hash_table_get_inst(item, dev_node_t, devman_dev);
53 return handle_key_hash(&dev->handle);
54}
55
56static size_t devman_functions_hash(const ht_link_t *item)
57{
58 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, devman_fun);
59 return handle_key_hash(&fun->handle);
60}
61
62static bool devman_devices_key_equal(const void *key, const ht_link_t *item)
63{
64 const devman_handle_t *handle = key;
65 dev_node_t *dev = hash_table_get_inst(item, dev_node_t, devman_dev);
66 return dev->handle == *handle;
67}
68
69static bool devman_functions_key_equal(const void *key, const ht_link_t *item)
70{
71 const devman_handle_t *handle = key;
72 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, devman_fun);
73 return fun->handle == *handle;
74}
75
76static inline size_t service_id_key_hash(const void *key)
77{
78 const service_id_t *service_id = key;
79 return *service_id;
80}
81
82static size_t loc_functions_hash(const ht_link_t *item)
83{
84 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, loc_fun);
85 return service_id_key_hash(&fun->service_id);
86}
87
88static bool loc_functions_key_equal(const void *key, const ht_link_t *item)
89{
90 const service_id_t *service_id = key;
91 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, loc_fun);
92 return fun->service_id == *service_id;
93}
94
95static hash_table_ops_t devman_devices_ops = {
96 .hash = devman_devices_hash,
97 .key_hash = handle_key_hash,
98 .key_equal = devman_devices_key_equal,
99 .equal = NULL,
100 .remove_callback = NULL
101};
102
103static hash_table_ops_t devman_functions_ops = {
104 .hash = devman_functions_hash,
105 .key_hash = handle_key_hash,
106 .key_equal = devman_functions_key_equal,
107 .equal = NULL,
108 .remove_callback = NULL
109};
110
111static hash_table_ops_t loc_devices_ops = {
112 .hash = loc_functions_hash,
113 .key_hash = service_id_key_hash,
114 .key_equal = loc_functions_key_equal,
115 .equal = NULL,
116 .remove_callback = NULL
117};
118
119/** Create root device and function node in the device tree.
120 *
121 * @param tree The device tree.
122 * @return True on success, false otherwise.
123 */
124bool create_root_nodes(dev_tree_t *tree)
125{
126 fun_node_t *fun;
127 dev_node_t *dev;
128
129 log_msg(LOG_DEFAULT, LVL_DEBUG, "create_root_nodes()");
130
131 fibril_rwlock_write_lock(&tree->rwlock);
132
133 /*
134 * Create root function. This is a pseudo function to which
135 * the root device node is attached. It allows us to match
136 * the root device driver in a standard manner, i.e. against
137 * the parent function.
138 */
139
140 fun = create_fun_node();
141 if (fun == NULL) {
142 fibril_rwlock_write_unlock(&tree->rwlock);
143 return false;
144 }
145
146 if (!insert_fun_node(tree, fun, str_dup(""), NULL)) {
147 fun_del_ref(fun); /* fun is destroyed */
148 fibril_rwlock_write_unlock(&tree->rwlock);
149 return false;
150 }
151
152 match_id_t *id = create_match_id();
153 id->id = str_dup("root");
154 id->score = 100;
155 add_match_id(&fun->match_ids, id);
156 tree->root_node = fun;
157
158 /*
159 * Create root device node.
160 */
161 dev = create_dev_node();
162 if (dev == NULL) {
163 fibril_rwlock_write_unlock(&tree->rwlock);
164 return false;
165 }
166
167 insert_dev_node(tree, dev, fun);
168
169 fibril_rwlock_write_unlock(&tree->rwlock);
170
171 return dev != NULL;
172}
173
174/** Initialize the device tree.
175 *
176 * Create root device node of the tree and assign driver to it.
177 *
178 * @param tree The device tree.
179 * @param drivers_list the list of available drivers.
180 * @return True on success, false otherwise.
181 */
182bool init_device_tree(dev_tree_t *tree, driver_list_t *drivers_list)
183{
184 log_msg(LOG_DEFAULT, LVL_DEBUG, "init_device_tree()");
185
186 tree->current_handle = 0;
187
188 hash_table_create(&tree->devman_devices, 0, 0, &devman_devices_ops);
189 hash_table_create(&tree->devman_functions, 0, 0, &devman_functions_ops);
190 hash_table_create(&tree->loc_functions, 0, 0, &loc_devices_ops);
191
192 fibril_rwlock_initialize(&tree->rwlock);
193
194 /* Create root function and root device and add them to the device tree. */
195 if (!create_root_nodes(tree))
196 return false;
197
198 /* Find suitable driver and start it. */
199 dev_node_t *rdev = tree->root_node->child;
200 dev_add_ref(rdev);
201 bool rc = assign_driver(rdev, drivers_list, tree);
202 dev_del_ref(rdev);
203
204 return rc;
205}
206
207/** Insert new device into device tree.
208 *
209 * @param tree The device tree.
210 * @param dev The newly added device node.
211 * @param pfun The parent function node.
212 *
213 * @return True on success, false otherwise (insufficient resources
214 * etc.).
215 */
216bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun)
217{
218 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
219
220 log_msg(LOG_DEFAULT, LVL_DEBUG, "insert_dev_node(dev=%p, pfun=%p [\"%s\"])",
221 dev, pfun, pfun->pathname);
222
223 /* Add the node to the handle-to-node map. */
224 dev->handle = ++tree->current_handle;
225 hash_table_insert(&tree->devman_devices, &dev->devman_dev);
226
227 /* Add the node to the list of its parent's children. */
228 dev->pfun = pfun;
229 pfun->child = dev;
230
231 return true;
232}
233
234/** Remove device from device tree.
235 *
236 * @param tree Device tree
237 * @param dev Device node
238 */
239void remove_dev_node(dev_tree_t *tree, dev_node_t *dev)
240{
241 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
242
243 log_msg(LOG_DEFAULT, LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
244
245 /* Remove node from the handle-to-node map. */
246 hash_table_remove(&tree->devman_devices, &dev->handle);
247
248 /* Unlink from parent function. */
249 dev->pfun->child = NULL;
250 dev->pfun = NULL;
251
252 dev->state = DEVICE_REMOVED;
253}
254
255/** Insert new function into device tree.
256 *
257 * @param tree The device tree.
258 * @param fun The newly added function node.
259 * @param fun_name The name of the newly added function.
260 * @param dev Owning device node.
261 *
262 * @return True on success, false otherwise (insufficient resources
263 * etc.).
264 */
265bool insert_fun_node(dev_tree_t *tree, fun_node_t *fun, char *fun_name,
266 dev_node_t *dev)
267{
268 fun_node_t *pfun;
269
270 assert(fun_name != NULL);
271 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
272
273 /*
274 * The root function is a special case, it does not belong to any
275 * device so for the root function dev == NULL.
276 */
277 pfun = (dev != NULL) ? dev->pfun : NULL;
278
279 fun->name = fun_name;
280 if (!set_fun_path(tree, fun, pfun)) {
281 return false;
282 }
283
284 /* Add the node to the handle-to-node map. */
285 fun->handle = ++tree->current_handle;
286 hash_table_insert(&tree->devman_functions, &fun->devman_fun);
287
288 /* Add the node to the list of its parent's children. */
289 fun->dev = dev;
290 if (dev != NULL)
291 list_append(&fun->dev_functions, &dev->functions);
292
293 return true;
294}
295
296/** Remove function from device tree.
297 *
298 * @param tree Device tree
299 * @param node Function node to remove
300 */
301void remove_fun_node(dev_tree_t *tree, fun_node_t *fun)
302{
303 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
304
305 /* Remove the node from the handle-to-node map. */
306 hash_table_remove(&tree->devman_functions, &fun->handle);
307
308 /* Remove the node from the list of its parent's children. */
309 if (fun->dev != NULL)
310 list_remove(&fun->dev_functions);
311
312 fun->dev = NULL;
313 fun->state = FUN_REMOVED;
314}
315
316/** @}
317 */
Note: See TracBrowser for help on using the repository browser.