source: mainline/uspace/srv/devman/devtree.c@ 95658c9

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 95658c9 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
RevLine 
[59dc181]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
[5e801dc]44static inline size_t handle_key_hash(const void *key)
[59dc181]45{
[5e801dc]46 const devman_handle_t *handle = key;
47 return *handle;
[59dc181]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
[5e801dc]62static bool devman_devices_key_equal(const void *key, const ht_link_t *item)
[59dc181]63{
[5e801dc]64 const devman_handle_t *handle = key;
[59dc181]65 dev_node_t *dev = hash_table_get_inst(item, dev_node_t, devman_dev);
[5e801dc]66 return dev->handle == *handle;
[59dc181]67}
68
[5e801dc]69static bool devman_functions_key_equal(const void *key, const ht_link_t *item)
[59dc181]70{
[5e801dc]71 const devman_handle_t *handle = key;
[59dc181]72 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, devman_fun);
[5e801dc]73 return fun->handle == *handle;
[59dc181]74}
75
[5e801dc]76static inline size_t service_id_key_hash(const void *key)
[59dc181]77{
[5e801dc]78 const service_id_t *service_id = key;
79 return *service_id;
[59dc181]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
[5e801dc]88static bool loc_functions_key_equal(const void *key, const ht_link_t *item)
[59dc181]89{
[5e801dc]90 const service_id_t *service_id = key;
[59dc181]91 fun_node_t *fun = hash_table_get_inst(item, fun_node_t, loc_fun);
[5e801dc]92 return fun->service_id == *service_id;
[59dc181]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;
[a35b458]128
[59dc181]129 log_msg(LOG_DEFAULT, LVL_DEBUG, "create_root_nodes()");
[a35b458]130
[59dc181]131 fibril_rwlock_write_lock(&tree->rwlock);
[a35b458]132
[59dc181]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 */
[a35b458]139
[59dc181]140 fun = create_fun_node();
141 if (fun == NULL) {
142 fibril_rwlock_write_unlock(&tree->rwlock);
143 return false;
144 }
[a35b458]145
[f89204ee]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 }
[a35b458]151
[59dc181]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;
[a35b458]157
[59dc181]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 }
[a35b458]166
[59dc181]167 insert_dev_node(tree, dev, fun);
[a35b458]168
[59dc181]169 fibril_rwlock_write_unlock(&tree->rwlock);
[a35b458]170
[59dc181]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()");
[a35b458]185
[59dc181]186 tree->current_handle = 0;
[a35b458]187
[59dc181]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);
[a35b458]191
[59dc181]192 fibril_rwlock_initialize(&tree->rwlock);
[a35b458]193
[59dc181]194 /* Create root function and root device and add them to the device tree. */
195 if (!create_root_nodes(tree))
196 return false;
[a35b458]197
[59dc181]198 /* Find suitable driver and start it. */
199 dev_node_t *rdev = tree->root_node->child;
200 dev_add_ref(rdev);
[1569a9b]201 bool rc = assign_driver(rdev, drivers_list, tree);
[59dc181]202 dev_del_ref(rdev);
[a35b458]203
[59dc181]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));
[a35b458]219
[59dc181]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;
[a35b458]230
[59dc181]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));
[a35b458]242
[59dc181]243 log_msg(LOG_DEFAULT, LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
[a35b458]244
[59dc181]245 /* Remove node from the handle-to-node map. */
246 hash_table_remove(&tree->devman_devices, &dev->handle);
[a35b458]247
[59dc181]248 /* Unlink from parent function. */
249 dev->pfun->child = NULL;
250 dev->pfun = NULL;
[a35b458]251
[59dc181]252 dev->state = DEVICE_REMOVED;
253}
254
255/** Insert new function into device tree.
256 *
257 * @param tree The device tree.
[1b20da0]258 * @param fun The newly added function node.
[59dc181]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;
[a35b458]269
[59dc181]270 assert(fun_name != NULL);
271 assert(fibril_rwlock_is_write_locked(&tree->rwlock));
[a35b458]272
[59dc181]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;
[a35b458]278
[59dc181]279 fun->name = fun_name;
280 if (!set_fun_path(tree, fun, pfun)) {
281 return false;
282 }
[a35b458]283
[59dc181]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);
[a35b458]292
[59dc181]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));
[a35b458]304
[59dc181]305 /* Remove the node from the handle-to-node map. */
306 hash_table_remove(&tree->devman_functions, &fun->handle);
[a35b458]307
[59dc181]308 /* Remove the node from the list of its parent's children. */
309 if (fun->dev != NULL)
310 list_remove(&fun->dev_functions);
[a35b458]311
[59dc181]312 fun->dev = NULL;
313 fun->state = FUN_REMOVED;
314}
315
316/** @}
317 */
Note: See TracBrowser for help on using the repository browser.