17421 name key order preservation
17422 rad dynamic namespace support
17423 rad kstat module
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/apis/kstat.xml Tue Nov 23 15:54:20 2010 -0800
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!--
+ Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (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
+-->
+
+<interface xmlns="http://www.opensolaris.org/ns/adr" name="kstat">
+
+ <pragma domain="java" name="package" value="org.opensolaris.os.kstat" />
+
+ <!-- Example of where it would be nice to have a native union type -->
+ <type name="union">
+ <field type="string" name="str" optional="true" />
+ <field type="integer" name="i32" />
+ <field type="uinteger" name="ui32" />
+ <field type="long" name="i64" />
+ <field type="ulong" name="ui64" />
+ <field type="float" name="f" />
+ <field type="double" name="d" />
+ </type>
+
+ <enum name="ksdtype">
+ <value name="char" />
+ <value name="int32" />
+ <value name="uint32" />
+ <value name="int64" />
+ <value name="uint64" />
+ <value name="float" />
+ <value name="double" />
+ <value name="string" />
+ </enum>
+
+ <enum name="kstype">
+ <value name="raw" />
+ <value name="named" />
+ <value name="intr" />
+ <value name="io" />
+ <value name="timer" />
+ </enum>
+
+ <type name="statistic">
+ <field type="string" name="name" />
+ <field typeref="ksdtype" name="type" />
+ <field typeref="union" name="value" />
+ </type>
+
+ <type name="snapshot">
+ <field type="ulong" name="timestamp" />
+ <field name="statistics">
+ <list typeref="statistic" />
+ </field>
+ </type>
+
+ <api name="kstat">
+ <version major="0" minor="1" />
+
+ <property type="string" name="module" access="ro" />
+ <property type="string" name="name" access="ro" />
+ <property type="string" name="class" access="ro" />
+ <property type="integer" name="instance" access="ro" />
+ <property typeref="kstype" name="kstatType" access="ro" />
+ <property type="ulong" name="creationTime" access="ro" />
+ <property type="boolean" name="stale" access="ro" />
+
+ <property typeref="snapshot" name="value" access="ro">
+ <!-- Stale handle or kstatType != named -->
+ <error />
+ </property>
+
+ <method name="get_fresh_value">
+ <result typeref="snapshot" />
+ <!-- Stale handle or kstatType != named -->
+ <error />
+ </method>
+ </api>
+
+ <api name="kstatctl">
+ <version major="0" minor="1" />
+
+ <method name="update_all" />
+ </api>
+</interface>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/pyclient/kstat_demo.py Tue Nov 23 15:54:20 2010 -0800
@@ -0,0 +1,46 @@
+#!/usr/bin/python2.6
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+import kstat.rad
+import time
+
+last = [ 0, 0, 0, 0 ]
+flds = [ "cpu_nsec_idle", "cpu_nsec_user", "cpu_nsec_kernel", "cpu_nsec_intr" ]
+frmt = "Idle: %.2f%% User: %.2f%% Kern: %.2f%% Intr: %.2f%%"
+
+def print_diff(prev, next):
+ diffs = [ next[i] - prev[i] for i in range(4) ]
+ total = sum(diffs)
+ print frmt % tuple([ float(x) * 100 / total for x in diffs ])
+
+stats = kstat.rad.Kstats() # get kstat connection
+cpu = stats.lookup("cpu", "sys", 0) # get cpu 0's kstat object
+
+while True:
+ stats.update() # update kstats
+ s = cpu.value # fetch new kstat
+ this = [ s.get(x) for x in flds ] # pick out interesting stats
+ print_diff(last, this) # pretty-print
+ last = this # new is now old
+ time.sleep(1) # wait
--- a/usr/src/cmd/rad/mdb/rad.c Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/rad/mdb/rad.c Tue Nov 23 15:54:20 2010 -0800
@@ -23,6 +23,8 @@
*/
#include <sys/mdb_modapi.h>
+#include <sys/list_impl.h>
+#include <stddef.h>
#include "../rad_object.h"
#include "../rad_container.h"
@@ -75,9 +77,9 @@
}
typedef struct iwalk_data {
- int iwd_n;
- int iwd_i;
- uintptr_t *iwd_instances;
+ size_t iwd_offset;
+ uintptr_t iwd_next;
+ uintptr_t iwd_start;
} iwalk_data_t;
static int
@@ -91,18 +93,19 @@
return (WALK_ERR);
}
- size_t isize = cont.c_ninstances * sizeof (uintptr_t);
- uintptr_t *instances = mdb_alloc(isize, UM_SLEEP | UM_GC);
- iwalk_data_t *data = mdb_alloc(sizeof (iwalk_data_t), UM_SLEEP | UM_GC);
-
- if (mdb_vread(instances, isize, (uintptr_t)cont.c_instances) == -1) {
- mdb_warn("failed to read instance array");
+ if (cont.c_instances.list_offset != offsetof(rad_instance_t, i_cnode) ||
+ cont.c_instances.list_size != sizeof (rad_instance_t)) {
+ mdb_warn("invalid/corrupt rad_container_t or "
+ "mismatched mdb module\n");
return (WALK_ERR);
}
- data->iwd_i = 0;
- data->iwd_n = cont.c_ninstances;
- data->iwd_instances = instances;
+ /* Unfortunately, the list_t walker is buried in the genunix module */
+ iwalk_data_t *data = mdb_alloc(sizeof (iwalk_data_t), UM_SLEEP | UM_GC);
+ data->iwd_offset = cont.c_instances.list_offset;
+ data->iwd_next = (uintptr_t)cont.c_instances.list_head.list_next;
+ data->iwd_start =
+ wsp->walk_addr + offsetof(rad_container_t, c_instances.list_head);
wsp->walk_data = data;
return (WALK_NEXT);
@@ -115,15 +118,16 @@
uintptr_t addr;
rad_instance_t inst;
- if (data->iwd_i >= data->iwd_n)
+ if (data->iwd_next == data->iwd_start)
return (WALK_DONE);
- addr = data->iwd_instances[data->iwd_i++];
+ addr = data->iwd_next - data->iwd_offset;
if (mdb_vread(&inst, sizeof (rad_instance_t), addr) == -1) {
mdb_warn("error reading rad_instance_t at %p, skipping\n",
addr);
return (WALK_NEXT);
}
+ data->iwd_next = (uintptr_t)inst.i_cnode.list_next;
return (wsp->walk_callback(addr, &inst, wsp->walk_cbdata));
}
--- a/usr/src/cmd/rad/mod/Makefile Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/rad/mod/Makefile Tue Nov 23 15:54:20 2010 -0800
@@ -30,6 +30,7 @@
MODULE_SUBDIRS = \
example-time2 \
files \
+ kstat \
network \
panels \
sharemgr \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/rad/mod/kstat/Makefile Tue Nov 23 15:54:20 2010 -0800
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include ../Makefile.env
+
+LDLIBS += -lkstat
+MOD_APIS=kstat
+MOD_OBJS=kstat.o
+MOD_LIBNAME=kstat.so
+MOD_INSTALLDIR=$(RADDIR_MODULE)
+
+include ../Makefile.com
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/rad/mod/kstat/kstat.c Tue Nov 23 15:54:20 2010 -0800
@@ -0,0 +1,504 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include <sys/list.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <kstat.h>
+#include <pthread.h>
+#include <string.h>
+#include <assert.h>
+
+#include <rad/adr.h>
+#include <rad/adr_object.h>
+#include <rad/rad_modapi.h>
+
+#include "api_kstat.h"
+
+#define KSTAT_DOMAIN "com.oracle.solaris.kstat"
+
+static pthread_mutex_t kstat_lock = PTHREAD_MUTEX_INITIALIZER;
+static list_t kstat_list;
+static kstat_ctl_t *kc;
+
+typedef struct kstat_inst {
+ adr_name_t *ki_name; /* full name */
+ int ki_instance; /* instance number */
+ uchar_t ki_type; /* last known type */
+ hrtime_t ki_crtime; /* last known creation time */
+
+ kstat_t *ki_ks; /* current kstat header, if any */
+ boolean_t ki_read; /* kstat data has been read */
+ rad_instance_t *ki_inst;
+ list_node_t *ki_node;
+} kstat_inst_t;
+
+static void
+kstat_inst_unread_all(void)
+{
+ for (kstat_inst_t *kid = list_head(&kstat_list); kid;
+ kid = list_next(&kstat_list, kid))
+ kid->ki_read = B_FALSE;
+}
+
+static void
+kstat_inst_invalidate_all(void)
+{
+ for (kstat_inst_t *kid = list_head(&kstat_list); kid;
+ kid = list_next(&kstat_list, kid)) {
+ kid->ki_read = B_FALSE;
+ kid->ki_ks = NULL;
+ }
+}
+
+static void
+kstat_inst_update(void)
+{
+ while (kstat_chain_update(kc))
+ kstat_inst_invalidate_all();
+ kstat_inst_unread_all();
+}
+
+static boolean_t
+kstat_inst_validate_int(kstat_inst_t *kid)
+{
+ if (kid->ki_ks == NULL) {
+ const char *kname = adr_name_key(kid->ki_name, "name");
+ const char *kmodule = adr_name_key(kid->ki_name, "module");
+ if ((kid->ki_ks = kstat_lookup(kc, (char *)kmodule,
+ kid->ki_instance, (char *)kname)) == NULL)
+ return (B_FALSE);
+ kid->ki_crtime = kid->ki_ks->ks_crtime;
+ kid->ki_type = kid->ki_ks->ks_type;
+ assert(!kid->ki_read);
+ }
+
+ return (B_TRUE);
+}
+
+static boolean_t
+kstat_inst_validate(kstat_inst_t *kid)
+{
+ rad_mutex_enter(&kstat_lock);
+ if (!kstat_inst_validate_int(kid)) {
+ rad_mutex_exit(&kstat_lock);
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+static boolean_t
+kstat_inst_read(kstat_inst_t *kid, boolean_t fresh)
+{
+ rad_mutex_enter(&kstat_lock);
+ do {
+ if (!kstat_inst_validate_int(kid)) {
+ rad_mutex_exit(&kstat_lock);
+ return (B_FALSE);
+ }
+ if (!fresh && kid->ki_read)
+ return (B_TRUE);
+ } while (kstat_read(kc, kid->ki_ks, NULL) == -1);
+
+ kid->ki_read = B_TRUE;
+ return (B_TRUE);
+}
+
+static void
+kstat_inst_free(kstat_inst_t *kid)
+{
+ adr_name_rele(kid->ki_name);
+ free(kid);
+}
+
+static adr_name_t *
+kstat_name_create(kstat_t *ks)
+{
+ char instance[100];
+ (void) snprintf(instance, sizeof (instance), "%d", ks->ks_instance);
+
+ return (adr_name_vcreate(KSTAT_DOMAIN, 5,
+ "type", "kstat",
+ "module", ks->ks_module,
+ "name", ks->ks_name,
+ "class", ks->ks_class,
+ "instance", instance));
+}
+
+/*
+ * Dynamic namespace callbacks
+ */
+
+static conerr_t
+kstat_listf(adr_name_t *pattern, data_t **names, void *arg)
+{
+ *names = data_new_array(&t_array_string, 0);
+
+ for (kstat_t *ks = kc->kc_chain; ks; ks = ks->ks_next) {
+ /* XXX: round-about filtering; could be much more efficient */
+ adr_name_t *name = kstat_name_create(ks);
+ if (adr_name_match(name, pattern))
+ array_add(*names,
+ data_new_string(adr_name_tostr(name), lt_free));
+ adr_name_rele(name);
+ }
+
+ return (*names == NULL ? ce_nomem : ce_ok);
+}
+
+static conerr_t
+kstat_lookupf(adr_name_t **name, rad_instance_t **inst, void *arg)
+{
+ adr_name_t *aname = *name;
+ const char *kclass = adr_name_key(aname, "class");
+ const char *kname = adr_name_key(aname, "name");
+ const char *kmodule = adr_name_key(aname, "module");
+ const char *kinst = adr_name_key(aname, "instance");
+ char *end = NULL;
+ int kinstnum;
+
+ if (kname == NULL || kmodule == NULL || kinst == NULL)
+ return (ce_notfound);
+
+ kinstnum = strtol(kinst, &end, 10);
+ if (*end != '\0')
+ return (ce_notfound);
+
+ rad_mutex_enter(&kstat_lock);
+ kstat_t *ks = kstat_lookup(kc, (char *)kmodule, kinstnum,
+ (char *)kname);
+ if (ks == NULL ||
+ (kclass != NULL && strcmp(kclass, ks->ks_class) != 0)) {
+ rad_mutex_exit(&kstat_lock);
+ return (ce_notfound);
+ }
+
+ if (kclass == NULL) {
+ /*
+ * We permit clients to omit the class when doing lookups.
+ * This results in a second kstat_lookup, but *shrug*.
+ */
+ adr_name_t *cname = kstat_name_create(ks);
+ rad_mutex_exit(&kstat_lock);
+ if (cname == NULL)
+ return (ce_nomem);
+ adr_name_rele(aname);
+ *name = cname;
+ *inst = NULL;
+ return (ce_ok);
+ }
+
+ kstat_inst_t *kid = malloc(sizeof (kstat_inst_t));
+ if (kid == NULL) {
+ rad_mutex_exit(&kstat_lock);
+ return (ce_nomem);
+ }
+
+ rad_instance_t *i = instance_create(adr_name_hold(aname),
+ &api_kstat_svr, kid, (void(*)(void *))kstat_inst_free);
+ if (i == NULL) {
+ rad_mutex_exit(&kstat_lock);
+ return (ce_nomem);
+ }
+
+ kid->ki_name = adr_name_hold(aname);
+ kid->ki_instance = kinstnum;
+ kid->ki_ks = ks;
+ kid->ki_read = B_FALSE;
+ kid->ki_inst = i;
+ list_insert_tail(&kstat_list, kid);
+ *inst = i;
+
+ rad_mutex_exit(&kstat_lock);
+
+ return (ce_ok);
+}
+
+/*
+ * "kstat" interface entry points
+ */
+
+conerr_t
+api_kstat_read_module(rad_instance_t *inst, adr_attribute_t *attr,
+ data_t **data, data_t **error)
+{
+ kstat_inst_t *kid = instance_getdata(inst);
+ *data = data_new_string(adr_name_key(kid->ki_name, "module"), lt_copy);
+ return (*data == NULL ? ce_nomem : ce_ok);
+}
+
+conerr_t
+api_kstat_read_name(rad_instance_t *inst, adr_attribute_t *attr,
+ data_t **data, data_t **error)
+{
+ kstat_inst_t *kid = instance_getdata(inst);
+ *data = data_new_string(adr_name_key(kid->ki_name, "name"), lt_copy);
+ return (*data == NULL ? ce_nomem : ce_ok);
+}
+
+conerr_t
+api_kstat_read_class(rad_instance_t *inst, adr_attribute_t *attr,
+ data_t **data, data_t **error)
+{
+ kstat_inst_t *kid = instance_getdata(inst);
+ *data = data_new_string(adr_name_key(kid->ki_name, "class"), lt_copy);
+ return (*data == NULL ? ce_nomem : ce_ok);
+}
+
+conerr_t
+api_kstat_read_instance(rad_instance_t *inst, adr_attribute_t *attr,
+ data_t **data, data_t **error)
+{
+ kstat_inst_t *kid = instance_getdata(inst);
+ *data = data_new_integer(kid->ki_instance);
+ return (*data == NULL ? ce_nomem : ce_ok);
+}
+
+conerr_t
+api_kstat_read_kstatType(rad_instance_t *inst, adr_attribute_t *attr,
+ data_t **data, data_t **error)
+{
+ kstat_inst_t *kid = instance_getdata(inst);
+ if (kstat_inst_validate(kid))
+ rad_mutex_exit(&kstat_lock);
+
+ switch (kid->ki_type) {
+ case KSTAT_TYPE_RAW:
+ *data = &e__kstype_raw;
+ break;
+ case KSTAT_TYPE_NAMED:
+ *data = &e__kstype_named;
+ break;
+ case KSTAT_TYPE_INTR:
+ *data = &e__kstype_intr;
+ break;
+ case KSTAT_TYPE_IO:
+ *data = &e__kstype_io;
+ break;
+ case KSTAT_TYPE_TIMER:
+ *data = &e__kstype_timer;
+ break;
+ default:
+ /* future? *data = &e__kstype_unknown; */
+ *data = &e__kstype_raw;
+ }
+
+ return (ce_ok);
+}
+
+conerr_t
+api_kstat_read_creationTime(rad_instance_t *inst, adr_attribute_t *attr,
+ data_t **data, data_t **error)
+{
+ kstat_inst_t *kid = instance_getdata(inst);
+ if (kstat_inst_validate(kid))
+ rad_mutex_exit(&kstat_lock);
+
+ *data = data_new_ulong(kid->ki_crtime);
+ return (*data == NULL ? ce_nomem : ce_ok);
+}
+
+conerr_t
+api_kstat_read_stale(rad_instance_t *inst, adr_attribute_t *attr,
+ data_t **data, data_t **error)
+{
+ if (kstat_inst_validate(instance_getdata(inst))) {
+ *data = data_new_boolean(B_FALSE);
+ rad_mutex_exit(&kstat_lock);
+ } else {
+ *data = data_new_boolean(B_TRUE);
+ }
+
+ return (ce_ok);
+}
+
+/* Compensate for lacking a discriminated union type */
+static data_t *
+make_union(void)
+{
+ data_t *value = data_new_struct(&t__union);
+ struct_set(value, "i32", data_new_integer(0));
+ struct_set(value, "ui32", data_new_uinteger(0));
+ struct_set(value, "i64", data_new_long(0));
+ struct_set(value, "ui64", data_new_ulong(0));
+ struct_set(value, "f", data_new_float(0));
+ struct_set(value, "d", data_new_double(0));
+ return (value);
+}
+
+/*
+ * Constructs kstat value. Future: consider caching.
+ */
+static conerr_t
+read_value(rad_instance_t *inst, data_t **data, boolean_t fresh)
+{
+ kstat_inst_t *kid = instance_getdata(inst);
+ if (!kstat_inst_read(kid, fresh))
+ return (ce_object);
+
+ if (kid->ki_ks->ks_type != KSTAT_TYPE_NAMED) {
+ rad_mutex_exit(&kstat_lock);
+ return (ce_object);
+ }
+
+ int n = kid->ki_ks->ks_ndata;
+ kstat_named_t *stats = kid->ki_ks->ks_data;
+
+ data_t *sarray = data_new_array(&t_array__statistic, n);
+ for (int i = 0; i < n; i++) {
+ data_t *type;
+ data_t *value = make_union();
+ switch (stats[i].data_type) {
+ case KSTAT_DATA_CHAR:
+ type = &e__ksdtype_char;
+ struct_set(value, "str",
+ data_new_nstring(stats[i].value.c,
+ sizeof (stats[i].value.c)));
+ break;
+ case KSTAT_DATA_INT32:
+ /* case KSTAT_DATA_LONG: */
+ type = &e__ksdtype_int32;
+ struct_set(value, "i32",
+ data_new_integer(stats[i].value.i32));
+ break;
+ case KSTAT_DATA_STRING:
+ type = &e__ksdtype_string;
+ struct_set(value, "str",
+ data_new_string(stats[i].value.str.addr.ptr,
+ lt_copy));
+ break;
+ case KSTAT_DATA_UINT32:
+ /* case KSTAT_DATA_ULONG: */
+ type = &e__ksdtype_uint32;
+ struct_set(value, "ui32",
+ data_new_uinteger(stats[i].value.ui32));
+ break;
+ case KSTAT_DATA_INT64:
+ /* case KSTAT_DATA_LONGLONG: */
+ type = &e__ksdtype_int64;
+ struct_set(value, "i64",
+ data_new_long(stats[i].value.i64));
+ break;
+ case KSTAT_DATA_UINT64:
+ /* case KSTAT_DATA_ULONGLONG: */
+ type = &e__ksdtype_uint64;
+ struct_set(value, "ui64",
+ data_new_ulong(stats[i].value.ui64));
+ break;
+ case KSTAT_DATA_FLOAT:
+ type = &e__ksdtype_float;
+ struct_set(value, "f",
+ data_new_float(stats[i].value.f));
+ break;
+ case KSTAT_DATA_DOUBLE:
+ type = &e__ksdtype_double;
+ struct_set(value, "d",
+ data_new_double(stats[i].value.d));
+ break;
+ default:
+ continue;
+ }
+
+ data_t *stat = data_new_struct(&t__statistic);
+ struct_set(stat, "name",
+ data_new_string(stats[i].name, lt_copy));
+ struct_set(stat, "type", type);
+ struct_set(stat, "value", value);
+ array_add(sarray, stat);
+ }
+
+ data_t *snap = data_new_struct(&t__snapshot);
+ struct_set(snap, "timestamp", data_new_ulong(kid->ki_ks->ks_snaptime));
+ struct_set(snap, "statistics", sarray);
+
+ if (data_verify(snap, NULL, B_TRUE)) {
+ *data = snap;
+ } else {
+ *data = NULL;
+ data_free(snap);
+ }
+
+ rad_mutex_exit(&kstat_lock);
+ return (*data == NULL ? ce_nomem : ce_ok);
+}
+
+conerr_t
+api_kstat_read_value(rad_instance_t *inst, adr_attribute_t *attr,
+ data_t **data, data_t **error)
+{
+ return (read_value(inst, data, B_FALSE));
+}
+
+conerr_t
+api_kstat_invoke_get_fresh_value(rad_instance_t *inst, adr_method_t *meth,
+ data_t **ret, data_t **args, int count, data_t **error)
+{
+ return (read_value(inst, ret, B_TRUE));
+}
+
+/*
+ * "kstatctl" interface entry point
+ */
+
+conerr_t
+api_kstatctl_invoke_update_all(rad_instance_t *inst, adr_method_t *meth,
+ data_t **ret, data_t **args, int count, data_t **error)
+{
+ rad_mutex_enter(&kstat_lock);
+ kstat_inst_update();
+ rad_mutex_exit(&kstat_lock);
+}
+
+static rad_modinfo_t modinfo = { "kstat", "kernel statistics module" };
+
+int
+_rad_init(void *handle)
+{
+ if (rad_module_register(handle, RAD_MODVERSION, &modinfo) == -1)
+ return (-1);
+
+ if (rad_isproxy)
+ return (0);
+
+ adr_name_t *domain = adr_name_vcreate(KSTAT_DOMAIN, 0);
+ if (domain == NULL)
+ return (0);
+
+ if ((kc = kstat_open()) == NULL)
+ return (0);
+
+ list_create(&kstat_list, sizeof (kstat_inst_t),
+ offsetof(kstat_inst_t, ki_node));
+ (void) cont_register_dynamic(rad_container, domain,
+ kstat_listf, kstat_lookupf, NULL);
+
+ adr_name_t *ctlname =
+ adr_name_vcreate(KSTAT_DOMAIN, 1, "type", "control");
+ (void) cont_insert_singleton(rad_container, ctlname, &api_kstatctl_svr);
+
+ return (0);
+}
--- a/usr/src/cmd/rad/mod/proto_rad/mod_proto_rad.c Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/rad/mod/proto_rad/mod_proto_rad.c Tue Nov 23 15:54:20 2010 -0800
@@ -435,7 +435,7 @@
&slavenames);
int len = array_size(names);
if (ce == ce_ok)
- names = array_combine(names, slavenames);
+ names = array_addall(names, slavenames);
/* Inefficiently remove duplicates */
for (int i = 0; i < len; i++) {
--- a/usr/src/cmd/rad/mod/smf/mod_smf.c Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/rad/mod/smf/mod_smf.c Tue Nov 23 15:54:20 2010 -0800
@@ -1805,7 +1805,7 @@
objname = adr_name_vcreate("org.opensolaris.os.smf", 2,
"type", "service", "service", sname);
}
- si->inst = instance_create(objname, &api_serviceInfo_svr, si);
+ si->inst = instance_create(objname, &api_serviceInfo_svr, si, NULL);
(void) cont_insert(rad_container, si->inst, INST_ID_PICK);
if (inst) {
@@ -1867,7 +1867,7 @@
scf_handle_destroy(scfhandle);
agg_inst = instance_create(adr_name_fromstr(aggregator_pattern),
- &api_aggregator_svr, NULL);
+ &api_aggregator_svr, NULL, NULL);
if (agg_inst != NULL)
(void) cont_insert(rad_container, agg_inst, INST_ID_PICK);
--- a/usr/src/cmd/rad/rad.c Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/rad/rad.c Tue Nov 23 15:54:20 2010 -0800
@@ -55,10 +55,9 @@
#define TEXT_DOMAIN "SYS_TEST"
#endif
-rad_container_t rad_container_auth = CONTAINER_INITIALIZER;
-rad_container_t rad_container_unauth = CONTAINER_INITIALIZER;
-rad_container_t rad_container_control = CONTAINER_INITIALIZER;
-
+rad_container_t rad_container_auth;
+rad_container_t rad_container_unauth;
+rad_container_t rad_container_control;
rad_container_t *rad_container = &rad_container_auth;
int rad_exit_failure = 1;
@@ -216,10 +215,10 @@
rad_loglevel = RL_ALL;
if ((moduledir = struct_get(config, "moduledir")) != NULL)
rad_moduledirs =
- array_combine(rad_moduledirs, data_ref(moduledir));
+ array_addall(rad_moduledirs, data_ref(moduledir));
if ((modules = struct_get(config, "modules")) != NULL)
rad_modules =
- array_combine(rad_modules, data_ref(modules));
+ array_addall(rad_modules, data_ref(modules));
data_free(config);
}
@@ -227,6 +226,10 @@
if (smf_startup)
svc_fd = rad_service_wait();
+ cont_create(&rad_container_auth);
+ cont_create(&rad_container_unauth);
+ cont_create(&rad_container_control);
+
xmlInitParser(); /* So libxml consumers are MT safe */
adr_ssl_init(); /* So OpenSSL consumers are MT safe */
rad_ticket_init();
--- a/usr/src/cmd/rad/rad_container.c Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/rad/rad_container.c Tue Nov 23 15:54:20 2010 -0800
@@ -46,24 +46,49 @@
#include "api_errors.h"
#include "api_container.h"
+void
+cont_create(rad_container_t *c)
+{
+ rad_mutex_init(&c->c_lock);
+ list_create(&c->c_instances, sizeof (rad_instance_t),
+ offsetof(rad_instance_t, i_cnode));
+ list_create(&c->c_dynamic, sizeof (rad_dynamic_t),
+ offsetof(rad_dynamic_t, rd_node));
+ c->c_ninstances = 0;
+ c->c_id = 0;
+ c->c_contobj = NULL;
+}
+
conerr_t
cont_list(rad_container_t *c, adr_name_t *pattern, data_t **names)
{
- data_t *result;
- int n = 0;
-
rad_mutex_enter(&c->c_lock);
- result = data_new_array(&t_array_string, c->c_ninstances);
-
+ data_t *result = data_new_array(&t_array_string, c->c_ninstances);
if (result == NULL)
goto out;
- for (int i = 0; i < c->c_ninstances; i++) {
- rad_instance_t *inst = c->c_instances[i];
- if (!adr_name_match(inst->i_name, pattern))
+ int n = 0;
+ for (rad_instance_t *i = list_head(&c->c_instances); i != NULL;
+ i = list_next(&c->c_instances, i)) {
+ if (!i->i_visible || !adr_name_match(i->i_name, pattern))
continue;
- array_set(result, n++,
- data_new_string(c->c_instances[i]->i_namestr, lt_copy));
+ array_set(result, n++, data_new_string(i->i_namestr, lt_copy));
+ }
+
+ for (rad_dynamic_t *dyn = list_head(&c->c_dynamic); dyn;
+ dyn = list_next(&c->c_dynamic, dyn)) {
+ data_t *n = NULL;
+ if (dyn->rd_list == NULL)
+ continue;
+
+ if (dyn->rd_list(pattern, &n, dyn->rd_arg) == ce_ok) {
+ result = array_addall(result, n);
+ } else {
+ data_free(result);
+ result = NULL;
+ }
+ if (result == NULL)
+ break;
}
*names = result;
@@ -76,25 +101,46 @@
static rad_instance_t *
cont_lookup_int(rad_container_t *c, adr_name_t *name)
{
- for (int i = 0; i < c->c_ninstances; i++)
- if (adr_name_cmp(c->c_instances[i]->i_name, name) == 0)
- return (c->c_instances[i]);
+ for (rad_instance_t *inst = list_head(&c->c_instances); inst != NULL;
+ inst = list_next(&c->c_instances, inst))
+ if (adr_name_cmp(inst->i_name, name) == 0)
+ return (inst);
return (NULL);
}
+static conerr_t
+cont_insert_unlocked(rad_container_t *c, rad_instance_t *inst, long long id);
+
conerr_t
cont_lookup(rad_container_t *c, const char *name, rad_instance_t **inst,
data_t **error)
{
- adr_name_t *aname = adr_name_fromstr(name);
- if (aname == NULL)
+ adr_name_t *adrn = adr_name_fromstr(name);
+ if (adrn == NULL)
return (error_notfound(error, &e__target_object, name));
rad_mutex_enter(&c->c_lock);
- *inst = cont_lookup_int(c, aname);
+retry:
+ *inst = cont_lookup_int(c, adrn);
+ if (*inst == NULL)
+ for (rad_dynamic_t *dyn = list_head(&c->c_dynamic); dyn;
+ dyn = list_next(&c->c_dynamic, dyn))
+ if (adr_name_match(adrn, dyn->rd_pattern) &&
+ dyn->rd_lookup != NULL &&
+ dyn->rd_lookup(&adrn, inst, dyn->rd_arg) == ce_ok) {
+ if (*inst == NULL)
+ goto retry;
+ cont_insert_unlocked(c, *inst, INST_ID_PICK);
+ /*
+ * We defer to dynamic list for objects
+ * instantiated by dynamic lookup.
+ */
+ (*inst)->i_visible = B_FALSE;
+ break;
+ }
instance_hold(*inst);
rad_mutex_exit(&c->c_lock);
- adr_name_rele(aname);
+ adr_name_rele(adrn);
if (*inst == NULL)
return (error_notfound(error, &e__target_object, name));
@@ -104,9 +150,10 @@
static rad_instance_t *
cont_lookup_id_int(rad_container_t *c, long long id)
{
- for (int i = 0; i < c->c_ninstances; i++)
- if (c->c_instances[i]->i_id == id)
- return (c->c_instances[i]);
+ for (rad_instance_t *inst = list_head(&c->c_instances); inst != NULL;
+ inst = list_next(&c->c_instances, inst))
+ if (inst->i_id == id)
+ return (inst);
return (NULL);
}
@@ -160,18 +207,8 @@
(id != INST_ID_PICK && cont_lookup_id_int(c, id) != NULL))
return (ce_exists);
- newarray = malloc((c->c_ninstances + 1) * sizeof (rad_instance_t *));
- if (newarray == NULL)
- return (ce_nomem);
-
- if (c->c_instances != NULL) {
- (void) memcpy(newarray, c->c_instances,
- c->c_ninstances * sizeof (rad_instance_t *));
- free(c->c_instances);
- }
-
- c->c_instances = newarray;
- newarray[c->c_ninstances++] = inst;
+ c->c_ninstances++;
+ list_insert_tail(&c->c_instances, inst);
if (id == INST_ID_PICK) {
inst->i_id = (rad_isproxy ? INST_ID_PROXY : 0) |
(long long)atomic_inc_64_nv(&instance_lastid);
@@ -203,7 +240,7 @@
cont_insert_singleton_id(rad_container_t *c, adr_name_t *name,
rad_object_t *obj, long long id)
{
- rad_instance_t *inst = instance_create(name, obj, NULL);
+ rad_instance_t *inst = instance_create(name, obj, NULL, NULL);
if (inst == NULL)
return (ce_nomem);
@@ -222,19 +259,11 @@
cont_remove(rad_container_t *c, rad_instance_t *inst)
{
rad_mutex_enter(&c->c_lock);
- for (int i = 0; i < c->c_ninstances; i++)
- if (c->c_instances[i] == inst) {
- c->c_instances[i] = c->c_instances[--c->c_ninstances];
- cont_sendevent(c, &e__nschange_remove, inst);
- rad_mutex_exit(&c->c_lock);
-
- instance_rele(inst);
- return (ce_ok);
- }
-
- rad_log(RL_FATAL, "cont_remove: instance not found: %s",
- inst->i_namestr);
- return (ce_notfound);
+ list_remove(&c->c_instances, inst);
+ cont_sendevent(c, &e__nschange_remove, inst);
+ rad_mutex_exit(&c->c_lock);
+ instance_rele(inst);
+ return (ce_ok);
}
/*
@@ -247,7 +276,7 @@
adr_name_t *objname = adr_name_vcreate("org.opensolaris.os.rad", 1,
"type", "container");
rad_instance_t *inst =
- instance_create(objname, &api_container_svr, NULL);
+ instance_create(objname, &api_container_svr, NULL, NULL);
if (inst == NULL)
return (B_FALSE);
@@ -265,3 +294,22 @@
return (err == ce_ok);
}
+
+conerr_t
+cont_register_dynamic(rad_container_t *c, adr_name_t *pattern,
+ rad_dyn_list_t listf, rad_dyn_lookup_t lookupf, void *arg)
+{
+ rad_dynamic_t *dyn = malloc(sizeof (rad_dynamic_t));
+ if (dyn == NULL)
+ return (ce_nomem);
+ dyn->rd_pattern = pattern;
+ dyn->rd_list = listf;
+ dyn->rd_lookup = lookupf;
+ dyn->rd_arg = arg;
+
+ rad_mutex_enter(&c->c_lock);
+ list_insert_tail(&c->c_dynamic, dyn);
+ rad_mutex_exit(&c->c_lock);
+
+ return (ce_ok);
+}
--- a/usr/src/cmd/rad/rad_container.h Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/rad/rad_container.h Tue Nov 23 15:54:20 2010 -0800
@@ -41,22 +41,31 @@
extern "C" {
#endif
+typedef struct rad_dynamic {
+ adr_name_t *rd_pattern;
+ rad_dyn_list_t rd_list;
+ rad_dyn_lookup_t rd_lookup;
+ void *rd_arg;
+ list_node_t rd_node;
+} rad_dynamic_t;
+
/* The container itself; contains instances */
struct rad_container {
pthread_mutex_t c_lock;
int c_ninstances; /* # of instances */
- rad_instance_t **c_instances; /* instances */
+ list_t c_instances; /* instances */
+ list_t c_dynamic; /* dynamic namespace providers */
long long c_id; /* last instance ID allocated */
rad_instance_t *c_contobj; /* container object */
};
-#define CONTAINER_INITIALIZER { PTHREAD_MUTEX_INITIALIZER, 0, NULL, 0, NULL }
-
+void cont_create(rad_container_t *);
conerr_t cont_list(rad_container_t *, adr_name_t *, data_t **);
conerr_t cont_lookup(rad_container_t *, const char *, rad_instance_t **,
- data_t **);
+ data_t **);
conerr_t cont_lookup_id(rad_container_t *, long long, rad_instance_t **,
- data_t **);
+ data_t **);
+
boolean_t cont_insert_contobj(rad_container_t *);
#ifdef __cplusplus
--- a/usr/src/cmd/rad/rad_modapi.h Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/rad/rad_modapi.h Tue Nov 23 15:54:20 2010 -0800
@@ -102,11 +102,19 @@
};
/*
+ * Dynamic namespace management
+ */
+typedef conerr_t (*rad_dyn_list_t)(adr_name_t *, data_t **, void *arg);
+typedef conerr_t (*rad_dyn_lookup_t)(adr_name_t **, rad_instance_t **,
+ void *arg);
+
+/*
* Container routines
*/
#define INST_ID_PICK (-1)
-rad_instance_t *instance_create(adr_name_t *, rad_object_t *, void *);
+rad_instance_t *instance_create(adr_name_t *, rad_object_t *, void *,
+ void (*)(void *));
void instance_hold(rad_instance_t *);
void instance_rele(rad_instance_t *);
data_t *instance_getname(rad_instance_t *);
@@ -116,8 +124,10 @@
conerr_t cont_insert(rad_container_t *, rad_instance_t *, long long);
conerr_t cont_insert_singleton(rad_container_t *, adr_name_t *, rad_object_t *);
conerr_t cont_insert_singleton_id(rad_container_t *, adr_name_t *,
- rad_object_t *, long long);
+ rad_object_t *, long long);
conerr_t cont_remove(rad_container_t *, rad_instance_t *);
+conerr_t cont_register_dynamic(rad_container_t *, adr_name_t *, rad_dyn_list_t,
+ rad_dyn_lookup_t, void *);
/*
* Logging routines
--- a/usr/src/cmd/rad/rad_object.c Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/rad/rad_object.c Tue Nov 23 15:54:20 2010 -0800
@@ -356,7 +356,8 @@
}
rad_instance_t *
-instance_create(adr_name_t *name, rad_object_t *type, void *data)
+instance_create(adr_name_t *name, rad_object_t *type, void *data,
+ void (*freef)(void *))
{
if (name == NULL)
return (NULL);
@@ -377,7 +378,9 @@
result->i_namestr = namestr;
result->i_type = type;
result->i_data = data;
+ result->i_freef = freef;
result->i_id = -1;
+ result->i_visible = B_TRUE;
list_create(&result->i_interest, sizeof (rad_interest_t),
offsetof(rad_interest_t, ri_instnode));
@@ -387,6 +390,8 @@
static void
instance_destroy(rad_instance_t *inst)
{
+ if (inst->i_freef != NULL)
+ inst->i_freef(inst->i_data);
adr_name_rele(inst->i_name);
free(inst->i_namestr);
free(inst);
--- a/usr/src/cmd/rad/rad_object.h Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/rad/rad_object.h Tue Nov 23 15:54:20 2010 -0800
@@ -44,12 +44,17 @@
pthread_mutex_t i_lock; /* protects *i_data */
pthread_mutex_t i_reflock; /* protects references */
long long i_refs; /* references */
+
+ long long i_id; /* instance id */
adr_name_t *i_name; /* instance name */
char *i_namestr; /* instance name (as canon. string) */
rad_object_t *i_type; /* instance's type */
+ boolean_t i_visible; /* visible to LIST */
+
void *i_data; /* instance-specific data */
+ void (*i_freef)(void *); /* free function for i_data */
list_t i_interest; /* event listeners */
- long long i_id; /* instance id */
+ list_node_t i_cnode; /* container membership */
};
adr_attribute_t *inst_attr_lookup(rad_instance_t *, const char *, data_t **);
--- a/usr/src/cmd/rad/rad_pam.c Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/rad/rad_pam.c Tue Nov 23 15:54:20 2010 -0800
@@ -613,10 +613,10 @@
{
adr_name_t *name = adr_name_vcreate("org.opensolaris.os.rad", 1,
"type", "authentication");
- rad_instance_t *inst =
- instance_create(adr_name_hold(name), &api_authenticator_svr, NULL);
- rad_instance_t *uinst =
- instance_create(adr_name_hold(name), &api_authenticator_svr, NULL);
+ rad_instance_t *inst = instance_create(adr_name_hold(name),
+ &api_authenticator_svr, NULL, NULL);
+ rad_instance_t *uinst = instance_create(adr_name_hold(name),
+ &api_authenticator_svr, NULL, NULL);
conerr_t err = ce_nomem;
if (inst == NULL || uinst == NULL ||
--- a/usr/src/cmd/test/libadr/name.c Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/cmd/test/libadr/name.c Tue Nov 23 15:54:20 2010 -0800
@@ -149,13 +149,6 @@
STR_6KV, STR_7KV, STR_8KV,
STR_9KV, STR_10KV
};
- /* Canonicalized strings */
- const char *cstrs[] = {
- STR_1KV, STR_2KV,
- STR_3KV, STR_5KV, STR_5KV,
- STR_6KV, STR_8KV, STR_8KV,
- STR_9KV, STR_10KV
- };
int t = 0;
const char *keys1[] = { KEY_1 };
@@ -363,11 +356,11 @@
/*
* Test batch 5: Does adr_name_tostr function properly?
*/
- if (comparestrs("adr_name_create", name_create, cstrs, strs))
+ if (comparestrs("adr_name_create", name_create, strs, strs))
fail = B_TRUE;
- if (comparestrs("adr_name_vcreate", name_vcreate, cstrs, strs))
+ if (comparestrs("adr_name_vcreate", name_vcreate, strs, strs))
fail = B_TRUE;
- if (comparestrs("adr_name_fromstr", name_fromstr, cstrs, strs))
+ if (comparestrs("adr_name_fromstr", name_fromstr, strs, strs))
fail = B_TRUE;
/*
--- a/usr/src/java/rad/org/opensolaris/os/rad/ADRName.java Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/java/rad/org/opensolaris/os/rad/ADRName.java Tue Nov 23 15:54:20 2010 -0800
@@ -25,7 +25,9 @@
package org.opensolaris.os.rad;
+import java.util.ArrayList;
import java.util.Hashtable;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
@@ -37,6 +39,9 @@
private String domain_;
private TreeMap<String, String> kvs_ = new TreeMap<String, String>();
+ /* Wire-ordered keys to play jconsole's silly collation game */
+ private List<String> keys_ = new ArrayList<String>();
+
public ADRName(ObjectName on) {
domain_ = on.getDomain();
Hashtable<String, String> keys = on.getKeyPropertyList();
@@ -83,6 +88,7 @@
if (pos == start || inkey)
throw new IllegalArgumentException("Empty value: " + str);
kvs_.put(key, new String(scratch, 0, dst));
+ keys_.add(key);
dst = 0;
inkey = true;
start = pos + 1;
@@ -118,13 +124,30 @@
if (pos == start || inkey)
throw new IllegalArgumentException("Empty value: " + str);
kvs_.put(key, new String(scratch, 0, dst));
+ keys_.add(key);
}
public ObjectName toObjectName() throws MalformedObjectNameException {
- Hashtable<String, String> keys = new Hashtable<String, String>();
- for (Map.Entry<String, String> e : kvs_.entrySet())
- keys.put(e.getKey(), ObjectName.quote(e.getValue()));
- return new ObjectName(domain_, keys);
+ /*
+ * In theory, ObjectName keys are unordered. In practice, their
+ * order is used as a hint to improve the appearance of jconsole.
+ * Discordant as this is, the end result is actually pretty nice.
+ *
+ * Unfortunately, the only ObjectName constructor that chooses
+ * practice over theory is the one that takes the string form, so
+ * below we cons up a String so that ObjectName(String) can then
+ * immediately undo our work and parse it.
+ */
+ StringBuffer sb = new StringBuffer(domain_).append(':');
+ boolean first = true;
+ for (String key : keys_) {
+ if (first)
+ first = false;
+ else
+ sb.append(',');
+ sb.append(key).append('=').append(ObjectName.quote(kvs_.get(key)));
+ }
+ return (new ObjectName(sb.toString()));
}
@Override
--- a/usr/src/lib/libadr/common/adr.c Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/lib/libadr/common/adr.c Tue Nov 23 15:54:20 2010 -0800
@@ -789,11 +789,38 @@
return (data->d_type->t_aux.t_array);
}
+#define array_tainted(x) (x->d_data.array == NULL)
+
+static void
+array_taint(data_t *a)
+{
+ for (int i = 0; i < a->d_size; i++)
+ data_free(a->d_data.array[i]);
+ free(a->d_data.array);
+ a->d_data.array = NULL;
+}
+
+static boolean_t
+array_grow(data_t *a, int nsize)
+{
+ data_t **narray = zalloc(nsize * sizeof (data_t *));
+ if (narray == NULL) {
+ array_taint(a);
+ return (B_FALSE);
+ }
+ for (int i = 0; i < a->d_rsize; i++)
+ narray[i] = a->d_data.array[i];
+ free(a->d_data.array);
+ a->d_size = nsize;
+ a->d_data.array = narray;
+
+ return (B_TRUE);
+}
void
array_set(data_t *data, int index, data_t *value)
{
- if (data == NULL || data->d_data.array == NULL) {
+ if (data == NULL || array_tainted(data)) {
data_free(value);
return;
}
@@ -813,7 +840,7 @@
int
array_vset(data_t *data, int index, data_t *value)
{
- if (data == NULL || data->d_data.array == NULL) {
+ if (data == NULL || array_tainted(data)) {
data_free(value);
return (1);
}
@@ -822,21 +849,10 @@
if (index >= data->d_size) {
int nsize = data->d_size * 2;
- data_t **narray = zalloc(nsize * sizeof (data_t *));
- if (narray == NULL) {
- for (int i = 0; i < data->d_size; i++)
- data_free(data->d_data.array[i]);
- free(data->d_data.array);
- data->d_data.array = NULL;
+ if (!array_grow(data, nsize)) {
data_free(value);
return (1);
}
- for (int i = 0; i < data->d_size; i++)
- narray[i] = data->d_data.array[i];
- free(data->d_data.array);
-
- data->d_size = nsize;
- data->d_data.array = narray;
}
array_set(data, index, value);
@@ -865,47 +881,56 @@
}
data_t *
-array_combine(data_t *a1, data_t *a2)
+array_addall(data_t *a1, data_t *a2)
{
+ if (a1 == NULL || array_tainted(a1)) {
+ data_free(a2);
+ return (NULL);
+ }
+
+ if (a2 == NULL) {
+ /*
+ * Unlike other array routines, all consumers overwrite
+ * their references with the result, so we free instead
+ * of taint.
+ */
+ data_free(a1);
+ return (NULL);
+ }
+
assert(data_basetype(a1) == dt_array);
assert(data_basetype(a2) == dt_array);
assert(data_type(a1) == data_type(a2));
/*
- * array_combine is a destructive operation unless someone besides
- * the caller has references
+ * We consume the caller's reference to a2. If that's the only
+ * reference, we get to co-opt the element references as well.
*/
- boolean_t c1 = a1->d_refs > 1;
- boolean_t c2 = a2->d_refs > 1;
- data_t *result = data_new_array(a1->d_type, a1->d_rsize + a2->d_rsize);
- result->d_rsize = a1->d_rsize + a2->d_rsize;
-
- int i = 0;
- for (int j = 0; j < a1->d_rsize; j++) {
- if (c1)
- (void) data_ref(a1->d_data.array[j]);
- result->d_data.array[i++] = a1->d_data.array[j];
- }
- for (int j = 0; j < a2->d_rsize; j++) {
- if (c2)
- (void) data_ref(a2->d_data.array[j]);
- result->d_data.array[i++] = a2->d_data.array[j];
+ boolean_t allmine = a2->d_refs == 1;
+ int nsize = a1->d_rsize + a2->d_rsize;
+ if (nsize > a1->d_size) {
+ if (!array_grow(a1, nsize)) {
+ data_free(a1); /* See earlier comment */
+ data_free(a2);
+ return (NULL);
+ }
}
- if (c1) {
- data_free(a1);
- } else {
- free(a1->d_data.array);
- free(a1);
+ int i = a1->d_rsize;
+ for (int j = 0; j < a2->d_rsize; j++) {
+ data_t *d = a1->d_data.array[i++] = a2->d_data.array[j];
+ if (allmine) {
+ /* Steal reference */
+ a2->d_data.array[j] = NULL;
+ } else {
+ /* We have to share */
+ data_ref(d);
+ }
}
- if (c2) {
- data_free(a2);
- } else {
- free(a2->d_data.array);
- free(a2);
- }
+ a1->d_rsize = i;
+ data_free(a2);
- return (result);
+ return (a1);
}
static boolean_t
--- a/usr/src/lib/libadr/common/adr.h Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/lib/libadr/common/adr.h Tue Nov 23 15:54:20 2010 -0800
@@ -253,7 +253,7 @@
int array_vset(data_t *, int, data_t *);
int array_add(data_t *, data_t *);
void array_remove(data_t *, int);
-data_t *array_combine(data_t *, data_t *);
+data_t *array_addall(data_t *, data_t *);
int array_search(data_t *, const char *, const char * const *);
int array_nsearch(data_t *, const char *, int, const char * const *);
--- a/usr/src/lib/libadr/common/adr_name.c Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/lib/libadr/common/adr_name.c Tue Nov 23 15:54:20 2010 -0800
@@ -46,8 +46,10 @@
int an_refs;
int an_count;
char *an_domain;
- char **an_keys;
- char **an_values;
+ char **an_keys; /* Unsorted keys */
+ char **an_values; /* Unsorted values */
+ char **an_skeys; /* Sorted keys */
+ char **an_svalues; /* Sorted values */
};
#define zalloc(x) calloc(1, x)
@@ -70,8 +72,10 @@
(void) pthread_mutex_init(&result->an_lock, NULL);
result->an_refs = 1;
result->an_count = n;
- result->an_keys = zalloc(2 * n * sizeof (char *));
+ result->an_keys = zalloc(4 * n * sizeof (char *));
result->an_values = &result->an_keys[n];
+ result->an_skeys = &result->an_keys[2 * n];
+ result->an_svalues = &result->an_keys[3 * n];
if (result->an_keys == NULL) {
free(result);
return (NULL);
@@ -87,20 +91,25 @@
adr_name_normalize(adr_name_t *name)
{
int c = name->an_count;
+ for (int i = 0; i < c; i++) {
+ name->an_skeys[i] = name->an_keys[i];
+ name->an_svalues[i] = name->an_values[i];
+ }
+
for (int i = 0; i < c - 1; i++) {
for (int j = i + 1; j < c; j++) {
- int res = strcmp(name->an_keys[i], name->an_keys[j]);
+ int res = strcmp(name->an_skeys[i], name->an_skeys[j]);
if (res == 0) {
adr_name_free(name);
return (NULL);
}
if (res > 0) {
- char *ktmp = name->an_keys[i];
- char *vtmp = name->an_values[i];
- name->an_keys[i] = name->an_keys[j];
- name->an_values[i] = name->an_values[j];
- name->an_keys[j] = ktmp;
- name->an_values[j] = vtmp;
+ char *ktmp = name->an_skeys[i];
+ char *vtmp = name->an_svalues[i];
+ name->an_skeys[i] = name->an_skeys[j];
+ name->an_svalues[i] = name->an_svalues[j];
+ name->an_skeys[j] = ktmp;
+ name->an_svalues[j] = vtmp;
}
}
}
@@ -482,12 +491,12 @@
if (n1->an_count > n2->an_count)
return (1);
- /* Assumes order is either normalized or significant. */
+ /* Compare pre-sorted key/value pairs */
for (int i = 0; i < n1->an_count; i++) {
- res = strcmp(n1->an_keys[i], n2->an_keys[i]);
+ res = strcmp(n1->an_skeys[i], n2->an_skeys[i]);
if (res != 0)
return (res);
- res = strcmp(n1->an_values[i], n2->an_values[i]);
+ res = strcmp(n1->an_svalues[i], n2->an_svalues[i]);
if (res != 0)
return (res);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pykstat/Makefile Tue Nov 23 15:54:20 2010 -0800
@@ -0,0 +1,41 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+include $(SRC)/Makefile.env
+
+PROTO_PYRAD = $(PROTO_PYTHON)/kstat
+PYSRCS = __init__.py rad.py
+PYOBJS = $(PYSRCS:%.py=%.pyc)
+PYFILES = $(PYSRCS) $(PYOBJS)
+INSTFILES = $(PYFILES:%=$(PROTO_PYRAD)/%)
+
+all: $(PYOBJS)
+
+install: all $(INSTFILES)
+
+$(PROTO_PYRAD)/%: %
+ $(INS.pyfile)
+
+include $(SRC)/Makefile.targ
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pykstat/__init__.py Tue Nov 23 15:54:20 2010 -0800
@@ -0,0 +1,26 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+# This file intentionally left blank.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pykstat/rad.py Tue Nov 23 15:54:20 2010 -0800
@@ -0,0 +1,115 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+""" A thin wrapper around the kstats support provided by rad """
+
+from __future__ import absolute_import
+import rad.client as client
+import rad.adaptor as adaptor
+import rad.util as util
+import os
+
+_RAD_KSTAT_DOMAIN = "com.oracle.solaris.kstat"
+_RAD_KSTAT_MODULE = "/usr/lib/rad/module/kstat.so"
+
+# The rad interface doesn't support discriminated unions, so the kstat
+# module fakes one up with a traditional structure. Snapshot and
+# StatAdaptor transform that structure to something more pythonic.
+
+class Snapshot:
+ def __init__(self, value):
+ self._timestamp = value.timestamp
+ self._stats = {}
+ for i in value.statistics:
+ if i.type == "char":
+ self._stats[i.name] = i.value.str
+ elif i.type == "int32":
+ self._stats[i.name] = i.value.i32
+ elif i.type == "uint32":
+ self._stats[i.name] = i.value.ui32
+ elif i.type == "int64":
+ self._stats[i.name] = i.value.i64
+ elif i.type == "uint64":
+ self._stats[i.name] = i.value.ui64
+ elif i.type == "float":
+ self._stats[i.name] = i.value.f
+ elif i.type == "double":
+ self._stats[i.name] = i.value.d
+ elif i.type == "string":
+ self._stats[i.name] = i.value.str
+
+ def timestamp(self):
+ return self._timestamp
+
+ def get(self, stat):
+ return self._stats[stat]
+
+class StatAdaptor(adaptor.Adaptor):
+ def __init__(self, statobj):
+ adaptor.Adaptor.__init__(self, statobj)
+ old_fresh = self.__dict__["get_fresh_value"]
+ self.__dict__["get_fresh_value"] = lambda: Snapshot(old_fresh())
+
+ def __getattr__(self, attr):
+ result = adaptor.Adaptor.__getattr__(self, attr)
+ if attr == "value":
+ return Snapshot(result)
+ return result
+
+class Kstats:
+ """ Represents the system's kstats """
+
+ ctlname = client.Name(_RAD_KSTAT_DOMAIN, [("type", "control")])
+
+ def __init__(self):
+ self._rc = util.connect_private([ _RAD_KSTAT_MODULE ])
+ self._ctl = adaptor.Adaptor(self._rc.get_object(Kstats.ctlname))
+
+ def lookup(self, module, name, instance):
+ return StatAdaptor(self._rc.get_object(
+ client.Name(_RAD_KSTAT_DOMAIN, [("type", "kstat"),
+ ("module", module), ("name", name),
+ ("instance", "%d" % instance)])))
+
+ def lookup_many(self, module = None, name = None, instance = None,
+ clazz = None):
+ keys = [("type", "kstat")]
+ if module:
+ keys.append(("module", module))
+ if name:
+ keys.append(("name", name))
+ if instance:
+ keys.append(("instance", "%d" % instance))
+ if clazz:
+ keys.append(("class", clazz))
+ o = self._rc.list_objects(client.Name(_RAD_KSTAT_DOMAIN, keys))
+
+ return [ StatAdaptor(self._rc.get_object(i)) for i in o ]
+
+ def update(self):
+ self._ctl.update_all()
+
+ def close(self):
+ self._rc.close()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkg/manifests/system-management-rad-kstat.mf Tue Nov 23 15:54:20 2010 -0800
@@ -0,0 +1,44 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (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) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+
+license cr_Oracle license=cr_Oracle
+set name=pkg.fmri value=pkg:/system/management/rad/kstat@$(PKGVERS)
+set name=pkg.summary value="rad kstat module"
+set name=pkg.description value="rad kstat module"
+set name=info.classification value="org.opensolaris.category.2008:Applications/Configuration and Preferences"
+set name=variant.arch value=$(ARCH)
+dir path=usr group=sys
+dir path=usr/lib
+dir path=usr/lib/python2.6
+dir path=usr/lib/python2.6/vendor-packages
+dir path=usr/lib/python2.6/vendor-packages/kstat
+file path=usr/lib/python2.6/vendor-packages/kstat/__init__.py
+file path=usr/lib/python2.6/vendor-packages/kstat/__init__.pyc
+file path=usr/lib/python2.6/vendor-packages/kstat/rad.py
+file path=usr/lib/python2.6/vendor-packages/kstat/rad.pyc
+dir path=usr/lib/rad
+dir path=usr/lib/rad/module
+file path=usr/lib/rad/module/kstat.so
+depend fmri=pkg:/system/management/rad@$(PKGVERS) type=require
--- a/usr/src/pkg/manifests_wos/system-management-visual-panels.content Mon Nov 22 10:50:58 2010 -0500
+++ b/usr/src/pkg/manifests_wos/system-management-visual-panels.content Tue Nov 23 15:54:20 2010 -0800
@@ -24,6 +24,7 @@
#
<include ../manifests/system-management-rad.mf>
+<include ../manifests/system-management-rad-kstat.mf>
<include ../manifests/system-management-visual-panels.mf>
<include ../manifests/system-management-visual-panels-sysmon.mf>
<include ../manifests/system-management-visual-panels-svcs.mf>