root/usr/src/cmd/prstat/prsort.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 * Copyright 2012 Joyent, Inc.  All rights reserved.
 */

#include <libintl.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

#include "prstat.h"
#include "prutil.h"
#include "prsort.h"

void
list_alloc(list_t *list, int size)
{
        list->l_size = size;
        if (size > 0)
                list->l_ptrs = Zalloc(sizeof (void *) * (size + 1));
        else
                list->l_ptrs = NULL;
}

void
list_free(list_t *list)
{
        if (list && list->l_ptrs) {
                free(list->l_ptrs);
                list->l_ptrs = NULL;
        }
}

/*
 * Sorting routines
 */
static ulong_t
get_cpu_from_psinfo(void *lwp)
{
        return ((ulong_t)
            FRC2PCT((((lwp_info_t *)lwp)->li_info.pr_lwp.pr_pctcpu)*1000));
}

static ulong_t
get_cpu_from_usage(void *lwp)
{
        lwp_info_t *p = (lwp_info_t *)lwp;
        float cpu = 0;
        cpu += p->li_usr;
        cpu += p->li_sys;
        cpu *= 1000;
        return ((ulong_t)cpu);
}

static ulong_t
get_time(void *lwp)
{
        return ((ulong_t)TIME2SEC(((lwp_info_t *)lwp)->li_info.pr_lwp.pr_time));
}

static ulong_t
get_size(void *lwp)
{
        return ((ulong_t)((lwp_info_t *)lwp)->li_info.pr_size);
}

static ulong_t
get_rssize(void *lwp)
{
        return ((ulong_t)((lwp_info_t *)lwp)->li_info.pr_rssize);
}

static ulong_t
get_pri(void *lwp)
{
        return ((ulong_t)((lwp_info_t *)lwp)->li_info.pr_lwp.pr_pri);
}

static ulong_t
get_idkey(void *id)
{
        return (((id_info_t *)id)->id_key);
}

void
list_setkeyfunc(char *arg, optdesc_t *opt, list_t *list, int type)
{
        if (list == NULL)
                return;

        list->l_sortorder = opt->o_sortorder;
        list->l_type = type;
        if (arg == NULL) {      /* special case for id_infos */
                list->l_func = get_idkey;
                return;
        }
        if (strcmp("cpu", arg) == 0) {
                if (opt->o_outpmode & OPT_MSACCT)
                        list->l_func = get_cpu_from_usage;
                else
                        list->l_func = get_cpu_from_psinfo;
                return;
        }
        if (strcmp("time", arg) == 0) {
                list->l_func = get_time;
                return;
        }
        if (strcmp("size", arg) == 0) {
                list->l_func = get_size;
                return;
        }
        if (strcmp("rss", arg) == 0) {
                list->l_func = get_rssize;
                return;
        }
        if (strcmp("pri", arg) == 0) {
                list->l_func = get_pri;
                return;
        }
        Die(gettext("invalid sort key -- %s\n"), arg);
}

ulong_t
list_getkeyval(list_t *list, void *ptr)
{
        return (list->l_func(ptr));
}

static int
compare_keys(list_t *list, ulong_t key1, ulong_t key2)
{
        if (key1 == key2)
                return (0);
        if (key1 < key2)
                return (1 * list->l_sortorder);
        else
                return (-1 * list->l_sortorder);
}

static void
list_insert(list_t *list, void *ptr)
{
        int i, j;
        long k1, k2;

        for (i = 0; i < list->l_used; i++) {    /* insert in the middle */
                k1 = list_getkeyval(list, ptr);
                k2 = list_getkeyval(list, list->l_ptrs[i]);
                if (compare_keys(list, k1, k2) >= 0) {
                        for (j = list->l_used - 1; j >= i; j--)
                                list->l_ptrs[j+1] = list->l_ptrs[j];
                        list->l_ptrs[i] = ptr;
                        if (list->l_used < list->l_size)
                                list->l_used++;
                        return;
                }
        }
        if (i + 1 <= list->l_size) {            /* insert at the tail */
                list->l_ptrs[list->l_used] = ptr;

                list->l_used++;
        }
}

static void
list_preinsert(list_t *list, void *ptr)
{
        ulong_t k1, k2;

        if (list->l_used < list->l_size) {      /* just add */
                list_insert(list, ptr);
                return;
        }
        k1 = list_getkeyval(list, list->l_ptrs[list->l_used - 1]);
        k2 = list_getkeyval(list, ptr);
        if (compare_keys(list, k1, k2) >= 0)    /* skip insertion */
                return;
        k1 = list_getkeyval(list, list->l_ptrs[0]);
        if (compare_keys(list, k2, k1) >= 0) {  /* add at the head */
                list_insert(list, ptr);
                return;
        }
        list_insert(list, ptr);
}

void
list_sort(list_t *list)
{
        list->l_used = 0;
        if (list->l_size == 0)
                return;

        (void) memset(list->l_ptrs, 0, sizeof (void *) * list->l_size);

        if (list->l_type == LT_LWPS) {
                lwp_info_t *lwp = list->l_head;

                while (lwp) {
                        list_preinsert(list, (void *)lwp);
                        lwp = lwp->li_next;
                }
        } else {
                id_info_t *id = list->l_head;

                while (id) {
                        list_preinsert(list, (void *)id);
                        id = id->id_next;
                }
        }
}