| /* |
| * 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 (c) 1985-2001 by Sun Microsystems, Inc. |
| * All rights reserved. |
| */ |
| |
| #pragma ident "%Z%%M% %I% %E% SMI" |
| |
| /* |
| * Vuid_store.c - Implement the vuid_store.h event storage interface. |
| */ |
| |
| #include <sys/types.h> |
| #include <sys/time.h> |
| #include <sys/kmem.h> |
| #include <sys/systm.h> |
| #include <sys/disp.h> |
| #include <sys/vuid_event.h> |
| #include <sys/vuid_state.h> |
| #include <sys/vuid_store.h> |
| |
| static void vuid_destroy_seg(); |
| static Vuid_seg * vuid_copy_seg(); |
| static Vuid_seg * vuid_find_seg(); |
| static Vuid_value * vuid_add_value(); |
| static Vuid_value * vuid_find_value(); |
| |
| #ifdef _KERNEL |
| #define vuid_alloc(bytes) \ |
| kmem_alloc((bytes), servicing_interrupt()) |
| #define vuid_free(ptr, bytes) kmem_free((ptr), (bytes)) |
| #else |
| #define vuid_alloc(bytes) malloc((bytes)) |
| #define vuid_free(ptr, bytes) free((ptr)) |
| #endif /* _KERNEL */ |
| |
| void |
| vuid_set_value(client_state_ptr, event) |
| Vuid_state *client_state_ptr; |
| register Firm_event *event; |
| { |
| Vuid_seg **state_ptr = (Vuid_seg **)client_state_ptr; |
| Vuid_seg *state = *state_ptr; |
| register Vuid_seg *seg; |
| register Vuid_value *val_node; |
| register Vuid_value *pair_val_node; |
| register ushort_t offset = vuid_id_offset(event->id); |
| register ushort_t pair = event->pair; |
| int int_bit, val_original; |
| |
| /* Get (search for) seg from state assoicated with event */ |
| if ((seg = vuid_find_seg(state, vuid_id_addr(event->id))) == |
| VUID_SEG_NULL) { |
| /* Allocate and initialize new seg for event */ |
| seg = (Vuid_seg *) vuid_alloc(sizeof (*seg)); |
| bzero((caddr_t)seg, sizeof (*seg)); |
| seg->addr = vuid_id_addr(event->id); |
| /* Add the seg to state */ |
| *state_ptr = seg; |
| seg->next = state; |
| } |
| int_bit = vuid_get_int_bit(seg, offset); |
| /* See if no value node and event value is not boolean */ |
| if ((!int_bit) && vuid_int_value(event->value)) { |
| (void) vuid_add_value(seg, offset); |
| int_bit = 1; |
| } |
| /* If boolean event then set boolean bit */ |
| if (!int_bit) { |
| if (event->value) |
| vuid_set_boolean_bit(seg, offset); |
| else |
| vuid_clear_boolean_bit(seg, offset); |
| } else { |
| /* Get (search for) value node (should be there) */ |
| val_node = vuid_find_value(seg, offset); |
| val_original = val_node->value; |
| val_node->value = event->value; |
| switch (event->pair_type) { |
| |
| case FE_PAIR_DELTA: |
| /* See if value node for pair */ |
| if (!vuid_get_int_bit(seg, pair)) |
| (void) vuid_add_value(seg, pair); |
| /* Get (search for) value node (should be there) */ |
| pair_val_node = vuid_find_value(seg, pair); |
| /* Set pair value to difference */ |
| pair_val_node->value = event->value - val_original; |
| break; |
| |
| case FE_PAIR_ABSOLUTE: |
| /* See if value node for pair */ |
| if (!vuid_get_int_bit(seg, pair)) |
| (void) vuid_add_value(seg, pair); |
| /* Get (search for) value node (should be there) */ |
| pair_val_node = vuid_find_value(seg, pair); |
| /* Add event value to pair value */ |
| pair_val_node->value += event->value; |
| break; |
| |
| default: |
| {} |
| } |
| } |
| /* Recursively call vuid_set_value if there is an associated pair */ |
| if (event->pair_type == FE_PAIR_SET) { |
| Firm_event pair_event; |
| |
| pair_event = *event; |
| pair_event.id = vuid_id_addr(event->id) | pair; |
| pair_event.pair_type = FE_PAIR_NONE; |
| pair_event.pair = 0; |
| vuid_set_value(client_state_ptr, &pair_event); |
| } |
| } |
| |
| int |
| vuid_get_value(client_state, id) |
| Vuid_state client_state; |
| ushort_t id; |
| { |
| Vuid_seg *state = vuid_cstate_to_state(client_state); |
| register Vuid_seg *seg; |
| Vuid_value *val_node; |
| register ushort_t offset = vuid_id_offset(id); |
| |
| /* Get (search for) seg from state assoicated with id */ |
| if ((seg = vuid_find_seg(state, vuid_id_addr(id))) == VUID_SEG_NULL) |
| return (0); |
| /* If boolean event (i.e., no ints bit on) then return boolean value */ |
| if (!vuid_get_int_bit(seg, offset)) |
| return (vuid_get_boolean_bit(seg, offset) != 0); |
| else { |
| /* Get (search for) value node and return value */ |
| val_node = vuid_find_value(seg, offset); |
| return (val_node->value); |
| } |
| } |
| |
| void |
| vuid_destroy_state(client_state) |
| Vuid_state client_state; |
| { |
| Vuid_seg *state = vuid_cstate_to_state(client_state); |
| register Vuid_seg *seg; |
| Vuid_seg *seg_next; |
| |
| for (seg = state; seg; seg = seg_next) { |
| seg_next = seg->next; |
| vuid_destroy_seg(seg); |
| } |
| } |
| |
| static void |
| vuid_destroy_seg(seg) |
| Vuid_seg *seg; |
| { |
| register Vuid_value *val_node; |
| Vuid_value *val_node_next; |
| |
| for (val_node = seg->list; val_node; val_node = val_node_next) { |
| val_node_next = val_node->next; |
| vuid_free((caddr_t)val_node, sizeof (Vuid_value)); |
| } |
| vuid_free((caddr_t)seg, sizeof (Vuid_seg)); |
| } |
| |
| Vuid_state |
| vuid_copy_state(client_state) |
| Vuid_state client_state; |
| { |
| Vuid_seg *state = vuid_cstate_to_state(client_state); |
| register Vuid_seg *seg; |
| Vuid_seg *new_first_seg = VUID_SEG_NULL; |
| register Vuid_seg *new_previous_seg = VUID_SEG_NULL; |
| register Vuid_seg *new_seg; |
| |
| for (seg = state; seg; seg = seg->next) { |
| new_seg = vuid_copy_seg(seg); |
| /* Remember first seg as state */ |
| if (new_first_seg == VUID_SEG_NULL) |
| new_first_seg = new_seg; |
| /* Link segs together */ |
| if (new_previous_seg != VUID_SEG_NULL) |
| new_previous_seg->next = new_seg; |
| /* Remember seg for linking later */ |
| new_previous_seg = new_seg; |
| } |
| return ((Vuid_state) new_first_seg); |
| } |
| |
| static Vuid_seg * |
| vuid_copy_seg(seg) |
| Vuid_seg *seg; |
| { |
| register Vuid_value *val_node; |
| Vuid_seg *new_seg; |
| register Vuid_value *new_previous_val = VUID_VALUE_NULL; |
| register Vuid_value *new_val; |
| |
| /* Allocate and initialize new seg for event */ |
| new_seg = (Vuid_seg *) vuid_alloc(sizeof (*seg)); |
| *new_seg = *seg; |
| /* Terminate new pointer with null */ |
| new_seg->next = VUID_SEG_NULL; |
| new_seg->list = VUID_VALUE_NULL; |
| /* Copy list elements */ |
| for (val_node = seg->list; val_node; val_node = val_node->next) { |
| new_val = (Vuid_value *) vuid_alloc(sizeof (*new_val)); |
| *new_val = *val_node; |
| new_val->next = VUID_VALUE_NULL; |
| /* Remember first value as head of list */ |
| if (new_seg->list == VUID_VALUE_NULL) |
| new_seg->list = new_val; |
| /* Link vals together */ |
| if (new_previous_val != VUID_VALUE_NULL) |
| new_previous_val->next = new_val; |
| /* Remember val for linking later */ |
| new_previous_val = new_val; |
| } |
| return (new_seg); |
| } |
| |
| static Vuid_seg * |
| vuid_find_seg(state, addr) |
| Vuid_seg *state; |
| ushort_t addr; |
| { |
| register Vuid_seg *seg; |
| |
| for (seg = state; seg; seg = seg->next) { |
| if (seg->addr == addr) |
| return (seg); |
| } |
| return (VUID_SEG_NULL); |
| } |
| |
| static Vuid_value * |
| vuid_find_value(seg, offset) |
| Vuid_seg *seg; |
| ushort_t offset; |
| { |
| register Vuid_value *val_node; |
| |
| for (val_node = seg->list; val_node; val_node = val_node->next) { |
| if (vuid_id_offset(val_node->offset) == offset) |
| return (val_node); |
| } |
| return (VUID_VALUE_NULL); |
| } |
| |
| static Vuid_value * |
| vuid_add_value(seg, offset) |
| Vuid_seg *seg; |
| ushort_t offset; |
| { |
| Vuid_value *list_tmp; |
| Vuid_value *val_node; |
| |
| /* Allocate and initialize new value node for event */ |
| val_node = (Vuid_value *) vuid_alloc(sizeof (*val_node)); |
| bzero((caddr_t)val_node, sizeof (*val_node)); |
| val_node->offset = offset; |
| /* Add the value node to list */ |
| list_tmp = seg->list; |
| seg->list = val_node; |
| val_node->next = list_tmp; |
| vuid_set_int_bit(seg, offset); |
| /* Clear boolean bit for event */ |
| vuid_clear_boolean_bit(seg, offset); |
| return (val_node); |
| } |