/* $Header: /san01/cvs/ashpool/csrc/continuity/cont/tas.c,v 1.7 2004/05/14 06:20:32 eric Exp $ */

/* Copyright (c) 1994, 2004 Alex Leigh, All Rights Reserved
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF ALEX LEIGH
 * The copyright notice above does not evidence any
 * actual or intended publication of such source code.
 * 
 * Disclosure, copying, distribution, or transmission of
 * this code without express permission is prohibited.
 */

/*
 * Runtime Statistics Alex Leigh, 1995, 2000 $Id: stat.c,v 1.1 2000/04/08
 * 17:35:55 aleigh Exp $
 */

#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <pthread.h>
#include <sys/mman.h>
#include <uuid/uuid.h>

#include "continuity.h"

#define TA_STAT_STRLEN 32

#define TA_STAT_INT 1
#define TA_STAT_UINT 2
#define TA_STAT_CHAR 3

struct tasSstat {
    unsigned int tas_ctime;
    struct tasSstat *tas_next;

    char tas_module[TA_STAT_STRLEN];
    int tas_instance;
    char tas_name[TA_STAT_STRLEN];
    int tas_type;
    char tas_class[TA_STAT_STRLEN];
    unsigned char tas_flags;
    void *tas_data;
    size_t tas_data_size;
    unsigned int tas_ndata;
};

struct tasSctl {
    struct tasSstat *chain;
};


tasTctl *tasGctl;
pthread_mutex_t tasMctl = PTHREAD_MUTEX_INITIALIZER;

int tasFinit(void)
{
    tasGctl = (tasTctl *) malloc(sizeof(tasTctl));
    bzero(tasGctl, sizeof(tasTctl));
    return 0;
}

tasTstat *tasFget_chain(void)
{
    return tasGctl->chain;
}

tasTstat *tasFcreate(const char *module, int instance, const char *name,
                     const char *class, unsigned char type,
                     unsigned long ndata, unsigned char flag)
{
    tasTstat *tas;
    int size;

    tas = (tasTstat *) malloc(sizeof(tasTstat));
    bzero(tas, sizeof(tasTstat));

    strncpy(tas->tas_name, name, TA_STAT_STRLEN);
    strncpy(tas->tas_module, module, TA_STAT_STRLEN);
    strncpy(tas->tas_class, class, TA_STAT_STRLEN);

    tas->tas_instance = instance;
    tas->tas_type = type;
    tas->tas_flags = flag;
    tas->tas_ndata = ndata;

    switch (type) {
    case TA_STAT_INT:
        size = ndata * sizeof(int32_t);
        tas->tas_data = (int32_t *) malloc(size);
        bzero(tas->tas_data, size);
        break;

    case TA_STAT_UINT:
        size = ndata * sizeof(uint32_t);
        tas->tas_data = (uint32_t *) malloc(size);
        bzero(tas->tas_data, size);
        break;

    case TA_STAT_CHAR:
        tas->tas_data = (char *) malloc(ndata);
        bzero(tas->tas_data, ndata);
        break;
    }

    if (tas->tas_data == NULL) {
        free(tas);
        return NULL;
    }
    return tas;

}


tasTstat *tasFstat_lookup(tasTctl * ctl, const char *module,
                          int instance, const char *name)
{
    tasTstat *p;
    int match = 1;

    if (ctl->chain == NULL)
        return NULL;

    p = ctl->chain;

    while (1) {
        match = 1;

        if (module != NULL)
            if (strcmp(p->tas_module, module) != 0)
                match = 0;

        if (instance != -1)
            if (p->tas_instance != instance)
                match = 0;

        if (strcmp(p->tas_name, name) != 0)
            match = 0;

        if (match == 1)
            return p;

        if (p->tas_next == NULL)
            break;
        p = p->tas_next;
    }
    return NULL;
}

tasTstat *tasFlookup(char *module, int instance, char *name)
{
    return tasFstat_lookup(tasGctl, module, instance, name);
}


void tasFstat_free(tasTstat * statp)
{

    if (statp->tas_data != NULL)
        free(statp->tas_data);
    free(statp);

    return;
}

void tasFstat_install(tasTstat * statp)
{
    pthread_mutex_lock(&tasMctl);
    statp->tas_next = tasGctl->chain;
    tasGctl->chain = statp;
    pthread_mutex_unlock(&tasMctl);
}

void tasFstat_delete(tasTstat * statp)
{
    tasTstat *p;

    pthread_mutex_lock(&tasMctl);

    if (tasGctl->chain == NULL) {
        pthread_mutex_unlock(&tasMctl);
        tasFstat_free(statp);
        return;
    }
    if (tasGctl->chain == statp) {
        tasGctl->chain = statp->tas_next;
        pthread_mutex_unlock(&tasMctl);
        tasFstat_free(statp);
        return;
    }
    p = tasGctl->chain;
    while (1) {
        if (p->tas_next == statp) {
            p->tas_next = statp->tas_next;
            pthread_mutex_unlock(&tasMctl);
            tasFstat_free(statp);
            return;
        }
        if (p->tas_next == NULL)
            break;
        p = p->tas_next;
    }

    pthread_mutex_unlock(&tasMctl);
    tasFstat_free(statp);
    return;
}

int tasFstat_counter_add(const char *module, int instance,
                         const char *name, unsigned int value)
{
    tasTstat *p;
    unsigned int *ip;

    p = tasFstat_lookup(tasGctl, module, instance, name);
    if (p == NULL) {
        p = tasFcreate(module, instance, name, "cnt", TA_STAT_UINT, 1,
                       (unsigned char) NULL);
        ip = p->tas_data;
        *ip = value;
        tasFstat_install(p);
        return value;
    }
    ip = (unsigned int *) p->tas_data;
    *ip += value;

    return *ip;
}

int tasFstat_counter_sub(const char *module, int instance, const char *name,
                         unsigned int value)
{
    tasTstat *p;
    unsigned int *ip;

    p = tasFstat_lookup(tasGctl, module, instance, name);
    if (p == NULL) {
        p = tasFcreate(module, instance, name, "cnt", TA_STAT_UINT, 1,
                       (unsigned char) NULL);
        ip = p->tas_data;
        *ip = value;
        tasFstat_install(p);
        return value;
    }
    ip = (unsigned int *) p->tas_data;
    *ip -= value;

    return *ip;
}

int tasFstat_set(const char *module, int instance, const char *name,
                 unsigned int value)
{
    tasTstat *p;
    unsigned int *ip;

    p = tasFstat_lookup(tasGctl, module, instance, name);
    if (p == NULL) {
        p = tasFcreate(module, instance, name, "cnt", TA_STAT_UINT, 1,
                       (unsigned char) NULL);
        ip = p->tas_data;
        *ip = value;
        tasFstat_install(p);
        return value;
    }
    ip = (unsigned int *) p->tas_data;
    *ip = value;

    return *ip;
}
