/* * 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 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include "dict.h" #include "pool_internal.h" #include "pool_impl.h" /* * Atom structure, used to reference count string atoms. */ typedef struct { char *a_string; /* String atom */ uint_t a_count; /* String reference count */ } atom_t; /* * The _internal_lock is used to lock the state of libpool during * internal initialisation operations. */ mutex_t _internal_lock; static int _libpool_debug = 0; /* debugging messages */ static dict_hdl_t *_pv_atoms; /* pool_value_t atoms */ static mutex_t _atom_lock; /* atom table lock */ static int _libpool_internal_initialised = PO_FALSE; /* * Various useful constant strings which are often encountered */ const char *c_a_dtype = "a-dtype"; const char *c_name = "name"; const char *c_type = "type"; const char *c_ref_id = "ref_id"; const char *c_max_prop = "max"; const char *c_min_prop = "min"; const char *c_size_prop = "size"; const char *c_sys_prop = "sys_id"; /* * prop_is_type() checks the supplied property and returns PO_TRUE if the * property value is set for the property else PO_FALSE */ static int prop_is_type(int, const pool_prop_t *); static int resource_get_common(const pool_resource_t *, const char *, uint64_t *); static int64_t elem_get_expected_int64(const pool_elem_t *, const char *); /* * The following returns a malloc'ed string which must be free'd by the * caller. */ static char *elem_get_expected_string(const pool_elem_t *, const char *); static int element_props_init(pool_prop_t *); /* * Each element class/sub-class has a set of properties and behaviours * which are used to create the element with appropriate property * values and to ensure correct property manipulations. The details * are all stored in the following arrays. */ static int elem_name_init(pool_prop_t *); static int elem_comment_init(pool_prop_t *); static int pool_importance_init(pool_prop_t *); static int pool_active_init(pool_prop_t *); static int res_max_init(pool_prop_t *); static int res_min_init(pool_prop_t *); static int res_size_init(pool_prop_t *); static int res_load_init(pool_prop_t *); static int pset_units_init(pool_prop_t *); static int cpu_status_init(pool_prop_t *); static int elem_no_set(pool_elem_t *, const pool_value_t *); static int elem_set_name(pool_elem_t *, const pool_value_t *); static int elem_get_type(const pool_elem_t *, pool_value_t *); static int elem_set_string(pool_elem_t *, const pool_value_t *); static int elem_set_bool(pool_elem_t *, const pool_value_t *); static int elem_set_uint(pool_elem_t *, const pool_value_t *); static int system_set_allocate(pool_elem_t *, const pool_value_t *); static int pool_set_scheduler(pool_elem_t *, const pool_value_t *); static int pool_set_active(pool_elem_t *, const pool_value_t *); static int res_set_max(pool_elem_t *, const pool_value_t *); static int res_set_min(pool_elem_t *, const pool_value_t *); static int cpu_set_status(pool_elem_t *, const pool_value_t *); static const char *pool_elem_class_name[] = { "invalid", "system", "pool", "component resource", "aggregate resource", "component" }; /* * This must be kept in sync with the pool_resource_elem_ctl array and * the "enum pool_resource_elem_class" type. */ static const char *pool_resource_elem_class_name[] = { "invalid", "pset" }; static const char *pool_component_elem_class_name[] = { "invalid", "cpu" }; static pool_prop_t system_props[] = { { "system.name", POOL_VALUE_INITIALIZER, PP_STORED, NULL, { NULL, elem_set_name } }, { "system.ref_id", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, { "system.comment", POOL_VALUE_INITIALIZER, PP_STORED, NULL, NULL }, { "system.version", POOL_VALUE_INITIALIZER, PP_STORED | PP_READ, NULL, NULL }, { "system.bind-default", POOL_VALUE_INITIALIZER, PP_STORED, NULL, NULL }, { "system.allocate-method", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL, { NULL, system_set_allocate } }, { "system.poold.log-level", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, { "system.poold.log-location", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, { "system.poold.monitor-interval", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_uint } }, { "system.poold.history-file", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, { "system.poold.objectives", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, NULL }; static pool_prop_t pool_props[] = { { "pool.sys_id", POOL_VALUE_INITIALIZER, PP_STORED | PP_READ, NULL, NULL }, { "pool.name", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, elem_name_init, { NULL, elem_set_name } }, { "pool.res", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, { "pool.ref_id", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, { "pool.active", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, pool_active_init, { NULL, pool_set_active } }, { "pool.default", POOL_VALUE_INITIALIZER, PP_STORED | PP_READ, NULL, NULL }, { "pool.scheduler", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL, { NULL, pool_set_scheduler } }, { "pool.importance", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, pool_importance_init, NULL }, { "pool.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, elem_comment_init, NULL }, NULL }; static pool_prop_t pset_props[] = { { "type", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL, { elem_get_type, NULL } }, { "pset.sys_id", POOL_VALUE_INITIALIZER, PP_STORED | PP_READ, NULL, NULL }, { "pset.name", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, elem_name_init, { NULL, elem_set_name } }, { "pset.ref_id", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, { "pset.default", POOL_VALUE_INITIALIZER, PP_STORED | PP_READ, NULL, NULL }, { "pset.min", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, res_min_init, { NULL, res_set_min } }, { "pset.max", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, res_max_init, { NULL, res_set_max } }, { "pset.units", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, pset_units_init, NULL }, { "pset.load", POOL_VALUE_INITIALIZER, PP_READ | PP_INIT, res_load_init, NULL }, { "pset.size", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT | PP_READ, res_size_init, NULL }, { "pset.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, elem_comment_init, NULL }, { "pset.poold.objectives", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_string } }, NULL }; static pool_prop_t cpu_props[] = { { "type", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL, { elem_get_type, NULL } }, { "cpu.sys_id", POOL_VALUE_INITIALIZER, PP_STORED | PP_READ, NULL, NULL }, { "cpu.ref_id", POOL_VALUE_INITIALIZER, PP_HIDDEN | PP_STORED | PP_READ, NULL, { NULL, elem_no_set } }, { "cpu.comment", POOL_VALUE_INITIALIZER, PP_STORED | PP_INIT, elem_comment_init, NULL }, { "cpu.status", POOL_VALUE_INITIALIZER, PP_INIT, cpu_status_init, { NULL, cpu_set_status } }, { "cpu.pinned", POOL_VALUE_INITIALIZER, PP_STORED | PP_OPTIONAL, NULL, { NULL, elem_set_bool } }, NULL }; static pool_prop_t *pool_elem_ctl[] = { NULL, system_props, pool_props, NULL, NULL, NULL }; /* * This must be kept in sync with the pool_resource_elem_class_name array and * the "enum pool_resource_elem_class" type. */ static pool_prop_t *pool_resource_elem_ctl[] = { NULL, pset_props }; static pool_prop_t *pool_component_elem_ctl[] = { NULL, cpu_props }; static void atom_init(void) { (void) mutex_lock(&_atom_lock); /* * Initialize pool_value_t atom dictionary */ if (_pv_atoms == NULL) if ((_pv_atoms = dict_new((int (*)(const void *, const void *)) strcmp, (uint64_t (*)(const void *))hash_str)) == NULL) abort(); (void) mutex_unlock(&_atom_lock); } /* * Initializer, called when the library is initialized. */ void internal_init(void) { (void) mutex_lock(&_internal_lock); if (_libpool_internal_initialised == PO_TRUE) { (void) mutex_unlock(&_internal_lock); return; } atom_init(); /* * Initialize all available property arrays. */ if (element_props_init(system_props) == PO_FAIL) abort(); if (element_props_init(pool_props) == PO_FAIL) abort(); if (element_props_init(pset_props) == PO_FAIL) abort(); if (element_props_init(cpu_props) == PO_FAIL) abort(); _libpool_internal_initialised = PO_TRUE; (void) mutex_unlock(&_internal_lock); } static int element_props_init(pool_prop_t *props) { int i; for (i = 0; props[i].pp_pname != NULL; i++) { /* * Initialise each of the properties */ if (pool_value_set_name(&props[i].pp_value, props[i].pp_pname) != PO_SUCCESS) { return (PO_FAIL); } if (props[i].pp_init && props[i].pp_init(&props[i]) != PO_SUCCESS) { return (PO_FAIL); } } return (PO_SUCCESS); } /* * These functions intialise the properties of this plugin. The only reason * they exist is because the ability to perform the static initialisation of * union members properly was only introduced in the C99 standard. i.e. if you * could do {.f = 1.0} like in the proposed C99 standard then that would * be the preferred way to do this as it keeps the data in the array and * minimises the scope for errors. However, until that time these functions * are the best way to minimise the scope for errors and to maximise * maintainability. * * There is one function for each property, and the initial value for each * property is hard-coded into each function. */ static int elem_name_init(pool_prop_t *prop) { return (string_init(prop, "default")); } static int elem_comment_init(pool_prop_t *prop) { return (string_init(prop, "")); } static int pool_importance_init(pool_prop_t *prop) { return (int_init(prop, 1)); } static int pool_active_init(pool_prop_t *prop) { return (bool_init(prop, PO_TRUE)); } static int res_max_init(pool_prop_t *prop) { return (uint_init(prop, 0)); } static int res_min_init(pool_prop_t *prop) { return (uint_init(prop, 0)); } static int res_size_init(pool_prop_t *prop) { return (uint_init(prop, 0)); } static int res_load_init(pool_prop_t *prop) { return (uint_init(prop, 0)); } static int pset_units_init(pool_prop_t *prop) { return (string_init(prop, "population")); } static int cpu_status_init(pool_prop_t *prop) { return (string_init(prop, PS_ONLINE)); } /* * Individual property manipulation routines for use by the generic * get/put property routines */ /* * Many properties cannot be modified. This function prevents property * modification. */ /* ARGSUSED */ static int elem_no_set(pool_elem_t *elem, const pool_value_t *pval) { return (PO_FAIL); } /* * Duplicate names for a pool or resource type are illegal. */ static int elem_set_name(pool_elem_t *elem, const pool_value_t *pval) { const char *nm; pool_t *pool; pool_resource_t *res; if (pool_value_get_string(pval, &nm) != PO_SUCCESS) { return (PO_FAIL); } if (!is_valid_name(nm)) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } switch (pool_elem_class(elem)) { case PEC_SYSTEM: break; case PEC_POOL: pool = pool_get_pool(TO_CONF(elem), nm); if (pool != NULL && pool != pool_elem_pool(elem)) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } break; case PEC_RES_COMP: case PEC_RES_AGG: res = pool_get_resource(TO_CONF(elem), pool_elem_class_string(elem), nm); if (res != NULL && res != pool_elem_res(elem)) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } break; default: return (PO_FAIL); } return (PO_SUCCESS); } /* * Ensure the type is a string. */ /* ARGSUSED */ static int elem_set_string(pool_elem_t *elem, const pool_value_t *pval) { if (pool_value_get_type(pval) == POC_STRING) return (PO_SUCCESS); else { pool_seterror(POE_BADPARAM); return (PO_FAIL); } } /* * Ensure the type is a boolean. */ /* ARGSUSED */ static int elem_set_bool(pool_elem_t *elem, const pool_value_t *pval) { if (pool_value_get_type(pval) == POC_BOOL) return (PO_SUCCESS); else { pool_seterror(POE_BADPARAM); return (PO_FAIL); } } /* * Ensure the type is an unsigned int. */ /* ARGSUSED */ static int elem_set_uint(pool_elem_t *elem, const pool_value_t *pval) { if (pool_value_get_type(pval) == POC_UINT) return (PO_SUCCESS); else { pool_seterror(POE_BADPARAM); return (PO_FAIL); } } /* ARGSUSED */ int system_set_allocate(pool_elem_t *elem, const pool_value_t *pval) { const char *sval; if (pool_value_get_string(pval, &sval) != PO_SUCCESS) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } if (strcmp(POA_IMPORTANCE, sval) != 0 && strcmp(POA_SURPLUS_TO_DEFAULT, sval) != 0) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } return (PO_SUCCESS); } /* ARGSUSED */ int pool_set_active(pool_elem_t *elem, const pool_value_t *pval) { uchar_t bval; if (pool_value_get_type(pval) != POC_BOOL) { pool_seterror(POE_BADPARAM); return (PO_FAIL); } (void) pool_value_get_bool(pval, &bval); if (bval != 1) { /* * "active" must be true on pools for * now. */ pool_seterror(POE_BADPARAM); return (PO_FAIL); } return (PO_SUCCESS); } /* ARGSUSED */ int pool_set_scheduler(pool_elem_t *elem, const pool_value_t *pval) { pcinfo_t pcinfo; const char *sched; if (pool_value_get_string(pval, &sched) != 0) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } (void) strncpy(pcinfo.pc_clname, sched, PC_CLNMSZ); if (priocntl(0, 0, PC_GETCID, &pcinfo) == -1) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } return (PO_SUCCESS); } static int res_set_max(pool_elem_t *elem, const pool_value_t *pval) { uint64_t min, max; pool_value_t val = POOL_VALUE_INITIALIZER; /* * max must be a uint */ if (pool_value_get_uint64(pval, &max) != PO_SUCCESS) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } /* * max can't be less than min (if it exists) */ if (pool_get_ns_property(elem, c_min_prop, &val) == POC_INVAL) return (PO_SUCCESS); if (pool_value_get_uint64(&val, &min) != PO_SUCCESS) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } if (max < min) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } /* * Ensure that changes to the max in a dynamic configuration * are still valid. */ if (conf_is_dynamic(TO_CONF(elem)) == PO_TRUE) { uint64_t oldmax; if (pool_get_ns_property(elem, c_max_prop, &val) == POC_INVAL) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } if (pool_value_get_uint64(&val, &oldmax) != PO_SUCCESS) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } if (max < oldmax) { /* * Ensure that the modified total max is >= size * of all resources of this type */ return (pool_validate_resource(TO_CONF(elem), pool_elem_class_string(elem), c_max_prop, max - oldmax)); } } return (PO_SUCCESS); } static int res_set_min(pool_elem_t *elem, const pool_value_t *pval) { uint64_t min, max; pool_value_t val = POOL_VALUE_INITIALIZER; /* * min must be a uint */ if (pool_value_get_uint64(pval, &min) != PO_SUCCESS) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } /* * min can't be more than max (if it exists) */ if (pool_get_ns_property(elem, c_max_prop, &val) == POC_INVAL) return (PO_SUCCESS); if (pool_value_get_uint64(&val, &max) != PO_SUCCESS) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } if (min > max) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } switch (pool_resource_elem_class(elem)) { case PREC_PSET: if (resource_is_default(pool_elem_res(elem))) { if (min < 1) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } } break; default: break; } /* * Ensure that changes to the min in a dynamic configuration * are still valid. */ if (conf_is_dynamic(TO_CONF(elem)) == PO_TRUE) { uint64_t oldmin; if (pool_get_ns_property(elem, c_min_prop, &val) == POC_INVAL) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } if (pool_value_get_uint64(&val, &oldmin) != PO_SUCCESS) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } if (min > oldmin) { /* * Ensure that the modified total min is <= size * of all resources of this type */ return (pool_validate_resource(TO_CONF(elem), pool_elem_class_string(elem), c_min_prop, min - oldmin)); } } return (PO_SUCCESS); } /* ARGSUSED */ int cpu_set_status(pool_elem_t *elem, const pool_value_t *pval) { const char *status; if (pool_value_get_string(pval, &status) != 0) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } if (strcmp(PS_ONLINE, status) != 0 && strcmp(PS_OFFLINE, status) != 0 && strcmp(PS_NOINTR, status) != 0 && strcmp(PS_SPARE, status) != 0 && strcmp(PS_FAULTED, status) != 0) { pool_seterror(POE_PUTPROP); return (PO_FAIL); } return (PO_SUCCESS); } static int elem_get_type(const pool_elem_t *elem, pool_value_t *pval) { if (pool_value_set_string(pval, pool_elem_class_string(elem)) == PO_FAIL) return (PO_FAIL); return (PO_SUCCESS); } /* * More general utilities */ /* * Is the supplied configuration the dynamic configuration * Return: PO_TRUE/PO_FALSE */ int conf_is_dynamic(const pool_conf_t *conf) { if (strcmp(pool_conf_location(conf), pool_dynamic_location()) == 0) return (PO_TRUE); return (PO_FALSE); } /* * uint_init() initialises the value of the supplied property with the * supplied value. * Returns PO_SUCCESS */ int uint_init(pool_prop_t *prop, uint64_t val) { pool_value_set_uint64(&prop->pp_value, val); return (PO_SUCCESS); } /* * int_init() initialises the value of the supplied property with the * supplied value. * Returns PO_SUCCESS */ int int_init(pool_prop_t *prop, int64_t val) { pool_value_set_int64(&prop->pp_value, val); return (PO_SUCCESS); } /* * double_init() initialises the value of the supplied property with the * supplied value. * Returns PO_SUCCESS */ int double_init(pool_prop_t *prop, double val) { pool_value_set_double(&prop->pp_value, val); return (PO_SUCCESS); } /* * bool_init() initialises the value of the supplied property with the * supplied value. * Returns PO_SUCCESS */ int bool_init(pool_prop_t *prop, uchar_t val) { pool_value_set_bool(&prop->pp_value, val); return (PO_SUCCESS); } /* * string_init() initialises the value of the supplied property with the * supplied value. * Returns PO_SUCCESS/PO_FAIL */ int string_init(pool_prop_t *prop, const char *val) { return (pool_value_set_string(&prop->pp_value, val)); } /* * pool_get_provider_count() returns the count of registered providers. * * Returns count of registered providers */ uint_t pool_get_provider_count(void) { uint_t count = 0; int i; for (i = 0; i < sizeof (pool_resource_elem_ctl) / sizeof (pool_resource_elem_ctl[0]); i++) { if (pool_resource_elem_ctl[i] != NULL) count++; } return (count); } /* * Return all the props for a specified provider */ const pool_prop_t * provider_get_props(const pool_elem_t *elem) { const pool_prop_t *prop_list = NULL; pool_elem_class_t elem_class = pool_elem_class(elem); switch (elem_class) { case PEC_SYSTEM: case PEC_POOL: prop_list = pool_elem_ctl[elem_class]; break; case PEC_RES_AGG: case PEC_RES_COMP: prop_list = pool_resource_elem_ctl [pool_resource_elem_class(elem)]; break; case PEC_COMP: prop_list = pool_component_elem_ctl [pool_component_elem_class(elem)]; break; } return (prop_list); } /* * provider_get_prop() return the pool_prop_t structure which * describes the supplied property name for the supplied provider. * * Returns the property description or NULL if it doesn't exist. */ const pool_prop_t * provider_get_prop(const pool_elem_t *elem, const char *name) { int i; const pool_prop_t *prop_list; if ((prop_list = provider_get_props(elem)) == NULL) return (NULL); for (i = 0; prop_list[i].pp_pname != NULL; i++) { if (strcmp(name, prop_list[i].pp_pname) == 0) { return (&prop_list[i]); } } return (NULL); } /* * prop_is_type() checks the supplied property and returns PO_TRUE if the * property value is 1 else PO_FALSE */ static int prop_is_type(int prop_type, const pool_prop_t *prop) { return ((prop->pp_perms & prop_type) ? PO_TRUE : PO_FALSE); } /* * prop_is_stored() returns PO_TRUE if the property is stored in the backing * configuration and PO_FALSE else. */ int prop_is_stored(const pool_prop_t *prop) { return (prop_is_type(PP_STORED, prop)); } /* * prop_is_readonly() returns PO_TRUE if the property is a read-only property * and PO_FALSE else. */ int prop_is_readonly(const pool_prop_t *prop) { return (prop_is_type(PP_READ, prop)); } /* * prop_is_init() returns PO_TRUE if the property should be * initialised when an element of this type is created and PO_FALSE * else. */ int prop_is_init(const pool_prop_t *prop) { return (prop_is_type(PP_INIT, prop)); } /* * prop_is_hidden() returns PO_TRUE if the property should be hidden * from access by the external property access mechanisms. */ int prop_is_hidden(const pool_prop_t *prop) { return (prop_is_type(PP_HIDDEN, prop)); } /* * prop_is_optional() returns PO_TRUE if the property is optional and * can be removed by external property access mechanisms. */ int prop_is_optional(const pool_prop_t *prop) { return (prop_is_type(PP_OPTIONAL, prop)); } int cpu_is_requested(pool_component_t *component) { pool_value_t val = POOL_VALUE_INITIALIZER; uchar_t requested; if (pool_get_property(TO_CONF(TO_ELEM(component)), TO_ELEM(component), "cpu.requested", &val) != POC_BOOL) { return (PO_FALSE); } if (pool_value_get_bool(&val, &requested) != PO_SUCCESS) { return (PO_FALSE); } return ((int)requested); } /* * Common code for various resource get functions */ static int resource_get_common(const pool_resource_t *res, const char *name, uint64_t *uval) { pool_value_t val = POOL_VALUE_INITIALIZER; pool_value_class_t pvc; int retval = PO_SUCCESS; pvc = pool_get_ns_property(TO_ELEM(res), name, &val); if (pvc == POC_INVAL) { *uval = 0; #ifdef DEBUG dprintf("can't retrieve %s\n"); pool_elem_dprintf(TO_ELEM(res)); #endif /* DEBUG */ } else if (pvc == POC_UINT) { retval = pool_value_get_uint64(&val, uval); } return (retval); } /* * resource_get_size() updates size with the size of the supplied resource. * * Returns PO_SUCCESS/PO_FAIL */ int resource_get_size(const pool_resource_t *res, uint64_t *size) { return (resource_get_common(res, c_size_prop, size)); } /* * resource_get_pinned() updates pinned with the size of the * pinned part of a supplied resource. Resource is not available for * allocation if it is marked as "pinned". * * Returns PO_SUCCESS/PO_FAIL */ int resource_get_pinned(const pool_resource_t *res, uint64_t *pinned) { pool_value_t *props[] = { NULL, NULL }; pool_value_t val = POOL_VALUE_INITIALIZER; pool_component_t **cs = NULL; uint_t ncompelem; props[0] = &val; pool_value_set_bool(props[0], PO_TRUE); if (pool_value_set_name(props[0], "cpu.pinned") != PO_SUCCESS) return (PO_FAIL); if ((cs = pool_query_resource_components(TO_CONF(TO_ELEM(res)), res, &ncompelem, props)) != NULL) { *pinned = ncompelem; free(cs); } else *pinned = 0; return (PO_SUCCESS); } /* * resource_get_min() updates min with the minimum size of the supplied * resource. * * Returns PO_SUCCESS/PO_FAIL */ int resource_get_min(const pool_resource_t *res, uint64_t *min) { return (resource_get_common(res, c_min_prop, min)); } /* * resource_get_max() updates max with the maximum size of the supplied * resource. * * Returns PO_SUCCESS/PO_FAIL */ int resource_get_max(const pool_resource_t *res, uint64_t *max) { return (resource_get_common(res, c_max_prop, max)); } /* * TODO: This is pset specific * * get_default_resource() returns the default resource for type of the supplied * resource. * * Returns A pointer to the default resource of the same type as the supplied * resource. */ const pool_resource_t * get_default_resource(const pool_resource_t *res) { return (resource_by_sysid(TO_CONF(TO_ELEM(res)), PS_NONE, pool_elem_class_string(TO_ELEM(res)))); } /* * resource_is_default() returns 1 if the supplied resource is the default * resource for it's type. */ int resource_is_default(const pool_resource_t *res) { return (get_default_resource(res) == res); } /* * resource_is_system() determines if the resource is a system resource. */ int resource_is_system(const pool_resource_t *res) { return (res->pr_is_system(res)); } /* * resource_can_associate() determines if it is possible to associate * with the supplied resource. */ int resource_can_associate(const pool_resource_t *res) { return (res->pr_can_associate(res)); } /* * Common code to get an int64 property. * Unfortunately (-1) is a valid psetid, so we'll return (-2) in case of * error. */ static int64_t elem_get_expected_int64(const pool_elem_t *elem, const char *name) { int64_t val64; pool_value_t val = POOL_VALUE_INITIALIZER; if (pool_get_ns_property(elem, name, &val) != POC_INT) { return (POOL_SYSID_BAD); } (void) pool_value_get_int64(&val, &val64); return (val64); } /* * The following returns a malloc'ed string which must be free'd by the * caller. */ static char * elem_get_expected_string(const pool_elem_t *elem, const char *name) { pool_value_t val = POOL_VALUE_INITIALIZER; char *retval; if (pool_get_ns_property(elem, name, &val) != POC_STRING) { return (NULL); } (void) pool_value_get_string(&val, (const char **)&retval); retval = strdup(retval); return (retval); } /* * elem_get_sysid() returns the sys_id for the supplied elem. */ id_t elem_get_sysid(const pool_elem_t *elem) { return ((id_t)elem_get_expected_int64(elem, c_sys_prop)); } /* * elem_get_name() returns the name for the supplied elem. Note that * it is the caller's responsibility to free this memory. */ char * elem_get_name(const pool_elem_t *elem) { return (elem_get_expected_string(elem, c_name)); } /* * elem_is_default() returns 1 if the supplied elem is the default * elem for it's type. */ int elem_is_default(const pool_elem_t *res) { return (get_default_elem(res) == res); } /* * Return B_TRUE if the element has the 'temporary' property set. */ boolean_t elem_is_tmp(const pool_elem_t *elem) { pool_value_t val = POOL_VALUE_INITIALIZER; uchar_t bval; if (pool_get_ns_property(elem, "temporary", &val) != POC_BOOL) return (B_FALSE); (void) pool_value_get_bool(&val, &bval); return (bval != 0); } /* * get_default_elem() returns the default elem for type of the supplied * elem. * * Returns A pointer to the default elem of the same type as the * supplied elem or NULL on error. Trying to access the default elem * for a type of element which doesn't support the notion of default * is an error. */ const pool_elem_t * get_default_elem(const pool_elem_t *pe) { pool_result_set_t *rs; pool_value_t *props[] = { NULL, NULL }; pool_value_t val = POOL_VALUE_INITIALIZER; char_buf_t *cb; const pool_elem_t *pe_default; props[0] = &val; if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { return (NULL); } if (set_char_buf(cb, "%s.default", pool_elem_class_string(pe)) != PO_SUCCESS) { free_char_buf(cb); return (NULL); } if (pool_value_set_name(props[0], cb->cb_buf) != PO_SUCCESS) { free_char_buf(cb); return (NULL); } free_char_buf(cb); pool_value_set_bool(props[0], PO_TRUE); if ((rs = pool_exec_query(TO_CONF(pe), NULL, NULL, PEC_QRY_ELEM(pe), props)) == NULL) { pool_seterror(POE_INVALID_CONF); return (NULL); } if (pool_rs_count(rs) != 1) { (void) pool_rs_close(rs); pool_seterror(POE_INVALID_CONF); return (NULL); } pe_default = rs->prs_next(rs); (void) pool_rs_close(rs); return (pe_default); } /* * is_a_known_prefix() determines if the supplied prop_name is a known * name for the supplied class. * * Returns a pointer to the prefix if it is found or NULL */ const char * is_a_known_prefix(pool_elem_class_t class, const char *prop_name) { int i; int len; switch (class) { case PEC_SYSTEM: case PEC_POOL: len = strlen(pool_elem_class_name[class]); if (strncmp(prop_name, pool_elem_class_name[class], len) == 0 && prop_name[len] == '.' || strcmp(prop_name, c_type) == 0) return (pool_elem_class_name[class]); break; case PEC_RES_COMP: case PEC_RES_AGG: for (i = 0; i < sizeof (pool_resource_elem_class_name) / sizeof (pool_resource_elem_class_name[0]); i++) { len = strlen(pool_resource_elem_class_name[i]); if (strncmp(prop_name, pool_resource_elem_class_name[i], len) == 0 && prop_name[len] == '.' || strcmp(prop_name, c_type) == 0) return (pool_resource_elem_class_name[i]); } break; case PEC_COMP: for (i = 0; i < sizeof (pool_component_elem_class_name) / sizeof (pool_component_elem_class_name[0]); i++) { len = strlen(pool_component_elem_class_name[i]); if (strncmp(prop_name, pool_component_elem_class_name[i], len) == 0 && prop_name[len] == '.' || strcmp(prop_name, c_type) == 0) return (pool_component_elem_class_name[i]); } break; default: break; } return (NULL); } const char * pool_elem_class_string(const pool_elem_t *pe) { switch (pool_elem_class(pe)) { case PEC_SYSTEM: case PEC_POOL: return (pool_elem_class_name[pool_elem_class(pe)]); case PEC_RES_COMP: case PEC_RES_AGG: return (pool_resource_elem_class_name [pool_resource_elem_class(pe)]); case PEC_COMP: return (pool_component_elem_class_name [pool_component_elem_class(pe)]); default: return (pool_elem_class_name[PEC_INVALID]); } } const char * pool_resource_type_string(pool_resource_elem_class_t type) { return (pool_resource_elem_class_name[type]); } const char * pool_component_type_string(pool_component_elem_class_t type) { return (pool_component_elem_class_name[type]); } /* * resource_by_sysid() finds a resource from it's supplied sysid and type. * * Returns a pointer to the resource or NULL if it doesn't exist. */ pool_resource_t * resource_by_sysid(const pool_conf_t *conf, id_t sysid, const char *type) { pool_value_t *props[] = { NULL, NULL, NULL }; pool_resource_t **resources = NULL; pool_resource_t *retval = NULL; uint_t nelem; char_buf_t *cb; pool_value_t val0 = POOL_VALUE_INITIALIZER; pool_value_t val1 = POOL_VALUE_INITIALIZER; props[0] = &val0; props[1] = &val1; if (pool_value_set_string(props[0], type) != PO_SUCCESS || pool_value_set_name(props[0], c_type) != PO_SUCCESS) return (NULL); if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { return (NULL); } if (set_char_buf(cb, "%s.sys_id", type) != PO_SUCCESS) { free_char_buf(cb); return (NULL); } if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) { free_char_buf(cb); return (NULL); } free_char_buf(cb); pool_value_set_int64(props[1], sysid); resources = pool_query_resources(conf, &nelem, props); if (resources != NULL) { retval = resources[0]; free(resources); } return (retval); } pool_elem_class_t pool_elem_class_from_string(const char *type) { int i; for (i = 0; i < sizeof (pool_elem_class_name) / sizeof (pool_elem_class_name[0]); i++) { if (strcmp(pool_elem_class_name[i], type) == 0) break; } if (i == sizeof (pool_elem_class_name) / sizeof (pool_elem_class_name[0])) return (PEC_INVALID); return ((pool_elem_class_t)i); } pool_resource_elem_class_t pool_resource_elem_class_from_string(const char *type) { int i; for (i = 0; i < sizeof (pool_resource_elem_class_name) / sizeof (pool_resource_elem_class_name[0]); i++) { if (strcmp(pool_resource_elem_class_name[i], type) == 0) break; } if (i == sizeof (pool_resource_elem_class_name) / sizeof (pool_resource_elem_class_name[0])) return (PREC_INVALID); return ((pool_resource_elem_class_t)i); } pool_component_elem_class_t pool_component_elem_class_from_string(const char *type) { int i; for (i = 0; i < sizeof (pool_component_elem_class_name) / sizeof (pool_component_elem_class_name[0]); i++) { if (strcmp(pool_component_elem_class_name[i], type) == 0) break; } if (i == sizeof (pool_component_elem_class_name) / sizeof (pool_component_elem_class_name[0])) return (PCEC_INVALID); return ((pool_component_elem_class_t)i); } /* * pool_resource_type_list() populates the supplied array of pointers * with the names of the available resource types on this system. */ int pool_resource_type_list(const char **types, uint_t *numtypes) { int i, j; uint_t maxnum = *numtypes; *numtypes = pool_get_provider_count(); if (types) { for (i = 0, j = 0; i < sizeof (pool_resource_elem_ctl) / sizeof (pool_resource_elem_ctl[0]) && j < maxnum; i++) { if (pool_resource_elem_ctl[i] != NULL) types[j++] = pool_resource_elem_class_name[i]; } } return (PO_SUCCESS); } /* * Return the system element for the supplied conf. * NULL is returned if an error is detected and the error code is updated * to indicate the cause of the error. */ pool_system_t * pool_conf_system(const pool_conf_t *conf) { pool_elem_t *system; pool_result_set_t *rs; if ((rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_SYSTEM, NULL)) == NULL) { pool_seterror(POE_INVALID_CONF); return (NULL); } /* There should only be one system record */ if (pool_rs_count(rs) != 1) { pool_seterror(POE_INVALID_CONF); (void) pool_rs_close(rs); return (NULL); } system = rs->prs_next(rs); (void) pool_rs_close(rs); return (pool_elem_system(system)); } pool_system_t * pool_elem_system(const pool_elem_t *pe) { if (pe->pe_class != PEC_SYSTEM) { pool_seterror(POE_BADPARAM); return (NULL); } return ((pool_system_t *)pe); } pool_t * pool_elem_pool(const pool_elem_t *pe) { if (pe->pe_class != PEC_POOL) { pool_seterror(POE_BADPARAM); return (NULL); } return ((pool_t *)pe); } pool_resource_t * pool_elem_res(const pool_elem_t *pe) { if (pe->pe_class != PEC_RES_COMP && pool_elem_class(pe) != PEC_RES_AGG) { pool_seterror(POE_BADPARAM); return (NULL); } return ((pool_resource_t *)pe); } pool_component_t * pool_elem_comp(const pool_elem_t *pe) { if (pe->pe_class != PEC_COMP) { pool_seterror(POE_BADPARAM); return (NULL); } return ((pool_component_t *)pe); } /* * qsort_elem_compare() is used for qsort elemement comparison. * * Returns see qsort(3c) */ int qsort_elem_compare(const void *a, const void *b) { const pool_elem_t *e1 = *(const pool_elem_t **)a; const pool_elem_t *e2 = *(const pool_elem_t **)b; /* * Special case for handling name changes on default elements * If both elements are default elements then always return 0 */ if (pool_elem_same_class(e1, e2) == PO_TRUE && (elem_is_default(e1) && elem_is_default(e2))) return (0); else return (pool_elem_compare_name(e1, e2)); } /* * Dynamic character buffers. */ /* * Resize the supplied character buffer to the new size. */ static int resize_char_buf(char_buf_t *cb, size_t size) { char *re_cb = NULL; if ((re_cb = realloc(cb->cb_buf, size)) == NULL) { pool_seterror(POE_SYSTEM); return (PO_FAIL); } /* If inital allocation, make sure buffer is zeroed */ if (cb->cb_buf == NULL) (void) memset(re_cb, 0, sizeof (re_cb)); /* If resized smaller, make sure buffer NULL terminated */ if (size < cb->cb_size) re_cb[size] = 0; cb->cb_buf = re_cb; cb->cb_size = size; return (PO_SUCCESS); } /* * Allocate a new char_buf_t structure. If there isn't enough memory, return * NULL. Initialise the new char_buf_t to 0 and then call resize_char_buf * to initialise the character buffer. Return a pointer to the new * char_buf_t if the operation succeeds. */ char_buf_t * alloc_char_buf(size_t size) { char_buf_t *cb; if ((cb = malloc(sizeof (char_buf_t))) == NULL) { pool_seterror(POE_SYSTEM); return (NULL); } (void) memset(cb, 0, sizeof (char_buf_t)); if (resize_char_buf(cb, size + 1) == PO_FAIL) { free(cb); return (NULL); } return (cb); } /* * Free the character buffer and then free the char_buf_t. */ void free_char_buf(char_buf_t *cb) { free((void *)cb->cb_buf); free(cb); } /* * Set the character buffer to the supplied data. The user supplies a printf * like format string and then an appropriate number of parameters for the * specified format. The character buffer is automatically resized to fit * the data as determined by resize_char_buf. */ /*PRINTFLIKE2*/ int set_char_buf(char_buf_t *cb, const char *fmt, ...) { va_list ap; int new_size; va_start(ap, fmt); if ((new_size = vsnprintf(cb->cb_buf, cb->cb_size, fmt, ap)) >= cb->cb_size) { if (resize_char_buf(cb, new_size + 1) != PO_SUCCESS) { pool_seterror(POE_SYSTEM); return (PO_FAIL); } (void) vsnprintf(cb->cb_buf, cb->cb_size, fmt, ap); } va_end(ap); return (PO_SUCCESS); } /* * Append the supplied data to the character buffer. The user supplies a printf * like format string and then an appropriate number of parameters for the * specified format. The character buffer is automatically resized to fit * the data as determined by resize_char_buf. */ /*PRINTFLIKE2*/ int append_char_buf(char_buf_t *cb, const char *fmt, ...) { va_list ap; int new_len; char size_buf[1]; int old_len = 0; if (cb->cb_buf != NULL) old_len = strlen(cb->cb_buf); va_start(ap, fmt); new_len = vsnprintf(size_buf, sizeof (size_buf), fmt, ap); if (new_len + old_len >= cb->cb_size) { if (resize_char_buf(cb, old_len + new_len + 1) != PO_SUCCESS) { pool_seterror(POE_SYSTEM); return (PO_FAIL); } } /* * Resized the buffer to the right size, now append the new data */ (void) vsnprintf(&cb->cb_buf[old_len], cb->cb_size - old_len, fmt, ap); va_end(ap); return (PO_SUCCESS); } /* * Return the class for the supplied elem. * If the return is PEC_INVALID, the error code will be set to reflect cause. */ pool_elem_class_t pool_elem_class(const pool_elem_t *elem) { return (elem->pe_class); } /* * Return the resource class for the supplied elem. */ pool_resource_elem_class_t pool_resource_elem_class(const pool_elem_t *elem) { return (elem->pe_resource_class); } /* * Return the component class for the supplied elem. */ pool_component_elem_class_t pool_component_elem_class(const pool_elem_t *elem) { return (elem->pe_component_class); } pool_elem_t * pool_get_pair(const pool_elem_t *pe) { return (pe->pe_pair); } void pool_set_pair(pool_elem_t *pe1, pool_elem_t *pe2) { pe1->pe_pair = pe2; } int pool_validate_resource(const pool_conf_t *conf, const char *type, const char *prop, int64_t delta) { pool_conf_t *dyn; uint_t nelem; uint64_t available, required, uval; int i; pool_resource_t **rl; pool_value_t val = POOL_VALUE_INITIALIZER; pool_value_t val1 = POOL_VALUE_INITIALIZER; pool_value_t *pvals[] = { NULL, NULL }; if (strcmp(prop, c_min_prop) && strcmp(prop, c_max_prop)) { pool_seterror(POE_BADPARAM); return (PO_FAIL); } pvals[0] = &val; (void) pool_value_set_string(&val, type); (void) pool_value_set_name(&val, c_type); /* * Check that there are available resources on this * system for this configuration to be applied. Find * each resource type and then find all resources of * each type and total ".min". Find all available * resources and ensure >= total min. */ available = 0; required = delta; if ((rl = (pool_query_resources(conf, &nelem, pvals))) == NULL) return (PO_FAIL); for (i = 0; i < nelem; i++) { if (pool_get_ns_property(TO_ELEM(rl[i]), prop, &val1) == POC_INVAL || pool_value_get_uint64(&val1, &uval) != PO_SUCCESS) { free(rl); return (PO_FAIL); } /* * Watch out for overflow */ if (required + uval < required) { required = UINT64_MAX; break; } else required += uval; } if (conf_is_dynamic(conf) == PO_TRUE) { dyn = (pool_conf_t *)conf; } else { free(rl); if ((dyn = pool_conf_alloc()) == NULL) return (PO_FAIL); if (pool_conf_open(dyn, pool_dynamic_location(), PO_RDONLY) != PO_SUCCESS) { pool_conf_free(dyn); return (PO_FAIL); } if ((rl = (pool_query_resources(dyn, &nelem, pvals))) == NULL) { (void) pool_conf_close(dyn); pool_conf_free(dyn); return (PO_FAIL); } } for (i = 0; i < nelem; i++) { if (pool_get_ns_property(TO_ELEM(rl[i]), c_size_prop, &val1) == POC_INVAL || pool_value_get_uint64(&val1, &uval) != PO_SUCCESS) { free(rl); if (conf != dyn) { (void) pool_conf_close(dyn); pool_conf_free(dyn); } return (PO_FAIL); } available += uval; } free(rl); if (conf != dyn) { (void) pool_conf_close(dyn); pool_conf_free(dyn); } if (strcmp(prop, c_min_prop) == 0) { if (available < required) { pool_seterror(POE_INVALID_CONF); return (PO_FAIL); } } else { if (available > required) { pool_seterror(POE_INVALID_CONF); return (PO_FAIL); } } return (PO_SUCCESS); } /* * If _libpool_debug is set, printf the debug message to stderr with an * appropriate prefix in front of it. */ void do_dprintf(const char *format, va_list ap) { if (_libpool_debug) { (void) fputs("libpool DEBUG: ", stderr); (void) vfprintf(stderr, format, ap); } } /*PRINTFLIKE1*/ void dprintf(const char *format, ...) { if (_libpool_debug) { va_list alist; va_start(alist, format); do_dprintf(format, alist); va_end(alist); } } /* * log_alloc() allocates a new, empty transaction log. * * Returns a pointer to the new log or NULL on failure. */ log_t * log_alloc(pool_conf_t *conf) { log_t *l; if ((l = calloc(1, sizeof (log_t))) == NULL) { pool_seterror(POE_SYSTEM); return (NULL); } l->l_state = LS_DO; l->l_conf = conf; if ((l->l_sentinel = log_item_alloc(l, 0, NULL)) == NULL) { free(l); pool_seterror(POE_SYSTEM); return (NULL); } l->l_sentinel->li_next = l->l_sentinel; l->l_sentinel->li_prev = l->l_sentinel; return (l); } /* * log_free() reclaims the resources associated with a transaction log. */ void log_free(log_t *l) { (void) log_walk(l, log_item_free); (void) log_item_free(l->l_sentinel); free(l); } /* * log_empty() removes all items from a transaction log. It is the * users responsibility to ensure that any resources associated with * an item are reclaimed before this function is invoked. */ void log_empty(log_t *l) { (void) log_walk(l, log_item_free); } /* * log_walk() visits each log item in turn and executes the supplied action * using the item as a parameter. If no action is supplied, then the item * uses it's own stored action. * * Returns PO_SUCCESS/PO_FAIL */ int log_walk(log_t *l, log_item_action_t action) { log_item_t *li, *li_next; li = l->l_sentinel->li_next; while (li != l->l_sentinel) { li_next = li->li_next; if ((action(li)) != PO_SUCCESS) return (PO_FAIL); li = li_next; } return (PO_SUCCESS); } /* * log_reverse_walk() visits each log item in turn (in reverse order) * and executes the supplied action using the item as a parameter. * * Returns PO_SUCCESS/PO_FAIL */ int log_reverse_walk(log_t *l, log_item_action_t action) { log_item_t *li, *li_prev; li = l->l_sentinel->li_prev; while (li != l->l_sentinel) { li_prev = li->li_prev; if ((action(li)) != PO_SUCCESS) return (PO_FAIL); li = li_prev; } return (PO_SUCCESS); } /* * log_size() returns the size of the log, i.e. the number of items pending in * the log. */ uint_t log_size(log_t *l) { log_item_t *li; uint_t size = 0; for (li = l->l_sentinel->li_next; li != l->l_sentinel; li = li->li_next) size++; return (size); } /* * log_append() allocates a new log item to hold the supplied details and * appends the newly created item to the supplied log. * * Returns PO_SUCCESS/PO_FAIL */ int log_append(log_t *l, int op, void *details) { log_item_t *li; if ((li = log_item_alloc(l, op, details)) == NULL) { l->l_state = LS_UNDO; return (PO_FAIL); } /* * Link it in */ li->li_prev = l->l_sentinel->li_prev; li->li_next = l->l_sentinel; l->l_sentinel->li_prev->li_next = li; l->l_sentinel->li_prev = li; return (PO_SUCCESS); } /* * log_item_alloc() allocates a new transaction log item. The item should be * used to store details about a transaction which may need to be undone if * commit processing fails. * * Returns a pointer to a new transaction log item or NULL. */ log_item_t * log_item_alloc(log_t *l, int op, void *details) { log_item_t *li; if ((li = malloc(sizeof (log_item_t))) == NULL) { pool_seterror(POE_SYSTEM); return (NULL); } (void) memset(li, 0, sizeof (log_item_t)); li->li_log = l; li->li_op = op; li->li_details = details; li->li_state = LS_DO; return (li); } /* * log_item_free() reclaims the resources associated with a log_item_t. */ int log_item_free(log_item_t *li) { li->li_prev->li_next = li->li_next; li->li_next->li_prev = li->li_prev; free(li); return (PO_SUCCESS); } /* * atom_string() checks the string table to see if a string is already * stored. If it is, return a pointer to it. If not, duplicate the * string and return a pointer to the duplicate. */ const char * atom_string(const char *s) { atom_t *atom; /* * atom_init() must have completed successfully */ atom_init(); (void) mutex_lock(&_atom_lock); if ((atom = dict_get(_pv_atoms, s)) == NULL) { if ((atom = calloc(1, sizeof (atom_t))) == NULL) { pool_seterror(POE_SYSTEM); (void) mutex_unlock(&_atom_lock); return (NULL); } if ((atom->a_string = strdup(s)) == NULL) { (void) mutex_unlock(&_atom_lock); free(atom); pool_seterror(POE_SYSTEM); return (NULL); } (void) dict_put(_pv_atoms, atom->a_string, atom); } atom->a_count++; (void) mutex_unlock(&_atom_lock); return (atom->a_string); } /* * atom_free() decrements the reference count for the supplied * string. If the reference count reaches zero, then the atom is * destroyed. */ void atom_free(const char *s) { atom_t *atom; (void) mutex_lock(&_atom_lock); if ((atom = dict_get(_pv_atoms, s)) != NULL) { if (--atom->a_count == 0) { (void) dict_remove(_pv_atoms, s); free(atom->a_string); free(atom); } } (void) mutex_unlock(&_atom_lock); } #ifdef DEBUG /* * log_item_dprintf() prints the contents of the supplied log item using the * pools dprintf() trace mechanism. * * Returns PO_SUCCESS */ void log_item_dprintf(log_item_t *li) { dprintf("LOGDUMP: %d operation, %p\n", li->li_op, li->li_details); } /* * log_item_dprintf() prints the contents of the supplied log item using the * pools dprintf() trace mechanism. * * Returns PO_SUCCESS */ void pool_elem_dprintf(const pool_elem_t *pe) { if (pool_elem_class(pe) != PEC_COMP) { const char *name = elem_get_name(pe); dprintf("element type: %s name: %s\n", pool_elem_class_string(pe), name); free((void *)name); } else { id_t sys_id = elem_get_sysid(pe); dprintf("element type: %s sys_id: %d\n", pool_elem_class_string(pe), sys_id); } } #endif /* DEBUG */