~jsvoboda/helenos/dnsr

« back to all changes in this revision

Viewing changes to uspace/srv/devman/devman.c

  • Committer: Jiri Svoboda
  • Date: 2012-11-11 21:31:03 UTC
  • mfrom: (1527.1.178 mainline)
  • Revision ID: jiri@wiwaxia-20121111213103-314bmkettwvlwj97
MergeĀ mainlineĀ changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
65
65
 
66
66
/* hash table operations */
67
67
 
68
 
static hash_index_t devices_hash(unsigned long key[])
69
 
{
70
 
        return key[0] % DEVICE_BUCKETS;
71
 
}
72
 
 
73
 
static int devman_devices_compare(unsigned long key[], hash_count_t keys,
74
 
    link_t *item)
75
 
{
76
 
        dev_node_t *dev = hash_table_get_instance(item, dev_node_t, devman_dev);
77
 
        return (dev->handle == (devman_handle_t) key[0]);
78
 
}
79
 
 
80
 
static int devman_functions_compare(unsigned long key[], hash_count_t keys,
81
 
    link_t *item)
82
 
{
83
 
        fun_node_t *fun = hash_table_get_instance(item, fun_node_t, devman_fun);
84
 
        return (fun->handle == (devman_handle_t) key[0]);
85
 
}
86
 
 
87
 
static int loc_functions_compare(unsigned long key[], hash_count_t keys,
88
 
    link_t *item)
89
 
{
90
 
        fun_node_t *fun = hash_table_get_instance(item, fun_node_t, loc_fun);
91
 
        return (fun->service_id == (service_id_t) key[0]);
92
 
}
93
 
 
94
 
static void devices_remove_callback(link_t *item)
95
 
{
96
 
}
97
 
 
98
 
static hash_table_operations_t devman_devices_ops = {
99
 
        .hash = devices_hash,
100
 
        .compare = devman_devices_compare,
101
 
        .remove_callback = devices_remove_callback
102
 
};
103
 
 
104
 
static hash_table_operations_t devman_functions_ops = {
105
 
        .hash = devices_hash,
106
 
        .compare = devman_functions_compare,
107
 
        .remove_callback = devices_remove_callback
108
 
};
109
 
 
110
 
static hash_table_operations_t loc_devices_ops = {
111
 
        .hash = devices_hash,
112
 
        .compare = loc_functions_compare,
113
 
        .remove_callback = devices_remove_callback
 
68
static inline size_t handle_key_hash(void *key)
 
69
{
 
70
        devman_handle_t handle = *(devman_handle_t*)key;
 
71
        return handle;
 
72
}
 
73
 
 
74
static size_t devman_devices_hash(const ht_link_t *item)
 
75
{
 
76
        dev_node_t *dev = hash_table_get_inst(item, dev_node_t, devman_dev);
 
77
        return handle_key_hash(&dev->handle);
 
78
}
 
79
 
 
80
static size_t devman_functions_hash(const ht_link_t *item)
 
81
{
 
82
        fun_node_t *fun = hash_table_get_inst(item, fun_node_t, devman_fun);
 
83
        return handle_key_hash(&fun->handle);
 
84
}
 
85
 
 
86
static bool devman_devices_key_equal(void *key, const ht_link_t *item)
 
87
{
 
88
        devman_handle_t handle = *(devman_handle_t*)key;
 
89
        dev_node_t *dev = hash_table_get_inst(item, dev_node_t, devman_dev);
 
90
        return dev->handle == handle;
 
91
}
 
92
 
 
93
static bool devman_functions_key_equal(void *key, const ht_link_t *item)
 
94
{
 
95
        devman_handle_t handle = *(devman_handle_t*)key;
 
96
        fun_node_t *fun = hash_table_get_inst(item, fun_node_t, devman_fun);
 
97
        return fun->handle == handle;
 
98
}
 
99
 
 
100
static inline size_t service_id_key_hash(void *key)
 
101
{
 
102
        service_id_t service_id = *(service_id_t*)key;
 
103
        return service_id;
 
104
}
 
105
 
 
106
static size_t loc_functions_hash(const ht_link_t *item)
 
107
{
 
108
        fun_node_t *fun = hash_table_get_inst(item, fun_node_t, loc_fun);
 
109
        return service_id_key_hash(&fun->service_id);
 
110
}
 
111
 
 
112
static bool loc_functions_key_equal(void *key, const ht_link_t *item)
 
113
{
 
114
        service_id_t service_id = *(service_id_t*)key;
 
115
        fun_node_t *fun = hash_table_get_inst(item, fun_node_t, loc_fun);
 
116
        return fun->service_id == service_id;
 
117
}
 
118
 
 
119
 
 
120
static hash_table_ops_t devman_devices_ops = {
 
121
        .hash = devman_devices_hash,
 
122
        .key_hash = handle_key_hash,
 
123
        .key_equal = devman_devices_key_equal,
 
124
        .equal = NULL,
 
125
        .remove_callback = NULL
 
126
};
 
127
 
 
128
static hash_table_ops_t devman_functions_ops = {
 
129
        .hash = devman_functions_hash,
 
130
        .key_hash = handle_key_hash,
 
131
        .key_equal = devman_functions_key_equal,
 
132
        .equal = NULL,
 
133
        .remove_callback = NULL
 
134
};
 
135
 
 
136
static hash_table_ops_t loc_devices_ops = {
 
137
        .hash = loc_functions_hash,
 
138
        .key_hash = service_id_key_hash,
 
139
        .key_equal = loc_functions_key_equal,
 
140
        .equal = NULL,
 
141
        .remove_callback = NULL
114
142
};
115
143
 
116
144
/**
150
178
        list_prepend(&drv->drivers, &drivers_list->drivers);
151
179
        fibril_mutex_unlock(&drivers_list->drivers_mutex);
152
180
 
153
 
        log_msg(LVL_NOTE, "Driver `%s' was added to the list of available "
 
181
        log_msg(LOG_DEFAULT, LVL_NOTE, "Driver `%s' was added to the list of available "
154
182
            "drivers.", drv->name);
155
183
}
156
184
 
241
269
 */
242
270
bool read_match_ids(const char *conf_path, match_id_list_t *ids)
243
271
{
244
 
        log_msg(LVL_DEBUG, "read_match_ids(conf_path=\"%s\")", conf_path);
 
272
        log_msg(LOG_DEFAULT, LVL_DEBUG, "read_match_ids(conf_path=\"%s\")", conf_path);
245
273
        
246
274
        bool suc = false;
247
275
        char *buf = NULL;
251
279
        
252
280
        fd = open(conf_path, O_RDONLY);
253
281
        if (fd < 0) {
254
 
                log_msg(LVL_ERROR, "Unable to open `%s' for reading: %s.",
 
282
                log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to open `%s' for reading: %s.",
255
283
                    conf_path, str_error(fd));
256
284
                goto cleanup;
257
285
        }
260
288
        len = lseek(fd, 0, SEEK_END);
261
289
        lseek(fd, 0, SEEK_SET);
262
290
        if (len == 0) {
263
 
                log_msg(LVL_ERROR, "Configuration file '%s' is empty.",
 
291
                log_msg(LOG_DEFAULT, LVL_ERROR, "Configuration file '%s' is empty.",
264
292
                    conf_path);
265
293
                goto cleanup;
266
294
        }
267
295
        
268
296
        buf = malloc(len + 1);
269
297
        if (buf == NULL) {
270
 
                log_msg(LVL_ERROR, "Memory allocation failed when parsing file "
 
298
                log_msg(LOG_DEFAULT, LVL_ERROR, "Memory allocation failed when parsing file "
271
299
                    "'%s'.", conf_path);
272
300
                goto cleanup;
273
301
        }
274
302
        
275
303
        ssize_t read_bytes = read_all(fd, buf, len);
276
304
        if (read_bytes <= 0) {
277
 
                log_msg(LVL_ERROR, "Unable to read file '%s' (%zd).", conf_path,
 
305
                log_msg(LOG_DEFAULT, LVL_ERROR, "Unable to read file '%s' (%zd).", conf_path,
278
306
                    read_bytes);
279
307
                goto cleanup;
280
308
        }
313
341
 */
314
342
bool get_driver_info(const char *base_path, const char *name, driver_t *drv)
315
343
{
316
 
        log_msg(LVL_DEBUG, "get_driver_info(base_path=\"%s\", name=\"%s\")",
 
344
        log_msg(LOG_DEFAULT, LVL_DEBUG, "get_driver_info(base_path=\"%s\", name=\"%s\")",
317
345
            base_path, name);
318
346
        
319
347
        assert(base_path != NULL && name != NULL && drv != NULL);
345
373
        /* Check whether the driver's binary exists. */
346
374
        struct stat s;
347
375
        if (stat(drv->binary_path, &s) == ENOENT) { /* FIXME!! */
348
 
                log_msg(LVL_ERROR, "Driver not found at path `%s'.",
 
376
                log_msg(LOG_DEFAULT, LVL_ERROR, "Driver not found at path `%s'.",
349
377
                    drv->binary_path);
350
378
                goto cleanup;
351
379
        }
373
401
 */
374
402
int lookup_available_drivers(driver_list_t *drivers_list, const char *dir_path)
375
403
{
376
 
        log_msg(LVL_DEBUG, "lookup_available_drivers(dir=\"%s\")", dir_path);
 
404
        log_msg(LOG_DEFAULT, LVL_DEBUG, "lookup_available_drivers(dir=\"%s\")", dir_path);
377
405
        
378
406
        int drv_cnt = 0;
379
407
        DIR *dir = NULL;
407
435
        fun_node_t *fun;
408
436
        dev_node_t *dev;
409
437
        
410
 
        log_msg(LVL_DEBUG, "create_root_nodes()");
 
438
        log_msg(LOG_DEFAULT, LVL_DEBUG, "create_root_nodes()");
411
439
        
412
440
        fibril_rwlock_write_lock(&tree->rwlock);
413
441
        
494
522
 */
495
523
void attach_driver(dev_tree_t *tree, dev_node_t *dev, driver_t *drv)
496
524
{
497
 
        log_msg(LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
 
525
        log_msg(LOG_DEFAULT, LVL_DEBUG, "attach_driver(dev=\"%s\",drv=\"%s\")",
498
526
            dev->pfun->pathname, drv->name);
499
527
        
500
528
        fibril_mutex_lock(&drv->driver_mutex);
519
547
        
520
548
        assert(drv != NULL);
521
549
        
522
 
        log_msg(LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
 
550
        log_msg(LOG_DEFAULT, LVL_DEBUG, "detach_driver(dev=\"%s\",drv=\"%s\")",
523
551
            dev->pfun->pathname, drv->name);
524
552
        
525
553
        fibril_mutex_lock(&drv->driver_mutex);
544
572
 
545
573
        assert(fibril_mutex_is_locked(&drv->driver_mutex));
546
574
        
547
 
        log_msg(LVL_DEBUG, "start_driver(drv=\"%s\")", drv->name);
 
575
        log_msg(LOG_DEFAULT, LVL_DEBUG, "start_driver(drv=\"%s\")", drv->name);
548
576
        
549
577
        rc = task_spawnl(NULL, drv->binary_path, drv->binary_path, NULL);
550
578
        if (rc != EOK) {
551
 
                log_msg(LVL_ERROR, "Spawning driver `%s' (%s) failed: %s.",
 
579
                log_msg(LOG_DEFAULT, LVL_ERROR, "Spawning driver `%s' (%s) failed: %s.",
552
580
                    drv->name, drv->binary_path, str_error(rc));
553
581
                return false;
554
582
        }
593
621
        dev_node_t *dev;
594
622
        link_t *link;
595
623
 
596
 
        log_msg(LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")",
 
624
        log_msg(LOG_DEFAULT, LVL_DEBUG, "pass_devices_to_driver(driver=\"%s\")",
597
625
            driver->name);
598
626
 
599
627
        fibril_mutex_lock(&driver->driver_mutex);
613
641
                        continue;
614
642
                }
615
643
 
616
 
                log_msg(LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
 
644
                log_msg(LOG_DEFAULT, LVL_DEBUG, "pass_devices_to_driver: dev->refcnt=%d\n",
617
645
                    (int)atomic_get(&dev->refcnt));
618
646
                dev_add_ref(dev);
619
647
 
649
677
         * the driver would be added to the device list and started
650
678
         * immediately and possibly started here as well.
651
679
         */
652
 
        log_msg(LVL_DEBUG, "Driver `%s' enters running state.", driver->name);
 
680
        log_msg(LOG_DEFAULT, LVL_DEBUG, "Driver `%s' enters running state.", driver->name);
653
681
        driver->state = DRIVER_RUNNING;
654
682
 
655
683
        fibril_mutex_unlock(&driver->driver_mutex);
666
694
 */
667
695
void initialize_running_driver(driver_t *driver, dev_tree_t *tree)
668
696
{
669
 
        log_msg(LVL_DEBUG, "initialize_running_driver(driver=\"%s\")",
 
697
        log_msg(LOG_DEFAULT, LVL_DEBUG, "initialize_running_driver(driver=\"%s\")",
670
698
            driver->name);
671
699
        
672
700
        /*
760
788
         * We do not expect to have driver's mutex locked as we do not
761
789
         * access any structures that would affect driver_t.
762
790
         */
763
 
        log_msg(LVL_DEBUG, "add_device(drv=\"%s\", dev=\"%s\")",
 
791
        log_msg(LOG_DEFAULT, LVL_DEBUG, "add_device(drv=\"%s\", dev=\"%s\")",
764
792
            drv->name, dev->pfun->name);
765
793
        
766
794
        /* Send the device to the driver. */
826
854
         */
827
855
        driver_t *drv = find_best_match_driver(drivers_list, dev);
828
856
        if (drv == NULL) {
829
 
                log_msg(LVL_ERROR, "No driver found for device `%s'.",
 
857
                log_msg(LOG_DEFAULT, LVL_ERROR, "No driver found for device `%s'.",
830
858
                    dev->pfun->pathname);
831
859
                return false;
832
860
        }
866
894
        
867
895
        assert(dev != NULL);
868
896
        
869
 
        log_msg(LVL_DEBUG, "driver_dev_remove(%p)", dev);
 
897
        log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_dev_remove(%p)", dev);
870
898
        
871
899
        fibril_rwlock_read_lock(&tree->rwlock);
872
900
        drv = dev->drv;
889
917
        
890
918
        assert(dev != NULL);
891
919
        
892
 
        log_msg(LVL_DEBUG, "driver_dev_gone(%p)", dev);
 
920
        log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_dev_gone(%p)", dev);
893
921
        
894
922
        fibril_rwlock_read_lock(&tree->rwlock);
895
923
        drv = dev->drv;
910
938
        driver_t *drv;
911
939
        devman_handle_t handle;
912
940
        
913
 
        log_msg(LVL_DEBUG, "driver_fun_online(%p)", fun);
 
941
        log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_fun_online(%p)", fun);
914
942
 
915
943
        fibril_rwlock_read_lock(&tree->rwlock);
916
944
        
938
966
        driver_t *drv;
939
967
        devman_handle_t handle;
940
968
        
941
 
        log_msg(LVL_DEBUG, "driver_fun_offline(%p)", fun);
 
969
        log_msg(LOG_DEFAULT, LVL_DEBUG, "driver_fun_offline(%p)", fun);
942
970
 
943
971
        fibril_rwlock_read_lock(&tree->rwlock);
944
972
        if (fun->dev == NULL) {
969
997
 */
970
998
bool init_device_tree(dev_tree_t *tree, driver_list_t *drivers_list)
971
999
{
972
 
        log_msg(LVL_DEBUG, "init_device_tree()");
 
1000
        log_msg(LOG_DEFAULT, LVL_DEBUG, "init_device_tree()");
973
1001
        
974
1002
        tree->current_handle = 0;
975
1003
        
976
 
        hash_table_create(&tree->devman_devices, DEVICE_BUCKETS, 1,
977
 
            &devman_devices_ops);
978
 
        hash_table_create(&tree->devman_functions, DEVICE_BUCKETS, 1,
979
 
            &devman_functions_ops);
980
 
        hash_table_create(&tree->loc_functions, DEVICE_BUCKETS, 1,
981
 
            &loc_devices_ops);
 
1004
        hash_table_create(&tree->devman_devices, 0, 0, &devman_devices_ops);
 
1005
        hash_table_create(&tree->devman_functions, 0, 0, &devman_functions_ops);
 
1006
        hash_table_create(&tree->loc_functions, 0, 0, &loc_devices_ops);
982
1007
        
983
1008
        fibril_rwlock_initialize(&tree->rwlock);
984
1009
        
1012
1037
        atomic_set(&dev->refcnt, 0);
1013
1038
        list_initialize(&dev->functions);
1014
1039
        link_initialize(&dev->driver_devices);
1015
 
        link_initialize(&dev->devman_dev);
1016
1040
        
1017
1041
        return dev;
1018
1042
}
1051
1075
                delete_dev_node(dev);
1052
1076
}
1053
1077
 
1054
 
 
1055
1078
/** Find the device node structure of the device witch has the specified handle.
1056
1079
 *
1057
1080
 * @param tree          The device tree where we look for the device node.
1060
1083
 */
1061
1084
dev_node_t *find_dev_node_no_lock(dev_tree_t *tree, devman_handle_t handle)
1062
1085
{
1063
 
        unsigned long key = handle;
1064
 
        link_t *link;
1065
 
        
1066
1086
        assert(fibril_rwlock_is_locked(&tree->rwlock));
1067
1087
        
1068
 
        link = hash_table_find(&tree->devman_devices, &key);
 
1088
        ht_link_t *link = hash_table_find(&tree->devman_devices, &handle);
1069
1089
        if (link == NULL)
1070
1090
                return NULL;
1071
1091
        
1072
 
        return hash_table_get_instance(link, dev_node_t, devman_dev);
 
1092
        return hash_table_get_inst(link, dev_node_t, devman_dev);
1073
1093
}
1074
1094
 
1075
1095
/** Find the device node structure of the device witch has the specified handle.
1141
1161
        
1142
1162
        fun->state = FUN_INIT;
1143
1163
        atomic_set(&fun->refcnt, 0);
 
1164
        fibril_mutex_initialize(&fun->busy_lock);
1144
1165
        link_initialize(&fun->dev_functions);
1145
1166
        list_initialize(&fun->match_ids.ids);
1146
 
        link_initialize(&fun->devman_fun);
1147
 
        link_initialize(&fun->loc_fun);
1148
1167
        
1149
1168
        return fun;
1150
1169
}
1185
1204
                delete_fun_node(fun);
1186
1205
}
1187
1206
 
 
1207
/** Make function busy for reconfiguration operations. */
 
1208
void fun_busy_lock(fun_node_t *fun)
 
1209
{
 
1210
        fibril_mutex_lock(&fun->busy_lock);
 
1211
}
 
1212
 
 
1213
/** Mark end of reconfiguration operation. */
 
1214
void fun_busy_unlock(fun_node_t *fun)
 
1215
{
 
1216
        fibril_mutex_unlock(&fun->busy_lock);
 
1217
}
 
1218
 
1188
1219
/** Find the function node with the specified handle.
1189
1220
 *
1190
1221
 * @param tree          The device tree where we look for the device node.
1193
1224
 */
1194
1225
fun_node_t *find_fun_node_no_lock(dev_tree_t *tree, devman_handle_t handle)
1195
1226
{
1196
 
        unsigned long key = handle;
1197
 
        link_t *link;
1198
1227
        fun_node_t *fun;
1199
1228
        
1200
1229
        assert(fibril_rwlock_is_locked(&tree->rwlock));
1201
1230
        
1202
 
        link = hash_table_find(&tree->devman_functions, &key);
 
1231
        ht_link_t *link = hash_table_find(&tree->devman_functions, &handle);
1203
1232
        if (link == NULL)
1204
1233
                return NULL;
1205
1234
        
1206
 
        fun = hash_table_get_instance(link, fun_node_t, devman_fun);
 
1235
        fun = hash_table_get_inst(link, fun_node_t, devman_fun);
1207
1236
        
1208
1237
        return fun;
1209
1238
}
1248
1277
        
1249
1278
        fun->pathname = (char *) malloc(pathsize);
1250
1279
        if (fun->pathname == NULL) {
1251
 
                log_msg(LVL_ERROR, "Failed to allocate device path.");
 
1280
                log_msg(LOG_DEFAULT, LVL_ERROR, "Failed to allocate device path.");
1252
1281
                return false;
1253
1282
        }
1254
1283
        
1276
1305
{
1277
1306
        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
1278
1307
        
1279
 
        log_msg(LVL_DEBUG, "insert_dev_node(dev=%p, pfun=%p [\"%s\"])",
 
1308
        log_msg(LOG_DEFAULT, LVL_DEBUG, "insert_dev_node(dev=%p, pfun=%p [\"%s\"])",
1280
1309
            dev, pfun, pfun->pathname);
1281
1310
 
1282
1311
        /* Add the node to the handle-to-node map. */
1283
1312
        dev->handle = ++tree->current_handle;
1284
 
        unsigned long key = dev->handle;
1285
 
        hash_table_insert(&tree->devman_devices, &key, &dev->devman_dev);
 
1313
        hash_table_insert(&tree->devman_devices, &dev->devman_dev);
1286
1314
 
1287
1315
        /* Add the node to the list of its parent's children. */
1288
1316
        dev->pfun = pfun;
1300
1328
{
1301
1329
        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
1302
1330
        
1303
 
        log_msg(LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
 
1331
        log_msg(LOG_DEFAULT, LVL_DEBUG, "remove_dev_node(dev=%p)", dev);
1304
1332
        
1305
1333
        /* Remove node from the handle-to-node map. */
1306
 
        unsigned long key = dev->handle;
1307
 
        hash_table_remove(&tree->devman_devices, &key, 1);
 
1334
        hash_table_remove(&tree->devman_devices, &dev->handle);
1308
1335
        
1309
1336
        /* Unlink from parent function. */
1310
1337
        dev->pfun->child = NULL;
1345
1372
        
1346
1373
        /* Add the node to the handle-to-node map. */
1347
1374
        fun->handle = ++tree->current_handle;
1348
 
        unsigned long key = fun->handle;
1349
 
        hash_table_insert(&tree->devman_functions, &key, &fun->devman_fun);
 
1375
        hash_table_insert(&tree->devman_functions, &fun->devman_fun);
1350
1376
 
1351
1377
        /* Add the node to the list of its parent's children. */
1352
1378
        fun->dev = dev;
1366
1392
        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
1367
1393
        
1368
1394
        /* Remove the node from the handle-to-node map. */
1369
 
        unsigned long key = fun->handle;
1370
 
        hash_table_remove(&tree->devman_functions, &key, 1);
 
1395
        hash_table_remove(&tree->devman_functions, &fun->handle);
1371
1396
        
1372
1397
        /* Remove the node from the list of its parent's children. */
1373
1398
        if (fun->dev != NULL)
1480
1505
fun_node_t *find_loc_tree_function(dev_tree_t *tree, service_id_t service_id)
1481
1506
{
1482
1507
        fun_node_t *fun = NULL;
1483
 
        link_t *link;
1484
 
        unsigned long key = (unsigned long) service_id;
1485
1508
        
1486
1509
        fibril_rwlock_read_lock(&tree->rwlock);
1487
 
        link = hash_table_find(&tree->loc_functions, &key);
 
1510
        ht_link_t *link = hash_table_find(&tree->loc_functions, &service_id);
1488
1511
        if (link != NULL) {
1489
 
                fun = hash_table_get_instance(link, fun_node_t, loc_fun);
 
1512
                fun = hash_table_get_inst(link, fun_node_t, loc_fun);
1490
1513
                fun_add_ref(fun);
1491
1514
        }
1492
1515
        fibril_rwlock_read_unlock(&tree->rwlock);
1498
1521
{
1499
1522
        assert(fibril_rwlock_is_write_locked(&tree->rwlock));
1500
1523
        
1501
 
        unsigned long key = (unsigned long) fun->service_id;
1502
 
        hash_table_insert(&tree->loc_functions, &key, &fun->loc_fun);
 
1524
        hash_table_insert(&tree->loc_functions, &fun->loc_fun);
1503
1525
}
1504
1526
 
1505
1527
/** @}