Changeset e1b6742 in mainline for kernel/generic/src/sysinfo/stats.c


Ignore:
Timestamp:
2010-04-18T12:17:11Z (14 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
e535eeb
Parents:
bbda5ab
Message:

export threads to user space
the "tasks" command can now print all threads or threads belonging to a task

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/sysinfo/stats.c

    rbbda5ab re1b6742  
    4040#include <time/clock.h>
    4141#include <mm/frame.h>
     42#include <proc/task.h>
    4243#include <proc/thread.h>
    4344#include <str.h>
     
    127128}
    128129
    129 /** Count number of tasks
    130  *
    131  * AVL task tree walker for counting tasks.
    132  *
    133  * @param node AVL task tree node (unused).
    134  * @param arg  Pointer to the counter.
     130/** Count number of nodes in an AVL tree
     131 *
     132 * AVL tree walker for counting nodes.
     133 *
     134 * @param node AVL tree node (unused).
     135 * @param arg  Pointer to the counter (size_t).
    135136 *
    136137 * @param Always true (continue the walk).
    137138 *
    138139 */
    139 static bool task_count_walker(avltree_node_t *node, void *arg)
     140static bool avl_count_walker(avltree_node_t *node, void *arg)
    140141{
    141142        size_t *count = (size_t *) arg;
     
    192193        /* First walk the task tree to count the tasks */
    193194        size_t count = 0;
    194         avltree_walk(&tasks_tree, task_count_walker, (void *) &count);
     195        avltree_walk(&tasks_tree, avl_count_walker, (void *) &count);
    195196       
    196197        if (count == 0) {
     
    228229       
    229230        return ((void *) task_ids);
     231}
     232
     233/** Gather threads
     234 *
     235 * AVL three tree walker for gathering thread IDs. Interrupts should
     236 * be already disabled while walking the tree.
     237 *
     238 * @param node AVL thread tree node.
     239 * @param arg  Pointer to the iterator into the array of thread IDs.
     240 *
     241 * @param Always true (continue the walk).
     242 *
     243 */
     244static bool thread_serialize_walker(avltree_node_t *node, void *arg)
     245{
     246        thread_id_t **ids = (thread_id_t **) arg;
     247        thread_t *thread = avltree_get_instance(node, thread_t, threads_tree_node);
     248       
     249        /* Interrupts are already disabled */
     250        spinlock_lock(&(thread->lock));
     251       
     252        /* Record the ID and increment the iterator */
     253        **ids = thread->tid;
     254        (*ids)++;
     255       
     256        spinlock_unlock(&(thread->lock));
     257       
     258        return true;
     259}
     260
     261/** Get thread IDs
     262 *
     263 * @param item    Sysinfo item (unused).
     264 * @param size    Size of the returned data.
     265 * @param dry_run Do not get the data, just calculate the size.
     266 *
     267 * @return Data containing thread IDs of all threads.
     268 *         If the return value is not NULL, it should be freed
     269 *         in the context of the sysinfo request.
     270 */
     271static void *get_stats_threads(struct sysinfo_item *item, size_t *size,
     272    bool dry_run)
     273{
     274        /* Messing with threads structures, avoid deadlock */
     275        ipl_t ipl = interrupts_disable();
     276        spinlock_lock(&threads_lock);
     277       
     278        /* First walk the thread tree to count the threads */
     279        size_t count = 0;
     280        avltree_walk(&threads_tree, avl_count_walker, (void *) &count);
     281       
     282        if (count == 0) {
     283                /* No threads found (strange) */
     284                spinlock_unlock(&threads_lock);
     285                interrupts_restore(ipl);
     286               
     287                *size = 0;
     288                return NULL;
     289        }
     290       
     291        *size = sizeof(thread_id_t) * count;
     292        if (dry_run) {
     293                spinlock_unlock(&threads_lock);
     294                interrupts_restore(ipl);
     295                return NULL;
     296        }
     297       
     298        thread_id_t *thread_ids = (thread_id_t *) malloc(*size, FRAME_ATOMIC);
     299        if (thread_ids == NULL) {
     300                /* No free space for allocation */
     301                spinlock_unlock(&threads_lock);
     302                interrupts_restore(ipl);
     303               
     304                *size = 0;
     305                return NULL;
     306        }
     307       
     308        /* Walk tha thread tree again to gather the IDs */
     309        thread_id_t *iterator = thread_ids;
     310        avltree_walk(&threads_tree, thread_serialize_walker, (void *) &iterator);
     311       
     312        spinlock_unlock(&threads_lock);
     313        interrupts_restore(ipl);
     314       
     315        return ((void *) thread_ids);
    230316}
    231317
     
    271357 * but it is still reasonable for the given purpose).
    272358 *
    273  * @param name Task ID (string-encoded number).
     359 * @param name    Task ID (string-encoded number).
     360 * @param dry_run Do not get the data, just calculate the size.
    274361 *
    275362 * @return Sysinfo return holder. The type of the returned
     
    281368 *
    282369 */
    283 static sysinfo_return_t get_stats_task(const char *name)
     370static sysinfo_return_t get_stats_task(const char *name, bool dry_run)
    284371{
    285372        /* Initially no return value */
     
    292379                return ret;
    293380       
    294         /* Allocate stats_task_t structure */
    295         stats_task_t *stats_task =
    296             (stats_task_t *) malloc(sizeof(stats_task_t), FRAME_ATOMIC);
    297         if (stats_task == NULL)
    298                 return ret;
    299        
    300381        /* Messing with task structures, avoid deadlock */
    301382        ipl_t ipl = interrupts_disable();
     
    307388                spinlock_unlock(&tasks_lock);
    308389                interrupts_restore(ipl);
    309                 free(stats_task);
    310390                return ret;
    311391        }
    312392       
    313         /* Hand-over-hand locking */
    314         spinlock_lock(&task->lock);
    315         spinlock_unlock(&tasks_lock);
    316        
    317         /* Copy task's statistics */
    318         str_cpy(stats_task->name, TASK_NAME_BUFLEN, task->name);
    319         stats_task->virtmem = get_task_virtmem(task->as);
    320         stats_task->threads = atomic_get(&task->refcount);
    321         task_get_accounting(task, &(stats_task->ucycles),
    322             &(stats_task->kcycles));
    323         stats_task->ipc_info = task->ipc_info;
    324        
    325         spinlock_unlock(&task->lock);
     393        if (dry_run) {
     394                ret.tag = SYSINFO_VAL_FUNCTION_DATA;
     395                ret.data.data = NULL;
     396                ret.data.size = sizeof(stats_task_t);
     397               
     398                spinlock_unlock(&tasks_lock);
     399        } else {
     400                /* Allocate stats_task_t structure */
     401                stats_task_t *stats_task =
     402                    (stats_task_t *) malloc(sizeof(stats_task_t), FRAME_ATOMIC);
     403                if (stats_task == NULL) {
     404                        spinlock_unlock(&tasks_lock);
     405                        interrupts_restore(ipl);
     406                        return ret;
     407                }
     408               
     409                /* Correct return value */
     410                ret.tag = SYSINFO_VAL_FUNCTION_DATA;
     411                ret.data.data = (void *) stats_task;
     412                ret.data.size = sizeof(stats_task_t);
     413       
     414                /* Hand-over-hand locking */
     415                spinlock_lock(&task->lock);
     416                spinlock_unlock(&tasks_lock);
     417               
     418                /* Copy task's statistics */
     419                str_cpy(stats_task->name, TASK_NAME_BUFLEN, task->name);
     420                stats_task->virtmem = get_task_virtmem(task->as);
     421                stats_task->threads = atomic_get(&task->refcount);
     422                task_get_accounting(task, &(stats_task->ucycles),
     423                    &(stats_task->kcycles));
     424                stats_task->ipc_info = task->ipc_info;
     425               
     426                spinlock_unlock(&task->lock);
     427        }
     428       
    326429        interrupts_restore(ipl);
    327430       
    328         /* Correct return value */
    329         ret.tag = SYSINFO_VAL_FUNCTION_DATA;
    330         ret.data.data = (void *) stats_task;
    331         ret.data.size = sizeof(stats_task_t);
     431        return ret;
     432}
     433
     434/** Get thread statistics
     435 *
     436 * Get statistics of a given thread. The thread ID is passed
     437 * as a string (current limitation of the sysinfo interface,
     438 * but it is still reasonable for the given purpose).
     439 *
     440 * @param name    Thread ID (string-encoded number).
     441 * @param dry_run Do not get the data, just calculate the size.
     442 *
     443 * @return Sysinfo return holder. The type of the returned
     444 *         data is either SYSINFO_VAL_UNDEFINED (unknown
     445 *         thread ID or memory allocation error) or
     446 *         SYSINFO_VAL_FUNCTION_DATA (in that case the
     447 *         generated data should be freed within the
     448 *         sysinfo request context).
     449 *
     450 */
     451static sysinfo_return_t get_stats_thread(const char *name, bool dry_run)
     452{
     453        /* Initially no return value */
     454        sysinfo_return_t ret;
     455        ret.tag = SYSINFO_VAL_UNDEFINED;
     456       
     457        /* Parse the thread ID */
     458        thread_id_t thread_id;
     459        if (str_uint64(name, NULL, 0, true, &thread_id) != EOK)
     460                return ret;
     461       
     462        /* Messing with threads structures, avoid deadlock */
     463        ipl_t ipl = interrupts_disable();
     464        spinlock_lock(&threads_lock);
     465       
     466        thread_t *thread = thread_find_by_id(thread_id);
     467        if (thread == NULL) {
     468                /* No thread with this ID */
     469                spinlock_unlock(&threads_lock);
     470                interrupts_restore(ipl);
     471                return ret;
     472        }
     473       
     474        if (dry_run) {
     475                ret.tag = SYSINFO_VAL_FUNCTION_DATA;
     476                ret.data.data = NULL;
     477                ret.data.size = sizeof(stats_thread_t);
     478               
     479                spinlock_unlock(&threads_lock);
     480        } else {
     481                /* Allocate stats_thread_t structure */
     482                stats_thread_t *stats_thread =
     483                    (stats_thread_t *) malloc(sizeof(stats_thread_t), FRAME_ATOMIC);
     484                if (stats_thread == NULL) {
     485                        spinlock_unlock(&threads_lock);
     486                        interrupts_restore(ipl);
     487                        return ret;
     488                }
     489               
     490                /* Correct return value */
     491                ret.tag = SYSINFO_VAL_FUNCTION_DATA;
     492                ret.data.data = (void *) stats_thread;
     493                ret.data.size = sizeof(stats_thread_t);
     494       
     495                /* Hand-over-hand locking */
     496                spinlock_lock(&thread->lock);
     497                spinlock_unlock(&threads_lock);
     498               
     499                /* Copy thread's statistics */
     500                stats_thread->task_id = thread->task->taskid;
     501                stats_thread->state = thread->state;
     502                stats_thread->priority = thread->priority;
     503                stats_thread->ucycles = thread->ucycles;
     504                stats_thread->kcycles = thread->kcycles;
     505               
     506                if (thread->cpu != NULL) {
     507                        stats_thread->on_cpu = true;
     508                        stats_thread->cpu = thread->cpu->id;
     509                } else
     510                        stats_thread->on_cpu = false;
     511               
     512                spinlock_unlock(&thread->lock);
     513        }
     514       
     515        interrupts_restore(ipl);
    332516       
    333517        return ret;
     
    477661        sysinfo_set_item_fn_data("system.load", NULL, get_stats_load);
    478662        sysinfo_set_item_fn_data("system.tasks", NULL, get_stats_tasks);
     663        sysinfo_set_item_fn_data("system.threads", NULL, get_stats_threads);
    479664        sysinfo_set_subtree_fn("system.tasks", NULL, get_stats_task);
     665        sysinfo_set_subtree_fn("system.threads", NULL, get_stats_thread);
    480666}
    481667
Note: See TracChangeset for help on using the changeset viewer.