Changeset 00aece0 in mainline for uspace/srv/devman/devman.c
- Timestamp:
- 2012-02-18T16:47:38Z (13 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 4449c6c
- Parents:
- bd5f3b7 (diff), f943dd3 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/srv/devman/devman.c
rbd5f3b7 r00aece0 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); 507 fibril_mutex_unlock(&drv->driver_mutex); 508 } 509 510 /** Detach driver from device. 511 * 512 * @param tree Device tree 513 * @param node The device's node in the device tree. 514 * @param drv The driver. 515 */ 516 void detach_driver(dev_tree_t *tree, dev_node_t *dev) 517 { 518 driver_t *drv = dev->drv; 519 520 assert(drv != NULL); 521 522 log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")", 523 dev->pfun->pathname, drv->name); 524 525 fibril_mutex_lock(&drv->driver_mutex); 526 fibril_rwlock_write_lock(&tree->rwlock); 527 528 dev->drv = NULL; 529 list_remove(&dev->driver_devices); 530 531 fibril_rwlock_write_unlock(&tree->rwlock); 482 532 fibril_mutex_unlock(&drv->driver_mutex); 483 533 } … … 556 606 while (link != &driver->devices.head) { 557 607 dev = list_get_instance(link, dev_node_t, driver_devices); 608 fibril_rwlock_write_lock(&tree->rwlock); 609 558 610 if (dev->passed_to_driver) { 611 fibril_rwlock_write_unlock(&tree->rwlock); 559 612 link = link->next; 560 613 continue; 561 614 } 562 615 563 /* 564 * We remove the device from the list to allow safe adding 565 * of new devices (no one will touch our item this way). 566 */ 567 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); 568 619 569 620 /* … … 572 623 */ 573 624 fibril_mutex_unlock(&driver->driver_mutex); 625 fibril_rwlock_write_unlock(&tree->rwlock); 574 626 575 627 add_device(driver, dev, tree); 628 629 dev_del_ref(dev); 576 630 577 631 /* … … 580 634 */ 581 635 fibril_mutex_lock(&driver->driver_mutex); 582 583 /*584 * Insert the device back.585 * The order is not relevant here so no harm is done586 * (actually, the order would be preserved in most cases).587 */588 list_append(link, &driver->devices);589 636 590 637 /* … … 679 726 char *loc_name = NULL; 680 727 728 assert(fibril_rwlock_is_locked(&tree->rwlock)); 729 681 730 asprintf(&loc_name, "%s", fun->pathname); 682 731 if (loc_name == NULL) … … 726 775 727 776 ipc_call_t answer; 728 aid_t req = async_send_2(exch, DRIVER_ ADD_DEVICE, dev->handle,777 aid_t req = async_send_2(exch, DRIVER_DEV_ADD, dev->handle, 729 778 parent_handle, &answer); 730 779 … … 751 800 default: 752 801 dev->state = DEVICE_INVALID; 802 break; 753 803 } 754 804 … … 783 833 784 834 /* Attach the driver to the device. */ 785 attach_driver( dev, drv);835 attach_driver(tree, dev, drv); 786 836 787 837 fibril_mutex_lock(&drv->driver_mutex); … … 797 847 add_device(drv, dev, tree); 798 848 849 fibril_mutex_lock(&drv->driver_mutex); 850 fibril_mutex_unlock(&drv->driver_mutex); 851 852 fibril_rwlock_write_lock(&tree->rwlock); 853 if (dev->pfun != NULL) { 854 dev->pfun->state = FUN_ON_LINE; 855 } 856 fibril_rwlock_write_unlock(&tree->rwlock); 799 857 return true; 858 } 859 860 int driver_dev_remove(dev_tree_t *tree, dev_node_t *dev) 861 { 862 async_exch_t *exch; 863 sysarg_t retval; 864 driver_t *drv; 865 devman_handle_t handle; 866 867 assert(dev != NULL); 868 869 log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev); 870 871 fibril_rwlock_read_lock(&tree->rwlock); 872 drv = dev->drv; 873 handle = dev->handle; 874 fibril_rwlock_read_unlock(&tree->rwlock); 875 876 exch = async_exchange_begin(drv->sess); 877 retval = async_req_1_0(exch, DRIVER_DEV_REMOVE, handle); 878 async_exchange_end(exch); 879 880 return retval; 881 } 882 883 int driver_dev_gone(dev_tree_t *tree, dev_node_t *dev) 884 { 885 async_exch_t *exch; 886 sysarg_t retval; 887 driver_t *drv; 888 devman_handle_t handle; 889 890 assert(dev != NULL); 891 892 log_msg(LVL_DEBUG, "driver_dev_gone(%p)", dev); 893 894 fibril_rwlock_read_lock(&tree->rwlock); 895 drv = dev->drv; 896 handle = dev->handle; 897 fibril_rwlock_read_unlock(&tree->rwlock); 898 899 exch = async_exchange_begin(drv->sess); 900 retval = async_req_1_0(exch, DRIVER_DEV_GONE, handle); 901 async_exchange_end(exch); 902 903 return retval; 904 } 905 906 int driver_fun_online(dev_tree_t *tree, fun_node_t *fun) 907 { 908 async_exch_t *exch; 909 sysarg_t retval; 910 driver_t *drv; 911 devman_handle_t handle; 912 913 log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun); 914 915 fibril_rwlock_read_lock(&tree->rwlock); 916 917 if (fun->dev == NULL) { 918 /* XXX root function? */ 919 fibril_rwlock_read_unlock(&tree->rwlock); 920 return EINVAL; 921 } 922 923 drv = fun->dev->drv; 924 handle = fun->handle; 925 fibril_rwlock_read_unlock(&tree->rwlock); 926 927 exch = async_exchange_begin(drv->sess); 928 retval = async_req_1_0(exch, DRIVER_FUN_ONLINE, handle); 929 loc_exchange_end(exch); 930 931 return retval; 932 } 933 934 int driver_fun_offline(dev_tree_t *tree, fun_node_t *fun) 935 { 936 async_exch_t *exch; 937 sysarg_t retval; 938 driver_t *drv; 939 devman_handle_t handle; 940 941 log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun); 942 943 fibril_rwlock_read_lock(&tree->rwlock); 944 if (fun->dev == NULL) { 945 /* XXX root function? */ 946 fibril_rwlock_read_unlock(&tree->rwlock); 947 return EINVAL; 948 } 949 950 drv = fun->dev->drv; 951 handle = fun->handle; 952 fibril_rwlock_read_unlock(&tree->rwlock); 953 954 exch = async_exchange_begin(drv->sess); 955 retval = async_req_1_0(exch, DRIVER_FUN_OFFLINE, handle); 956 loc_exchange_end(exch); 957 958 return retval; 959 800 960 } 801 961 … … 826 986 if (!create_root_nodes(tree)) 827 987 return false; 828 988 829 989 /* Find suitable driver and start it. */ 830 return assign_driver(tree->root_node->child, drivers_list, tree); 990 dev_node_t *rdev = tree->root_node->child; 991 dev_add_ref(rdev); 992 int rc = assign_driver(rdev, drivers_list, tree); 993 dev_del_ref(rdev); 994 995 return rc; 831 996 } 832 997 … … 839 1004 dev_node_t *create_dev_node(void) 840 1005 { 841 dev_node_t *res = malloc(sizeof(dev_node_t)); 842 843 if (res != NULL) { 844 memset(res, 0, sizeof(dev_node_t)); 845 list_initialize(&res->functions); 846 link_initialize(&res->driver_devices); 847 link_initialize(&res->devman_dev); 848 } 849 850 return res; 1006 dev_node_t *dev; 1007 1008 dev = calloc(1, sizeof(dev_node_t)); 1009 if (dev == NULL) 1010 return NULL; 1011 1012 atomic_set(&dev->refcnt, 0); 1013 list_initialize(&dev->functions); 1014 link_initialize(&dev->driver_devices); 1015 link_initialize(&dev->devman_dev); 1016 1017 return dev; 851 1018 } 852 1019 … … 864 1031 } 865 1032 1033 /** Increase device node reference count. 1034 * 1035 * @param dev Device node 1036 */ 1037 void dev_add_ref(dev_node_t *dev) 1038 { 1039 atomic_inc(&dev->refcnt); 1040 } 1041 1042 /** Decrease device node reference count. 1043 * 1044 * When the count drops to zero the device node is freed. 1045 * 1046 * @param dev Device node 1047 */ 1048 void dev_del_ref(dev_node_t *dev) 1049 { 1050 if (atomic_predec(&dev->refcnt) == 0) 1051 delete_dev_node(dev); 1052 } 1053 1054 866 1055 /** Find the device node structure of the device witch has the specified handle. 867 1056 * … … 878 1067 879 1068 link = hash_table_find(&tree->devman_devices, &key); 1069 if (link == NULL) 1070 return NULL; 1071 880 1072 return hash_table_get_instance(link, dev_node_t, devman_dev); 881 1073 } … … 893 1085 fibril_rwlock_read_lock(&tree->rwlock); 894 1086 dev = find_dev_node_no_lock(tree, handle); 1087 if (dev != NULL) 1088 dev_add_ref(dev); 1089 895 1090 fibril_rwlock_read_unlock(&tree->rwlock); 896 1091 … … 920 1115 list_get_instance(item, fun_node_t, dev_functions); 921 1116 922 if (pos < buf_cnt) 1117 if (pos < buf_cnt) { 923 1118 hdl_buf[pos] = fun->handle; 1119 } 1120 924 1121 pos++; 925 1122 } … … 937 1134 fun_node_t *create_fun_node(void) 938 1135 { 939 fun_node_t *res = malloc(sizeof(fun_node_t)); 940 941 if (res != NULL) { 942 memset(res, 0, sizeof(fun_node_t)); 943 link_initialize(&res->dev_functions); 944 list_initialize(&res->match_ids.ids); 945 link_initialize(&res->devman_fun); 946 link_initialize(&res->loc_fun); 947 } 948 949 return res; 1136 fun_node_t *fun; 1137 1138 fun = calloc(1, sizeof(fun_node_t)); 1139 if (fun == NULL) 1140 return NULL; 1141 1142 fun->state = FUN_INIT; 1143 atomic_set(&fun->refcnt, 0); 1144 link_initialize(&fun->dev_functions); 1145 list_initialize(&fun->match_ids.ids); 1146 link_initialize(&fun->devman_fun); 1147 link_initialize(&fun->loc_fun); 1148 1149 return fun; 950 1150 } 951 1151 … … 965 1165 } 966 1166 1167 /** Increase function node reference count. 1168 * 1169 * @param fun Function node 1170 */ 1171 void fun_add_ref(fun_node_t *fun) 1172 { 1173 atomic_inc(&fun->refcnt); 1174 } 1175 1176 /** Decrease function node reference count. 1177 * 1178 * When the count drops to zero the function node is freed. 1179 * 1180 * @param fun Function node 1181 */ 1182 void fun_del_ref(fun_node_t *fun) 1183 { 1184 if (atomic_predec(&fun->refcnt) == 0) 1185 delete_fun_node(fun); 1186 } 1187 967 1188 /** Find the function node with the specified handle. 968 1189 * … … 975 1196 unsigned long key = handle; 976 1197 link_t *link; 1198 fun_node_t *fun; 977 1199 978 1200 assert(fibril_rwlock_is_locked(&tree->rwlock)); … … 982 1204 return NULL; 983 1205 984 return hash_table_get_instance(link, fun_node_t, devman_fun); 1206 fun = hash_table_get_instance(link, fun_node_t, devman_fun); 1207 1208 return fun; 985 1209 } 986 1210 … … 996 1220 997 1221 fibril_rwlock_read_lock(&tree->rwlock); 1222 998 1223 fun = find_fun_node_no_lock(tree, handle); 1224 if (fun != NULL) 1225 fun_add_ref(fun); 1226 999 1227 fibril_rwlock_read_unlock(&tree->rwlock); 1000 1228 … … 1004 1232 /** Create and set device's full path in device tree. 1005 1233 * 1234 * @param tree Device tree 1006 1235 * @param node The device's device node. 1007 1236 * @param parent The parent device node. … … 1009 1238 * resources etc.). 1010 1239 */ 1011 static bool set_fun_path(fun_node_t *fun, fun_node_t *parent) 1012 { 1240 static bool set_fun_path(dev_tree_t *tree, fun_node_t *fun, fun_node_t *parent) 1241 { 1242 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1013 1243 assert(fun->name != NULL); 1014 1244 … … 1037 1267 * 1038 1268 * @param tree The device tree. 1039 * @param node The newly added device node. 1040 * @param dev_name The name of the newly added device. 1041 * @param parent The parent device node. 1269 * @param dev The newly added device node. 1270 * @param pfun The parent function node. 1042 1271 * 1043 1272 * @return True on success, false otherwise (insufficient resources … … 1046 1275 bool insert_dev_node(dev_tree_t *tree, dev_node_t *dev, fun_node_t *pfun) 1047 1276 { 1048 assert(dev != NULL);1049 assert(tree != NULL);1050 1277 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1051 1278 … … 1065 1292 } 1066 1293 1294 /** Remove device from device tree. 1295 * 1296 * @param tree Device tree 1297 * @param dev Device node 1298 */ 1299 void remove_dev_node(dev_tree_t *tree, dev_node_t *dev) 1300 { 1301 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1302 1303 log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev); 1304 1305 /* Remove node from the handle-to-node map. */ 1306 unsigned long key = dev->handle; 1307 hash_table_remove(&tree->devman_devices, &key, 1); 1308 1309 /* Unlink from parent function. */ 1310 dev->pfun->child = NULL; 1311 dev->pfun = NULL; 1312 1313 dev->state = DEVICE_REMOVED; 1314 } 1315 1316 1067 1317 /** Insert new function into device tree. 1068 1318 * 1069 1319 * @param tree The device tree. 1070 * @param nodeThe newly added function node.1071 * @param dev_name The name of the newly added function.1072 * @param parentOwning device node.1320 * @param fun The newly added function node. 1321 * @param fun_name The name of the newly added function. 1322 * @param dev Owning device node. 1073 1323 * 1074 1324 * @return True on success, false otherwise (insufficient resources … … 1080 1330 fun_node_t *pfun; 1081 1331 1082 assert(fun != NULL);1083 assert(tree != NULL);1084 1332 assert(fun_name != NULL); 1085 1333 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); … … 1092 1340 1093 1341 fun->name = fun_name; 1094 if (!set_fun_path( fun, pfun)) {1342 if (!set_fun_path(tree, fun, pfun)) { 1095 1343 return false; 1096 1344 } … … 1116 1364 void remove_fun_node(dev_tree_t *tree, fun_node_t *fun) 1117 1365 { 1118 assert(tree != NULL);1119 assert(fun != NULL);1120 1366 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1121 1367 … … 1127 1373 if (fun->dev != NULL) 1128 1374 list_remove(&fun->dev_functions); 1375 1376 fun->dev = NULL; 1377 fun->state = FUN_REMOVED; 1129 1378 } 1130 1379 … … 1148 1397 1149 1398 fun_node_t *fun = tree->root_node; 1399 fun_add_ref(fun); 1150 1400 /* 1151 1401 * Relative path to the function from its parent (but with '/' at the … … 1165 1415 } 1166 1416 1167 fun = find_node_child(fun, rel_path + 1); 1417 fun_node_t *cfun = find_node_child(tree, fun, rel_path + 1); 1418 fun_del_ref(fun); 1419 fun = cfun; 1168 1420 1169 1421 if (cont) { … … 1183 1435 * Device tree rwlock should be held at least for reading. 1184 1436 * 1437 * @param tree Device tree 1185 1438 * @param dev Device the function belongs to. 1186 1439 * @param name Function name (not path). … … 1188 1441 * @retval NULL No function with given name. 1189 1442 */ 1190 fun_node_t *find_fun_node_in_device(dev_ node_t *dev, const char *name)1191 { 1192 assert(dev != NULL); 1443 fun_node_t *find_fun_node_in_device(dev_tree_t *tree, dev_node_t *dev, 1444 const char *name) 1445 { 1193 1446 assert(name != NULL); 1447 assert(fibril_rwlock_is_locked(&tree->rwlock)); 1194 1448 1195 1449 fun_node_t *fun; … … 1198 1452 fun = list_get_instance(link, fun_node_t, dev_functions); 1199 1453 1200 if (str_cmp(name, fun->name) == 0) 1454 if (str_cmp(name, fun->name) == 0) { 1455 fun_add_ref(fun); 1201 1456 return fun; 1457 } 1202 1458 } 1203 1459 … … 1209 1465 * Device tree rwlock should be held at least for reading. 1210 1466 * 1467 * @param tree Device tree 1211 1468 * @param parent The parent function node. 1212 1469 * @param name The name of the child function. 1213 1470 * @return The child function node. 1214 1471 */ 1215 fun_node_t *find_node_child(fun_node_t *pfun, const char *name) 1216 { 1217 return find_fun_node_in_device(pfun->child, name); 1472 static fun_node_t *find_node_child(dev_tree_t *tree, fun_node_t *pfun, 1473 const char *name) 1474 { 1475 return find_fun_node_in_device(tree, pfun->child, name); 1218 1476 } 1219 1477 … … 1228 1486 fibril_rwlock_read_lock(&tree->rwlock); 1229 1487 link = hash_table_find(&tree->loc_functions, &key); 1230 if (link != NULL) 1488 if (link != NULL) { 1231 1489 fun = hash_table_get_instance(link, fun_node_t, loc_fun); 1490 fun_add_ref(fun); 1491 } 1232 1492 fibril_rwlock_read_unlock(&tree->rwlock); 1233 1493 … … 1237 1497 void tree_add_loc_function(dev_tree_t *tree, fun_node_t *fun) 1238 1498 { 1499 assert(fibril_rwlock_is_write_locked(&tree->rwlock)); 1500 1239 1501 unsigned long key = (unsigned long) fun->service_id; 1240 fibril_rwlock_write_lock(&tree->rwlock);1241 1502 hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun); 1242 fibril_rwlock_write_unlock(&tree->rwlock);1243 1503 } 1244 1504
Note:
See TracChangeset
for help on using the changeset viewer.