source: mainline/kernel/generic/src/sysinfo/sysinfo.c@ 9dae191e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9dae191e was 9dae191e, checked in by Martin Decky <martin@…>, 15 years ago

sysinfo API cleanup

  • better support for generated subtrees
  • synchronization
  • memory management (generated items cleanup)
  • simplier sysinfo_dump()

remove separate statistical syscalls, replace with virtual sysinfo items (some functionality is still missing)

  • naming consolidation
  • cleaner API
  • proper synchronization

minor renames

  • zone_print_list() → zones_print_list()
  • zone_busy_and_free() → zones_stats()
  • Property mode set to 100644
File size: 14.4 KB
Line 
1/*
2 * Copyright (c) 2006 Jakub Vana
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 generic
30 * @{
31 */
32/** @file
33 */
34
35#include <sysinfo/sysinfo.h>
36#include <mm/slab.h>
37#include <print.h>
38#include <syscall/copy.h>
39#include <synch/spinlock.h>
40#include <errno.h>
41
42#define SYSINFO_MAX_PATH 2048
43
44bool fb_exported = false;
45
46static sysinfo_item_t *global_root = NULL;
47static slab_cache_t *sysinfo_item_slab;
48
49SPINLOCK_STATIC_INITIALIZE_NAME(sysinfo_lock, "sysinfo_lock");
50
51static int sysinfo_item_constructor(void *obj, int kmflag)
52{
53 sysinfo_item_t *item = (sysinfo_item_t *) obj;
54
55 item->name = NULL;
56 item->val_type = SYSINFO_VAL_UNDEFINED;
57 item->subtree_type = SYSINFO_SUBTREE_NONE;
58 item->subtree.table = NULL;
59 item->next = NULL;
60
61 return 0;
62}
63
64static int sysinfo_item_destructor(void *obj)
65{
66 sysinfo_item_t *item = (sysinfo_item_t *) obj;
67
68 if (item->name != NULL)
69 free(item->name);
70
71 return 0;
72}
73
74void sysinfo_init(void)
75{
76 sysinfo_item_slab = slab_cache_create("sysinfo_item_slab",
77 sizeof(sysinfo_item_t), 0, sysinfo_item_constructor,
78 sysinfo_item_destructor, SLAB_CACHE_MAGDEFERRED);
79}
80
81/** Recursively find item in sysinfo tree
82 *
83 * Should be called with interrupts disabled
84 * and sysinfo_lock held.
85 *
86 */
87static sysinfo_item_t *sysinfo_find_item(const char *name,
88 sysinfo_item_t *subtree, sysinfo_return_t **ret)
89{
90 ASSERT(subtree != NULL);
91 ASSERT(ret != NULL);
92
93 sysinfo_item_t *cur = subtree;
94
95 while (cur != NULL) {
96 size_t i = 0;
97
98 /* Compare name with path */
99 while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
100 i++;
101
102 /* Check for perfect name and path match */
103 if ((name[i] == 0) && (cur->name[i] == 0))
104 return cur;
105
106 /* Partial match up to the delimiter */
107 if ((name[i] == '.') && (cur->name[i] == 0)) {
108 /* Look into the subtree */
109 switch (cur->subtree_type) {
110 case SYSINFO_SUBTREE_TABLE:
111 /* Recursively find in subtree */
112 return sysinfo_find_item(name + i + 1,
113 cur->subtree.table, ret);
114 case SYSINFO_SUBTREE_FUNCTION:
115 /* Get generated data */
116 **ret = cur->subtree.get_data(name + i + 1);
117 return NULL;
118 default:
119 /* Not found */
120 *ret = NULL;
121 return NULL;
122 }
123 }
124
125 cur = cur->next;
126 }
127
128 *ret = NULL;
129 return NULL;
130}
131
132/** Recursively create items in sysinfo tree
133 *
134 * Should be called with interrupts disabled
135 * and sysinfo_lock held.
136 *
137 */
138static sysinfo_item_t *sysinfo_create_path(const char *name,
139 sysinfo_item_t **psubtree)
140{
141 ASSERT(psubtree != NULL);
142
143 if (*psubtree == NULL) {
144 /* No parent */
145
146 size_t i = 0;
147
148 /* Find the first delimiter in name */
149 while ((name[i] != 0) && (name[i] != '.'))
150 i++;
151
152 *psubtree =
153 (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
154 ASSERT(*psubtree);
155
156 /* Fill in item name up to the delimiter */
157 (*psubtree)->name = str_ndup(name, i);
158 ASSERT((*psubtree)->name);
159
160 /* Create subtree items */
161 if (name[i] == '.') {
162 (*psubtree)->subtree_type = SYSINFO_SUBTREE_TABLE;
163 return sysinfo_create_path(name + i + 1,
164 &((*psubtree)->subtree.table));
165 }
166
167 /* No subtree needs to be created */
168 return *psubtree;
169 }
170
171 sysinfo_item_t *cur = *psubtree;
172
173 while (cur != NULL) {
174 size_t i = 0;
175
176 /* Compare name with path */
177 while ((cur->name[i] != 0) && (name[i] == cur->name[i]))
178 i++;
179
180 /* Check for perfect name and path match
181 * -> item is already present.
182 */
183 if ((name[i] == 0) && (cur->name[i] == 0))
184 return cur;
185
186 /* Partial match up to the delimiter */
187 if ((name[i] == '.') && (cur->name[i] == 0)) {
188 switch (cur->subtree_type) {
189 case SYSINFO_SUBTREE_NONE:
190 /* No subtree yet, create one */
191 cur->subtree_type = SYSINFO_SUBTREE_TABLE;
192 return sysinfo_create_path(name + i + 1,
193 &(cur->subtree.table));
194 case SYSINFO_SUBTREE_TABLE:
195 /* Subtree already created, add new sibling */
196 return sysinfo_create_path(name + i + 1,
197 &(cur->subtree.table));
198 default:
199 /* Subtree items handled by a function, this
200 * cannot be overriden.
201 */
202 return NULL;
203 }
204 }
205
206 /* No match and no more siblings to check
207 * -> create a new sibling item.
208 */
209 if (cur->next == NULL) {
210 /* Find the first delimiter in name */
211 i = 0;
212 while ((name[i] != 0) && (name[i] != '.'))
213 i++;
214
215 sysinfo_item_t *item =
216 (sysinfo_item_t *) slab_alloc(sysinfo_item_slab, 0);
217 ASSERT(item);
218
219 cur->next = item;
220
221 /* Fill in item name up to the delimiter */
222 item->name = str_ndup(name, i);
223 ASSERT(item->name);
224
225 /* Create subtree items */
226 if (name[i] == '.') {
227 item->subtree_type = SYSINFO_SUBTREE_TABLE;
228 return sysinfo_create_path(name + i + 1,
229 &(item->subtree.table));
230 }
231
232 /* No subtree needs to be created */
233 return item;
234 }
235
236 /* Get next sibling */
237 cur = cur->next;
238 }
239
240 /* Unreachable */
241 ASSERT(false);
242 return NULL;
243}
244
245void sysinfo_set_item_val(const char *name, sysinfo_item_t **root,
246 unative_t val)
247{
248 ipl_t ipl = interrupts_disable();
249 spinlock_lock(&sysinfo_lock);
250
251 if (root == NULL)
252 root = &global_root;
253
254 sysinfo_item_t *item = sysinfo_create_path(name, root);
255 if (item != NULL) {
256 item->val_type = SYSINFO_VAL_VAL;
257 item->val.val = val;
258 }
259
260 spinlock_unlock(&sysinfo_lock);
261 interrupts_restore(ipl);
262}
263
264void sysinfo_set_item_data(const char *name, sysinfo_item_t **root,
265 void *data, size_t size)
266{
267 ipl_t ipl = interrupts_disable();
268 spinlock_lock(&sysinfo_lock);
269
270 if (root == NULL)
271 root = &global_root;
272
273 sysinfo_item_t *item = sysinfo_create_path(name, root);
274 if (item != NULL) {
275 item->val_type = SYSINFO_VAL_DATA;
276 item->val.data.data = data;
277 item->val.data.size = size;
278 }
279
280 spinlock_unlock(&sysinfo_lock);
281 interrupts_restore(ipl);
282}
283
284void sysinfo_set_item_fn_val(const char *name, sysinfo_item_t **root,
285 sysinfo_fn_val_t fn)
286{
287 ipl_t ipl = interrupts_disable();
288 spinlock_lock(&sysinfo_lock);
289
290 if (root == NULL)
291 root = &global_root;
292
293 sysinfo_item_t *item = sysinfo_create_path(name, root);
294 if (item != NULL) {
295 item->val_type = SYSINFO_VAL_FUNCTION_VAL;
296 item->val.fn_val = fn;
297 }
298
299 spinlock_unlock(&sysinfo_lock);
300 interrupts_restore(ipl);
301}
302
303void sysinfo_set_item_fn_data(const char *name, sysinfo_item_t **root,
304 sysinfo_fn_data_t fn)
305{
306 ipl_t ipl = interrupts_disable();
307 spinlock_lock(&sysinfo_lock);
308
309 if (root == NULL)
310 root = &global_root;
311
312 sysinfo_item_t *item = sysinfo_create_path(name, root);
313 if (item != NULL) {
314 item->val_type = SYSINFO_VAL_FUNCTION_DATA;
315 item->val.fn_data = fn;
316 }
317
318 spinlock_unlock(&sysinfo_lock);
319 interrupts_restore(ipl);
320}
321
322void sysinfo_set_item_undefined(const char *name, sysinfo_item_t **root)
323{
324 ipl_t ipl = interrupts_disable();
325 spinlock_lock(&sysinfo_lock);
326
327 if (root == NULL)
328 root = &global_root;
329
330 sysinfo_item_t *item = sysinfo_create_path(name, root);
331 if (item != NULL)
332 item->val_type = SYSINFO_VAL_UNDEFINED;
333
334 spinlock_unlock(&sysinfo_lock);
335 interrupts_restore(ipl);
336}
337
338void sysinfo_set_subtree_fn(const char *name, sysinfo_item_t **root,
339 sysinfo_fn_subtree_t fn)
340{
341 ipl_t ipl = interrupts_disable();
342 spinlock_lock(&sysinfo_lock);
343
344 if (root == NULL)
345 root = &global_root;
346
347 sysinfo_item_t *item = sysinfo_create_path(name, root);
348 if ((item != NULL) && (item->subtree_type != SYSINFO_SUBTREE_TABLE)) {
349 item->subtree_type = SYSINFO_SUBTREE_FUNCTION;
350 item->subtree.get_data = fn;
351 }
352
353 spinlock_unlock(&sysinfo_lock);
354 interrupts_restore(ipl);
355}
356
357/** Sysinfo dump indentation helper routine
358 *
359 */
360static void sysinfo_indent(unsigned int depth)
361{
362 unsigned int i;
363 for (i = 0; i < depth; i++)
364 printf(" ");
365}
366
367/** Dump the structure of sysinfo tree
368 *
369 * Should be called with interrupts disabled
370 * and sysinfo_lock held. Because this routine
371 * might take a reasonable long time to proceed,
372 * having the spinlock held is not optimal, but
373 * there is no better simple solution.
374 *
375 */
376static void sysinfo_dump_internal(sysinfo_item_t *root, unsigned int depth)
377{
378 sysinfo_item_t *cur = root;
379
380 while (cur != NULL) {
381 sysinfo_indent(depth);
382
383 unative_t val;
384 void *data;
385 size_t size;
386
387 switch (cur->val_type) {
388 case SYSINFO_VAL_UNDEFINED:
389 printf("+ %s\n", cur->name);
390 break;
391 case SYSINFO_VAL_VAL:
392 printf("+ %s -> %" PRIun" (%#" PRIxn ")\n", cur->name,
393 cur->val.val, cur->val.val);
394 break;
395 case SYSINFO_VAL_DATA:
396 printf("+ %s (%" PRIs" bytes)\n", cur->name,
397 cur->val.data.size);
398 break;
399 case SYSINFO_VAL_FUNCTION_VAL:
400 val = cur->val.fn_val(cur);
401 printf("+ %s -> %" PRIun" (%#" PRIxn ") [generated]\n",
402 cur->name, val, val);
403 break;
404 case SYSINFO_VAL_FUNCTION_DATA:
405 data = cur->val.fn_data(cur, &size);
406 if (data != NULL)
407 free(data);
408
409 printf("+ %s (%" PRIs" bytes) [generated]\n", cur->name,
410 size);
411 break;
412 default:
413 printf("+ %s [unknown]\n", cur->name);
414 }
415
416 switch (cur->subtree_type) {
417 case SYSINFO_SUBTREE_NONE:
418 break;
419 case SYSINFO_SUBTREE_TABLE:
420 sysinfo_dump_internal(cur->subtree.table, depth + 1);
421 break;
422 case SYSINFO_SUBTREE_FUNCTION:
423 sysinfo_indent(depth + 1);
424 printf("+ [generated subtree]\n");
425 break;
426 default:
427 sysinfo_indent(depth + 1);
428 printf("+ [unknown subtree]\n");
429 }
430
431 cur = cur->next;
432 }
433}
434
435void sysinfo_dump(sysinfo_item_t *root)
436{
437 ipl_t ipl = interrupts_disable();
438 spinlock_lock(&sysinfo_lock);
439
440 if (root == NULL)
441 sysinfo_dump_internal(global_root, 0);
442 else
443 sysinfo_dump_internal(root, 0);
444
445 spinlock_unlock(&sysinfo_lock);
446 interrupts_restore(ipl);
447}
448
449/** Return sysinfo item determined by name
450 *
451 * Should be called with interrupts disabled
452 * and sysinfo_lock held.
453 *
454 */
455static sysinfo_return_t sysinfo_get_item(const char *name, sysinfo_item_t **root)
456{
457 if (root == NULL)
458 root = &global_root;
459
460 sysinfo_return_t ret;
461 sysinfo_return_t *ret_ptr = &ret;
462 sysinfo_item_t *item = sysinfo_find_item(name, *root, &ret_ptr);
463
464 if (item != NULL) {
465 ret.tag = item->val_type;
466 switch (item->val_type) {
467 case SYSINFO_VAL_UNDEFINED:
468 break;
469 case SYSINFO_VAL_VAL:
470 ret.val = item->val.val;
471 break;
472 case SYSINFO_VAL_DATA:
473 ret.data = item->val.data;
474 break;
475 case SYSINFO_VAL_FUNCTION_VAL:
476 ret.val = item->val.fn_val(item);
477 break;
478 case SYSINFO_VAL_FUNCTION_DATA:
479 ret.data.data = item->val.fn_data(item, &ret.data.size);
480 break;
481 }
482 } else {
483 if (ret_ptr == NULL)
484 ret.tag = SYSINFO_VAL_UNDEFINED;
485 }
486
487 return ret;
488}
489
490/** Return sysinfo item determined by name from user space
491 *
492 * Should be called with interrupts disabled
493 * and sysinfo_lock held.
494 *
495 */
496static sysinfo_return_t sysinfo_get_item_uspace(void *ptr, size_t size)
497{
498 sysinfo_return_t ret;
499 ret.tag = SYSINFO_VAL_UNDEFINED;
500
501 if (size > SYSINFO_MAX_PATH)
502 return ret;
503
504 char *path = (char *) malloc(size + 1, 0);
505 ASSERT(path);
506
507 if ((copy_from_uspace(path, ptr, size + 1) == 0)
508 && (path[size] == 0))
509 ret = sysinfo_get_item(path, NULL);
510
511 free(path);
512 return ret;
513}
514
515unative_t sys_sysinfo_get_tag(void *path_ptr, size_t path_size)
516{
517 ipl_t ipl = interrupts_disable();
518 spinlock_lock(&sysinfo_lock);
519
520 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size);
521
522 if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
523 free(ret.data.data);
524
525 if (ret.tag == SYSINFO_VAL_FUNCTION_VAL)
526 ret.tag = SYSINFO_VAL_VAL;
527 else if (ret.tag == SYSINFO_VAL_FUNCTION_DATA)
528 ret.tag = SYSINFO_VAL_DATA;
529
530 spinlock_unlock(&sysinfo_lock);
531 interrupts_restore(ipl);
532
533 return (unative_t) ret.tag;
534}
535
536unative_t sys_sysinfo_get_value(void *path_ptr, size_t path_size,
537 void *value_ptr)
538{
539 ipl_t ipl = interrupts_disable();
540 spinlock_lock(&sysinfo_lock);
541
542 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size);
543 int rc;
544
545 if ((ret.tag == SYSINFO_VAL_VAL) || (ret.tag == SYSINFO_VAL_FUNCTION_VAL))
546 rc = copy_to_uspace(value_ptr, &ret.val, sizeof(ret.val));
547 else
548 rc = EINVAL;
549
550 if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
551 free(ret.data.data);
552
553 spinlock_unlock(&sysinfo_lock);
554 interrupts_restore(ipl);
555
556 return (unative_t) rc;
557}
558
559unative_t sys_sysinfo_get_data_size(void *path_ptr, size_t path_size,
560 void *size_ptr)
561{
562 ipl_t ipl = interrupts_disable();
563 spinlock_lock(&sysinfo_lock);
564
565 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size);
566 int rc;
567
568 if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA))
569 rc = copy_to_uspace(size_ptr, &ret.data.size,
570 sizeof(ret.data.size));
571 else
572 rc = EINVAL;
573
574 if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
575 free(ret.data.data);
576
577 spinlock_unlock(&sysinfo_lock);
578 interrupts_restore(ipl);
579
580 return (unative_t) rc;
581}
582
583unative_t sys_sysinfo_get_data(void *path_ptr, size_t path_size,
584 void *buffer_ptr, size_t buffer_size)
585{
586 ipl_t ipl = interrupts_disable();
587 spinlock_lock(&sysinfo_lock);
588
589 sysinfo_return_t ret = sysinfo_get_item_uspace(path_ptr, path_size);
590 int rc;
591
592 if ((ret.tag == SYSINFO_VAL_DATA) || (ret.tag == SYSINFO_VAL_FUNCTION_DATA)) {
593 if (ret.data.size == buffer_size)
594 rc = copy_to_uspace(buffer_ptr, ret.data.data,
595 ret.data.size);
596 else
597 rc = ENOMEM;
598 } else
599 rc = EINVAL;
600
601 if ((ret.tag == SYSINFO_VAL_FUNCTION_DATA) && (ret.data.data != NULL))
602 free(ret.data.data);
603
604 spinlock_unlock(&sysinfo_lock);
605 interrupts_restore(ipl);
606
607 return (unative_t) rc;
608}
609
610/** @}
611 */
Note: See TracBrowser for help on using the repository browser.