Changeset 58cbb0c8 in mainline for uspace/srv/devman/devman.c
- Timestamp:
- 2011-09-01T22:19:21Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- aff587f
- Parents:
- 5f6e25e
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/devman.c
r5f6e25e r58cbb0c8 30 30 * @{ 31 31 */ 32 /** @file Device Manager 33 * 34 * Locking order: 35 * (1) driver_t.driver_mutex 36 * (2) dev_tree_t.rwlock 37 * 38 * Synchronization: 39 * - device_tree.rwlock protects: 40 * - tree root, complete tree topology 41 * - complete contents of device and function nodes 42 * - dev_node_t.refcnt, fun_node_t.refcnt prevent nodes from 43 * being deallocated 44 * - find_xxx() functions increase reference count of returned object 45 * - find_xxx_no_lock() do not increase reference count 46 * 47 * TODO 48 * - Track all steady and transient device/function states 49 * - Check states, wait for steady state on certain operations 50 */ 32 51 33 52 #include <errno.h> … … 43 62 #include "devman.h" 44 63 45 fun_node_t *find_node_child(fun_node_t *parent, const char *name);64 static fun_node_t *find_node_child(dev_tree_t *, fun_node_t *, const char *); 46 65 47 66 /* hash table operations */ … … 406 425 } 407 426 427 fun_add_ref(fun); 408 428 insert_fun_node(tree, fun, str_dup(""), NULL); 429 409 430 match_id_t *id = create_match_id(); 410 431 id->id = str_dup("root"); … … 422 443 } 423 444 445 dev_add_ref(dev); 424 446 insert_dev_node(tree, dev, fun); 425 447 … … 467 489 /** Assign a driver to a device. 468 490 * 491 * @param tree Device tree 469 492 * @param node The device's node in the device tree. 470 493 * @param drv The driver. 471 494 */ 472 void attach_driver(dev_ node_t *dev, driver_t *drv)495 void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv) 473 496 { 474 497 log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")", … … 476 499 477 500 fibril_mutex_lock(&drv->driver_mutex); 501 fibril_rwlock_write_lock(&tree->rwlock); 478 502 479 503 dev->drv = drv; 480 504 list_append(&dev->driver_devices, &drv->devices); 481 505 506 fibril_rwlock_write_unlock(&tree->rwlock); 482 507 fibril_mutex_unlock(&drv->driver_mutex); 483 508 } … … 485 510 /** Detach driver from device. 486 511 * 512 * @param tree Device tree 487 513 * @param node The device's node in the device tree. 488 514 * @param drv The driver. 489 515 */ 490 void detach_driver(dev_node_t *dev) 491 { 492 /* XXX need lock on dev */ 516 void detach_driver(dev_tree_t *tree, dev_node_t *dev) 517 { 493 518 driver_t *drv = dev->drv; 494 519 495 520 assert(drv != NULL); 521 496 522 log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")", 497 523 dev->pfun->pathname, drv->name); 498 524 499 525 fibril_mutex_lock(&drv->driver_mutex); 526 fibril_rwlock_write_lock(&tree->rwlock); 500 527 501 528 dev->drv = NULL; 502 529 list_remove(&dev->driver_devices); 503 530 531 fibril_rwlock_write_unlock(&tree->rwlock); 504 532 fibril_mutex_unlock(&drv->driver_mutex); 505 533 } … … 578 606 while (link != &driver->devices.head) { 579 607 dev = list_get_instance(link, dev_node_t, driver_devices); 608 fibril_rwlock_write_lock(&tree->rwlock); 609 580 610 if (dev->passed_to_driver) { 611 fibril_rwlock_write_unlock(&tree->rwlock); 581 612 link = link->next; 582 613 continue; 583 614 } 584 615 585 /* 586 * We remove the device from the list to allow safe adding 587 * of new devices (no one will touch our item this way). 588 */ 589 list_remove(link); 616 log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n", 617 (int)atomic_get(&dev->refcnt)); 618 dev_add_ref(dev); 590 619 591 620 /* … … 594 623 */ 595 624 fibril_mutex_unlock(&driver->driver_mutex); 625 fibril_rwlock_write_unlock(&tree->rwlock); 596 626 597 627 add_device(driver, dev, tree); 628 629 dev_del_ref(dev); 598 630 599 631 /* … … 602 634 */ 603 635 fibril_mutex_lock(&driver->driver_mutex); 604 605 /*606 * Insert the device back.607 * The order is not relevant here so no harm is done608 * (actually, the order would be preserved in most cases).609 */610 list_append(link, &driver->devices);611 636 612 637 /* … … 701 726 char *loc_name = NULL; 702 727 728 assert(fibril_rwlock_is_locked(&tree->rwlock)); 729 703 730 asprintf(&loc_name, "%s", fun->pathname); 704 731 if (loc_name == NULL) … … 805 832 806 833 /* Attach the driver to the device. */ 807 attach_driver( dev, drv);834 attach_driver(tree, dev, drv); 808 835 809 836 fibril_mutex_lock(&drv->driver_mutex); … … 822 849 } 823 850 824 int driver_dev_remove(dev_ node_t *dev)851 int driver_dev_remove(dev_tree_t *tree, dev_node_t *dev) 825 852 { 826 853 async_exch_t *exch; 827 854 sysarg_t retval; 828 855 driver_t *drv; 856 devman_handle_t handle; 829 857 830 858 assert(dev != NULL); 859 831 860 log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev); 861 862 fibril_rwlock_read_lock(&tree->rwlock); 832 863 drv = dev->drv; 864 handle = dev->handle; 865 fibril_rwlock_read_unlock(&tree->rwlock); 833 866 834 867 exch = async_exchange_begin(drv->sess); 835 retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, dev->handle);868 retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle); 836 869 async_exchange_end(exch); 837 870 … … 840 873 } 841 874 842 int driver_fun_online( fun_node_t *fun)875 int driver_fun_online(dev_tree_t *tree, fun_node_t *fun) 843 876 { 844 877 async_exch_t *exch; 845 878 sysarg_t retval; 846 879 driver_t *drv; 880 devman_handle_t handle; 847 881 848 882 log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun); 883 884 fibril_rwlock_read_lock(&tree->rwlock); 885 849 886 if (fun->dev == NULL) { 850 887 /* XXX root function? */ 888 fibril_rwlock_read_unlock(&tree->rwlock); 851 889 return EINVAL; 852 890 } 853 891 854 892 drv = fun->dev->drv; 893 handle = fun->handle; 894 fibril_rwlock_read_unlock(&tree->rwlock); 855 895 856 896 exch = async_exchange_begin(drv->sess); 857 retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, fun->handle);897 retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle); 858 898 loc_exchange_end(exch); 859 899 … … 861 901 } 862 902 863 int driver_fun_offline( fun_node_t *fun)903 int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun) 864 904 { 865 905 async_exch_t *exch; 866 906 sysarg_t retval; 867 907 driver_t *drv; 908 devman_handle_t handle; 868 909 869 910 log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun); 911 912 fibril_rwlock_read_lock(&tree->rwlock); 870 913 if (fun->dev == NULL) { 871 914 /* XXX root function? */ 915 fibril_rwlock_read_unlock(&tree->rwlock); 872 916 return EINVAL; 873 917 } 874 918 875 919 drv = fun->dev->drv; 920 handle = fun->handle; 921 fibril_rwlock_read_unlock(&tree->rwlock); 876 922 877 923 exch = async_exchange_begin(drv->sess); 878 retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, fun->handle);924 retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle); 879 925 loc_exchange_end(exch); 880 926 … … 909 955 if (!create_root_nodes(tree)) 910 956 return false; 911 957 912 958 /* Find suitable driver and start it. */ 913 return assign_driver(tree->root_node->child, drivers_list, tree); 959 dev_node_t *rdev = tree->root_node->child; 960 dev_add_ref(rdev); 961 int rc = assign_driver(rdev, drivers_list, tree); 962 dev_del_ref(rdev); 963 964 return rc; 914 965 } 915 966 … … 922 973 dev_node_t *create_dev_node(void) 923 974 { 924 dev_node_t *res = malloc(sizeof(dev_node_t)); 925 926 if (res != NULL) { 927 memset(res, 0, sizeof(dev_node_t)); 928 list_initialize(&res->functions); 929 link_initialize(&res->driver_devices); 930 link_initialize(&res->devman_dev); 931 } 932 933 return res; 975 dev_node_t *dev; 976 977 dev = calloc(1, sizeof(dev_node_t)); 978 if (dev == NULL) 979 return NULL; 980 981 atomic_set(&dev->refcnt, 0); 982 list_initialize(&dev->functions); 983 link_initialize(&dev->driver_devices); 984 link_initialize(&dev->devman_dev); 985 986 return dev; 934 987 } 935 988 … … 947 1000 } 948 1001 1002 /** Increase device node reference count. 1003 * 1004 * @param dev Device node 1005 */ 1006 void dev_add_ref(dev_node_t *dev) 1007 { 1008 atomic_inc(&dev->refcnt); 1009 } 1010 1011 /** Decrease device node reference count. 1012 * 1013 * When the count drops to zero the device node is freed. 1014 * 1015 * @param dev Device node 1016 */ 1017 void dev_del_ref(dev_node_t *dev) 1018 { 1019 if (atomic_predec(&dev->refcnt) == 0) 1020 delete_dev_node(dev); 1021 } 1022 1023 949 1024 /** Find the device node structure of the device witch has the specified handle. 950 1025 * … … 976 1051 fibril_rwlock_read_lock(&tree->rwlock); 977 1052 dev = find_dev_node_no_lock(tree, handle); 1053 if (dev != NULL) 1054 dev_add_ref(dev); 1055 978 1056 fibril_rwlock_read_unlock(&tree->rwlock); 979 1057 … … 1003 1081 list_get_instance(item, fun_node_t, dev_functions); 1004 1082 1005 if (pos < buf_cnt) 1083 if (pos < buf_cnt) { 1006 1084 hdl_buf[pos] = fun->handle; 1085 } 1086 1007 1087 pos++; 1008 1088 } … … 1020 1100 fun_node_t *create_fun_node(void) 1021 1101 { 1022 fun_node_t *res = malloc(sizeof(fun_node_t)); 1023 1024 if (res != NULL) { 1025 memset(res, 0, sizeof(fun_node_t)); 1026 link_initialize(&res->dev_functions); 1027 list_initialize(&res->match_ids.ids); 1028 link_initialize(&res->devman_fun); 1029 link_initialize(&res->loc_fun); 1030 } 1031 1032 return res; 1102 fun_node_t *fun; 1103 1104 fun = calloc(1, sizeof(fun_node_t)); 1105 if (fun == NULL) 1106 return NULL; 1107 1108 atomic_set(&fun->refcnt, 0); 1109 link_initialize(&fun->dev_functions); 1110 list_initialize(&fun->match_ids.ids); 1111 link_initialize(&fun->devman_fun); 1112 link_initialize(&fun->loc_fun); 1113 1114 return fun; 1033 1115 } 1034 1116 … … 1048 1130 } 1049 1131 1132 /** Increase function node reference count. 1133 * 1134 * @param fun Function node 1135 */ 1136 void fun_add_ref(fun_node_t *fun) 1137 { 1138 atomic_inc(&fun->refcnt); 1139 } 1140 1141 /** Decrease function node reference count. 1142 * 1143 * When the count drops to zero the function node is freed. 1144 * 1145 * @param fun Function node 1146 */ 1147 void fun_del_ref(fun_node_t *fun) 1148 { 1149 if (atomic_predec(&fun->refcnt) == 0) 1150 delete_fun_node(fun); 1151 } 1152 1050 1153 /** Find the function node with the specified handle. 1051 1154 * … … 1058 1161 unsigned long key = handle; 1059 1162 link_t *link; 1163 fun_node_t *fun; 1060 1164 1061 1165 assert(fibril_rwlock_is_locked(&tree->rwlock)); … … 1065 1169 return NULL; 1066 1170 1067 return hash_table_get_instance(link, fun_node_t, devman_fun); 1171 fun = hash_table_get_instance(link, fun_node_t, devman_fun); 1172 1173 return fun; 1068 1174 } 1069 1175 … … 1079 1185 1080 1186 fibril_rwlock_read_lock(&tree->rwlock); 1187 1081 1188 fun = find_fun_node_no_lock(tree, handle); 1189 if (fun != NULL) 1190 fun_add_ref(fun); 1191 1082 1192 fibril_rwlock_read_unlock(&tree->rwlock); 1083 1193 … … 1087 1197 /** Create and set device's full path in device tree. 1088 1198 * 1199 * @param tree Device tree 1089 1200 * @param node The device's device node. 1090 1201 * @param parent The parent device node. … … 1092 1203 * resources etc.). 1093 1204 */ 1094 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent) 1095 { 1205 static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent) 1206 { 1207 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1096 1208 assert(fun->name != NULL); 1097 1209 … … 1120 1232 * 1121 1233 * @param tree The device tree. 1122 * @param node The newly added device node. 1123 * @param dev_name The name of the newly added device. 1124 * @param parent The parent device node. 1234 * @param dev The newly added device node. 1235 * @param pfun The parent function node. 1125 1236 * 1126 1237 * @return True on success, false otherwise (insufficient resources … … 1129 1240 bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun) 1130 1241 { 1131 assert(dev != NULL);1132 assert(tree != NULL);1133 1242 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1134 1243 … … 1155 1264 void remove_dev_node(dev_tree_t *tree, dev_node_t *dev) 1156 1265 { 1157 assert(tree != NULL);1158 assert(dev != NULL);1159 1266 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1160 1267 … … 1174 1281 * 1175 1282 * @param tree The device tree. 1176 * @param nodeThe newly added function node.1177 * @param dev_name The name of the newly added function.1178 * @param parentOwning device node.1283 * @param fun The newly added function node. 1284 * @param fun_name The name of the newly added function. 1285 * @param dev Owning device node. 1179 1286 * 1180 1287 * @return True on success, false otherwise (insufficient resources … … 1186 1293 fun_node_t *pfun; 1187 1294 1188 assert(fun != NULL);1189 assert(tree != NULL);1190 1295 assert(fun_name != NULL); 1191 1296 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); … … 1198 1303 1199 1304 fun->name = fun_name; 1200 if (!set_fun_path( fun, pfun)) {1305 if (!set_fun_path(tree, fun, pfun)) { 1201 1306 return false; 1202 1307 } … … 1222 1327 void remove_fun_node(dev_tree_t *tree, fun_node_t *fun) 1223 1328 { 1224 assert(tree != NULL);1225 assert(fun != NULL);1226 1329 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1227 1330 … … 1256 1359 1257 1360 fun_node_t *fun = tree->root_node; 1361 fun_add_ref(fun); 1258 1362 /* 1259 1363 * Relative path to the function from its parent (but with '/' at the … … 1273 1377 } 1274 1378 1275 fun = find_node_child(fun, rel_path + 1); 1379 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1); 1380 fun_del_ref(fun); 1381 fun = cfun; 1276 1382 1277 1383 if (cont) { … … 1291 1397 * Device tree rwlock should be held at least for reading. 1292 1398 * 1399 * @param tree Device tree 1293 1400 * @param dev Device the function belongs to. 1294 1401 * @param name Function name (not path). … … 1296 1403 * @retval NULL No function with given name. 1297 1404 */ 1298 fun_node_t *find_fun_node_in_device(dev_ node_t *dev, const char *name)1299 { 1300 assert(dev != NULL); 1405 fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev, 1406 const char *name) 1407 { 1301 1408 assert(name != NULL); 1409 assert(fibril_rwlock_is_locked(&tree->rwlock)); 1302 1410 1303 1411 fun_node_t *fun; … … 1306 1414 fun = list_get_instance(link, fun_node_t, dev_functions); 1307 1415 1308 if (str_cmp(name, fun->name) == 0) 1416 if (str_cmp(name, fun->name) == 0) { 1417 fun_add_ref(fun); 1309 1418 return fun; 1419 } 1310 1420 } 1311 1421 … … 1317 1427 * Device tree rwlock should be held at least for reading. 1318 1428 * 1429 * @param tree Device tree 1319 1430 * @param parent The parent function node. 1320 1431 * @param name The name of the child function. 1321 1432 * @return The child function node. 1322 1433 */ 1323 fun_node_t *find_node_child(fun_node_t *pfun, const char *name) 1324 { 1325 return find_fun_node_in_device(pfun->child, name); 1434 static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun, 1435 const char *name) 1436 { 1437 return find_fun_node_in_device(tree, pfun->child, name); 1326 1438 } 1327 1439 … … 1336 1448 fibril_rwlock_read_lock(&tree->rwlock); 1337 1449 link = hash_table_find(&tree->loc_functions, &key); 1338 if (link != NULL) 1450 if (link != NULL) { 1339 1451 fun = hash_table_get_instance(link, fun_node_t, loc_fun); 1452 fun_add_ref(fun); 1453 } 1340 1454 fibril_rwlock_read_unlock(&tree->rwlock); 1341 1455 … … 1345 1459 void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun) 1346 1460 { 1461 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1462 1347 1463 unsigned long key = (unsigned long) fun->service_id; 1348 fibril_rwlock_write_lock(&tree->rwlock);1349 1464 hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun); 1350 fibril_rwlock_write_unlock(&tree->rwlock);1351 1465 } 1352 1466
Note:
See TracChangeset
for help on using the changeset viewer.