diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
commit | 47e6e7c84f008a53061e661f31ae96629bc694ef (patch) | |
tree | 648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/perl/PMDA/PMDA.xs | |
download | pcp-debian/3.9.10.tar.gz |
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/perl/PMDA/PMDA.xs')
-rw-r--r-- | src/perl/PMDA/PMDA.xs | 1212 |
1 files changed, 1212 insertions, 0 deletions
diff --git a/src/perl/PMDA/PMDA.xs b/src/perl/PMDA/PMDA.xs new file mode 100644 index 0000000..a6d16b2 --- /dev/null +++ b/src/perl/PMDA/PMDA.xs @@ -0,0 +1,1212 @@ +/* + * Copyright (c) 2013-2014 Red Hat. + * Copyright (c) 2008-2012 Aconex. All Rights Reserved. + * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "local.h" +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +static pmdaInterface dispatch; +static pmdaMetric *metrictab; +static int mtab_size; +static __pmnsTree *pmns; +static int need_refresh; +static pmdaIndom *indomtab; +static int itab_size; +static int *clustertab; +static int ctab_size; + +static HV *metric_names; +static HV *metric_oneline; +static HV *metric_helptext; +static HV *indom_helptext; +static HV *indom_oneline; + +static SV *fetch_func; +static SV *refresh_func; +static SV *instance_func; +static SV *store_cb_func; +static SV *fetch_cb_func; + +int +clustertab_lookup(int cluster) +{ + int i, found = 0; + + for (i = 0; i < ctab_size; i++) { + if (cluster == clustertab[i]) { + found = 1; + break; + } + } + return found; +} + +void +clustertab_replace(int index, int cluster) +{ + if (index >= 0 && index < ctab_size) + clustertab[index] = cluster; + else + warn("invalid cluster table replacement requested"); +} + +void +clustertab_scratch() +{ + memset(clustertab, -1, sizeof(int) * ctab_size); +} + +void +clustertab_refresh(int index) +{ + dSP; + ENTER; + SAVETMPS; + PUSHMARK(sp); + XPUSHs(sv_2mortal(newSVuv(clustertab[index]))); + PUTBACK; + + perl_call_sv(refresh_func, G_VOID); + + SPAGAIN; + PUTBACK; + FREETMPS; + LEAVE; +} + +void +refresh(int numpmid, pmID *pmidlist) +{ + int i, numclusters = 0; + __pmID_int *pmid; + + /* Create list of affected clusters from pmidlist + * Note: we overwrite the initial cluster array here, to avoid + * allocating memory. The initial array contains all possible + * clusters whereas we (possibly) construct a subset here. We + * do not touch ctab_size at all, however, which lets us reuse + * the preallocated array space on every fetch. + */ + clustertab_scratch(); + for (i = 0; i < numpmid; i++) { + pmid = (__pmID_int *) &pmidlist[i]; + if (clustertab_lookup(pmid->cluster) == 0) + clustertab_replace(numclusters++, pmid->cluster); + } + + /* For each unique cluster, call the cluster refresh method */ + for (i = 0; i < numclusters; i++) + clustertab_refresh(i); +} + +void +pmns_refresh(void) +{ + char *pmid, *next; + I32 idsize; + SV *metric; + int sts; + + if (pmns) + __pmFreePMNS(pmns); + + if ((sts = __pmNewPMNS(&pmns)) < 0) + croak("failed to create namespace root: %s", pmErrStr(sts)); + + hv_iterinit(metric_names); + while ((metric = hv_iternextsv(metric_names, &pmid, &idsize)) != NULL) { + unsigned int domain, cluster, item, id; + + domain = strtoul(pmid, &next, 10); + cluster = strtoul(next+1, &next, 10); + item = strtoul(next+1, &next, 10); + id = pmid_build(domain, cluster, item); + if ((sts = __pmAddPMNSNode(pmns, id, SvPV_nolen(metric))) < 0) + croak("failed to add metric %s(%s) to namespace: %s", + SvPV_nolen(metric), pmIDStr(id), pmErrStr(sts)); + } + + pmdaTreeRebuildHash(pmns, mtab_size); /* for reverse (pmid->name) lookups */ + need_refresh = 0; +} + +int +pmns_desc(pmID pmid, pmDesc *desc, pmdaExt *ep) +{ + if (need_refresh) + pmns_refresh(); + return pmdaDesc(pmid, desc, ep); +} + +int +pmns_pmid(const char *name, pmID *pmid, pmdaExt *pmda) +{ + if (need_refresh) + pmns_refresh(); + return pmdaTreePMID(pmns, name, pmid); +} + +int +pmns_name(pmID pmid, char ***nameset, pmdaExt *pmda) +{ + if (need_refresh) + pmns_refresh(); + return pmdaTreeName(pmns, pmid, nameset); +} + +int +pmns_children(const char *name, int traverse, char ***kids, int **sts, pmdaExt *pmda) +{ + if (need_refresh) + pmns_refresh(); + return pmdaTreeChildren(pmns, name, traverse, kids, sts); +} + +void +pmns_write(void) +{ + __pmnsNode *node; + char *pppenv = getenv("PCP_PERL_PMNS"); + int root = pppenv ? strcmp(pppenv, "root") == 0 : 0; + char *prefix = root ? "\t" : ""; + + pmns_refresh(); + + if (root) + printf("root {\n"); + for (node = pmns->root->first; node != NULL; node = node->next) + printf("%s%s\t%u:*:*\n", prefix, node->name, dispatch.domain); + if (root) + printf("}\n"); +} + +void +domain_write(void) +{ + char *p, name[512] = { 0 }; + int i, len = strlen(pmProgname); + + if (len >= sizeof(name) - 1) + len = sizeof(name) - 2; + p = pmProgname; + if (strncmp(pmProgname, "pmda", 4) == 0) + p += 4; + for (i = 0; i < len; i++) + name[i] = toupper(p[i]); + printf("#define %s %u\n", name, dispatch.domain); +} + +void +prefetch(void) +{ + dSP; + ENTER; + SAVETMPS; + PUSHMARK(sp); + PUTBACK; + + perl_call_sv(fetch_func, G_VOID|G_NOARGS); + + SPAGAIN; + PUTBACK; + FREETMPS; + LEAVE; +} + +int +fetch(int numpmid, pmID *pmidlist, pmResult **rp, pmdaExt *pmda) +{ + if (need_refresh) + pmns_refresh(); + if (fetch_func) + prefetch(); + if (refresh_func) + refresh(numpmid, pmidlist); + return pmdaFetch(numpmid, pmidlist, rp, pmda); +} + +int +instance_index(pmInDom indom) +{ + int i; + + for (i = 0; i < itab_size; i++) + if (indomtab[i].it_indom == indom) + return i; + return PM_INDOM_NULL; +} + +void +preinstance(pmInDom indom) +{ + dSP; + ENTER; + SAVETMPS; + PUSHMARK(sp); + XPUSHs(sv_2mortal(newSVuv(indom))); + PUTBACK; + + perl_call_sv(instance_func, G_VOID); + + SPAGAIN; + PUTBACK; + FREETMPS; + LEAVE; +} + +int +instance(pmInDom indom, int a, char *b, __pmInResult **rp, pmdaExt *pmda) +{ + if (need_refresh) + pmns_refresh(); + if (instance_func) + preinstance(instance_index(indom)); + return pmdaInstance(indom, a, b, rp, pmda); +} + +void +timer_callback(int afid, void *data) +{ + dSP; + ENTER; + SAVETMPS; + PUSHMARK(sp); + XPUSHs(sv_2mortal(newSViv(local_timer_get_cookie(afid)))); + PUTBACK; + + perl_call_sv(local_timer_get_callback(afid), G_VOID); + + SPAGAIN; + PUTBACK; + FREETMPS; + LEAVE; +} + +void +input_callback(SV *input_cb_func, int data, char *string) +{ + dSP; + ENTER; + SAVETMPS; + PUSHMARK(sp); + XPUSHs(sv_2mortal(newSViv(data))); + XPUSHs(sv_2mortal(newSVpv(string,0))); + PUTBACK; + + perl_call_sv(input_cb_func, G_VOID); + + SPAGAIN; + PUTBACK; + FREETMPS; + LEAVE; +} + +int +fetch_callback(pmdaMetric *metric, unsigned int inst, pmAtomValue *atom) +{ + dSP; + __pmID_int *pmid; + int sts; + STRLEN n_a; /* required by older Perl versions, used in POPpx */ + + ENTER; + SAVETMPS; /* allows us to tidy our perl stack changes later */ + + (void)n_a; + pmid = (__pmID_int *) &metric->m_desc.pmid; + + PUSHMARK(sp); + XPUSHs(sv_2mortal(newSVuv(pmid->cluster))); + XPUSHs(sv_2mortal(newSVuv(pmid->item))); + XPUSHs(sv_2mortal(newSVuv(inst))); + PUTBACK; + + sts = perl_call_sv(fetch_cb_func, G_ARRAY); + SPAGAIN; /* refresh local perl stack pointer after call */ + if (sts != 2) { + croak("fetch CB error (returned %d values, expected 2)", sts); + sts = -EINVAL; + goto fetch_end; + } + sts = POPi; /* pop function return status */ + if (sts < 0) { + goto fetch_end; + } + else if (sts == 0) { + sts = POPi; + goto fetch_end; + } + + sts = PMDA_FETCH_STATIC; + switch (metric->m_desc.type) { /* pop result value */ + case PM_TYPE_32: atom->l = POPi; break; + case PM_TYPE_U32: atom->ul = POPi; break; + case PM_TYPE_64: atom->ll = POPl; break; + case PM_TYPE_U64: atom->ull = POPl; break; + case PM_TYPE_FLOAT: atom->f = POPn; break; + case PM_TYPE_DOUBLE: atom->d = POPn; break; + case PM_TYPE_STRING: { + atom->cp = strdup(POPpx); + sts = PMDA_FETCH_DYNAMIC; + break; + } + } + +fetch_end: + PUTBACK; + FREETMPS; + LEAVE; /* fix up the perl stack, freeing anything we created */ + return sts; +} + +int +store_callback(__pmID_int *pmid, unsigned int inst, pmAtomValue av, int type) +{ + dSP; + int sts; + ENTER; + SAVETMPS; + PUSHMARK(sp); + XPUSHs(sv_2mortal(newSVuv(pmid->cluster))); + XPUSHs(sv_2mortal(newSVuv(pmid->item))); + XPUSHs(sv_2mortal(newSVuv(inst))); + switch (type) { + case PM_TYPE_32: XPUSHs(sv_2mortal(newSViv(av.l))); break; + case PM_TYPE_U32: XPUSHs(sv_2mortal(newSVuv(av.ul))); break; + case PM_TYPE_64: XPUSHs(sv_2mortal(newSVuv(av.ll))); break; + case PM_TYPE_U64: XPUSHs(sv_2mortal(newSVuv(av.ull))); break; + case PM_TYPE_FLOAT: XPUSHs(sv_2mortal(newSVnv(av.f))); break; + case PM_TYPE_DOUBLE: XPUSHs(sv_2mortal(newSVnv(av.d))); break; + case PM_TYPE_STRING: XPUSHs(sv_2mortal(newSVpv(av.cp,0)));break; + } + PUTBACK; + + sts = perl_call_sv(store_cb_func, G_SCALAR); + SPAGAIN; /* refresh local perl stack pointer after call */ + if (sts != 1) { + croak("store CB error (returned %d values, expected 1)", sts); + sts = -EINVAL; + goto store_end; + } + sts = POPi; /* pop function return status */ + +store_end: + PUTBACK; + FREETMPS; + LEAVE; /* fix up the perl stack, freeing anything we created */ + return sts; +} + +int +store(pmResult *result, pmdaExt *pmda) +{ + int i, j; + int type; + int sts; + pmAtomValue av; + pmValueSet *vsp; + __pmID_int *pmid; + + if (need_refresh) + pmns_refresh(); + + for (i = 0; i < result->numpmid; i++) { + vsp = result->vset[i]; + pmid = (__pmID_int *)&vsp->pmid; + + /* need to find the type associated with this PMID */ + for (j = 0; j < mtab_size; j++) + if (metrictab[j].m_desc.pmid == *(pmID *)pmid) + break; + if (j == mtab_size) + return PM_ERR_PMID; + type = metrictab[j].m_desc.type; + + for (j = 0; j < vsp->numval; j++) { + sts = pmExtractValue(vsp->valfmt, &vsp->vlist[j],type, &av, type); + if (sts < 0) + return sts; + sts = store_callback(pmid, vsp->vlist[j].inst, av, type); + if (sts < 0) + return sts; + } + } + return 0; +} + +int +text(int ident, int type, char **buffer, pmdaExt *pmda) +{ + const char *hash; + int size; + SV **sv; + + if (need_refresh) + pmns_refresh(); + + if ((type & PM_TEXT_PMID) == PM_TEXT_PMID) { + hash = pmIDStr((pmID)ident); + size = strlen(hash); + if (type & PM_TEXT_ONELINE) + sv = hv_fetch(metric_oneline, hash, size, 0); + else + sv = hv_fetch(metric_helptext, hash, size, 0); + } + else { + hash = pmInDomStr((pmInDom)ident); + size = strlen(hash); + if (type & PM_TEXT_ONELINE) + sv = hv_fetch(indom_oneline, hash, size, 0); + else + sv = hv_fetch(indom_helptext, hash, size, 0); + } + + if (sv && (*sv)) + *buffer = SvPV_nolen(*sv); + return (*buffer == NULL) ? PM_ERR_TEXT : 0; +} + +/* + * Converts Perl hash ref like {'foo' => \&data, 'boo' => \&data} + * into an instance structure (indom). + */ +static int +update_hash_indom(SV *insts, pmInDom indom) +{ + int sts; + SV *data; + I32 instsize; + char *instance; + HV *ihash = (HV *) SvRV(insts); + + sts = pmdaCacheOp(indom, PMDA_CACHE_INACTIVE); + if (sts < 0) + warn("pmda cache inactivation failed: %s", pmErrStr(sts)); + + hv_iterinit(ihash); + while ((data = hv_iternextsv(ihash, &instance, &instsize)) != NULL) + pmdaCacheStore(indom, PMDA_CACHE_ADD, instance, SvREFCNT_inc(data)); + + sts = pmdaCacheOp(indom, PMDA_CACHE_SAVE); + if (sts < 0) + warn("pmda cache persistance failed: %s", pmErrStr(sts)); + + return 0; +} + +/* + * Free all memory associated with a Perl list based indom + */ +static void +release_list_indom(pmdaInstid *instances, int numinst) +{ + int i; + + if (instances && numinst > 0) { + for (i = 0; i < numinst; i++) + free(instances[i].i_name); /* update_list_indom strdup */ + free(instances); /* update_list_indom calloc */ + } +} + +/* + * Converts Perl list ref like [a => 'foo', b => 'boo'] into an indom. + */ +static int +update_list_indom(SV *insts, pmdaInstid **set) +{ + int i, len; + SV **id; + SV **name; + AV *ilist = (AV *) SvRV(insts); + pmdaInstid *instances; + + if ((len = av_len(ilist)) == -1) { /* empty */ + *set = NULL; + return 0; + } + if (len++ % 2 == 0) { + warn("invalid instance list (length must be a multiple of 2)"); + return -1; + } + + len /= 2; + instances = (pmdaInstid *) calloc(len, sizeof(pmdaInstid)); + if (instances == NULL) { + warn("insufficient memory for instance array"); + return -1; + } + for (i = 0; i < len; i++) { + id = av_fetch(ilist,i*2,0); + name = av_fetch(ilist,i*2+1,0); + instances[i].i_inst = SvIV(*id); + instances[i].i_name = strdup(SvPV_nolen(*name)); + if (instances[i].i_name == NULL) { + release_list_indom(instances, i); + warn("insufficient memory for instance array names"); + return -1; + } + } + *set = instances; + return len; +} + +/* + * Converts a Perl instance reference into a populated indom. + * This interface handles either the hash or list formats. + */ +static int +update_indom(SV *insts, pmInDom indom, pmdaInstid **set) +{ + SV *rv = (SV *) SvRV(insts); + pmdaInstid *instances; + + if (! SvROK(insts)) { + warn("expected a reference for instances argument"); + return -1; + } + if (SvTYPE(rv) == SVt_PVAV) + return update_list_indom(insts, set); + if (SvTYPE(rv) == SVt_PVHV) + return update_hash_indom(insts, indom); + warn("instance argument is neither an array nor hash reference"); + return -1; +} + + +MODULE = PCP::PMDA PACKAGE = PCP::PMDA + + +pmdaInterface * +new(CLASS,name,domain) + char * CLASS + char * name + int domain + PREINIT: + int sep; + char * p; + char * logfile; + char * pmdaname; + char helpfile[256]; + CODE: + pmProgname = name; + RETVAL = &dispatch; + logfile = local_strdup_suffix(name, ".log"); + pmdaname = local_strdup_prefix("pmda", name); + __pmSetProgname(pmdaname); + sep = __pmPathSeparator(); + if ((p = getenv("PCP_PERL_DEBUG")) != NULL) + if ((pmDebug = __pmParseDebug(p)) < 0) + pmDebug = 0; +#ifndef IS_MINGW + setsid(); +#endif + atexit(&local_atexit); + snprintf(helpfile, sizeof(helpfile), "%s%c%s%c" "help", + pmGetConfig("PCP_PMDAS_DIR"), sep, name, sep); + if (access(helpfile, R_OK) != 0) { + pmdaDaemon(&dispatch, PMDA_INTERFACE_5, pmdaname, domain, + logfile, NULL); + dispatch.version.four.text = text; + } + else { + pmdaDaemon(&dispatch, PMDA_INTERFACE_5, pmdaname, domain, + logfile, strdup(helpfile)); + } + dispatch.version.four.fetch = fetch; + dispatch.version.four.instance = instance; + dispatch.version.four.desc = pmns_desc; + dispatch.version.four.pmid = pmns_pmid; + dispatch.version.four.name = pmns_name; + dispatch.version.four.children = pmns_children; + + if (!getenv("PCP_PERL_PMNS") && !getenv("PCP_PERL_DOMAIN")) { + pmdaOpenLog(&dispatch); + } + metric_names = newHV(); + metric_oneline = newHV(); + metric_helptext = newHV(); + indom_helptext = newHV(); + indom_oneline = newHV(); + OUTPUT: + RETVAL + +int +pmda_pmid(cluster,item) + unsigned int cluster + unsigned int item + CODE: + RETVAL = pmid_build(dispatch.domain, cluster, item); + OUTPUT: + RETVAL + +SV * +pmda_pmid_name(cluster,item) + unsigned int cluster + unsigned int item + PREINIT: + const char *name; + SV **rval; + CODE: + name = pmIDStr(pmid_build(dispatch.domain, cluster, item)); + rval = hv_fetch(metric_names, name, strlen(name), 0); + if (!rval || !(*rval)) + XSRETURN_UNDEF; + RETVAL = newSVsv(*rval); + OUTPUT: + RETVAL + +SV * +pmda_pmid_text(cluster,item) + unsigned int cluster + unsigned int item + PREINIT: + const char *name; + SV **rval; + CODE: + name = pmIDStr(pmid_build(dispatch.domain, cluster, item)); + rval = hv_fetch(metric_oneline, name, strlen(name), 0); + if (!rval || !(*rval)) + XSRETURN_UNDEF; + RETVAL = newSVsv(*rval); + OUTPUT: + RETVAL + +SV * +pmda_inst_name(index,instance) + unsigned int index + int instance + PREINIT: + int i; + pmdaIndom * p; + pmdaInstid *instp; + CODE: + if (index >= itab_size) /* is this a valid indom */ + XSRETURN_UNDEF; + p = indomtab + index; + if (!p->it_set) /* was this indom previously setup via a hash? */ + XSRETURN_UNDEF; + + /* Optimistic (fast) direct lookup first, then iterate */ + i = instance; + if (i > p->it_numinst || i < 0 || instance != p->it_set[i].i_inst) { + for (i = 0; i < p->it_numinst; i++) + if (instance == p->it_set[i].i_inst) + break; + if (i == p->it_numinst) + XSRETURN_UNDEF; + } + RETVAL = newSVpv(p->it_set[i].i_name,0); + OUTPUT: + RETVAL + +SV * +pmda_inst_lookup(index,instance) + unsigned int index + int instance + PREINIT: + pmdaIndom * p; + SV * svp; + int i, sts; + CODE: + if (index >= itab_size) /* is this a valid indom */ + XSRETURN_UNDEF; + p = indomtab + index; + if (p->it_set) /* was this indom previously setup via an array? */ + XSRETURN_UNDEF; + sts = pmdaCacheLookup(p->it_indom, instance, NULL, (void *)&svp); + if (sts != PMDA_CACHE_ACTIVE) + XSRETURN_UNDEF; + RETVAL = SvREFCNT_inc(svp); + OUTPUT: + RETVAL + +int +pmda_units(dim_space,dim_time,dim_count,scale_space,scale_time,scale_count) + unsigned int dim_space + unsigned int dim_time + unsigned int dim_count + unsigned int scale_space + unsigned int scale_time + unsigned int scale_count + PREINIT: + pmUnits units; + CODE: + units.pad = 0; + units.dimSpace = dim_space; units.scaleSpace = scale_space; + units.dimTime = dim_time; units.scaleTime = scale_time; + units.dimCount = dim_count; units.scaleCount = scale_count; + RETVAL = *(int *)(&units); + OUTPUT: + RETVAL + +char * +pmda_config(name) + char * name + CODE: + RETVAL = pmGetConfig(name); + if (!RETVAL) + XSRETURN_UNDEF; + OUTPUT: + RETVAL + +char * +pmda_uptime(now) + int now + PREINIT: + static char s[32]; + size_t sz = sizeof(s); + int days, hours, mins, secs; + CODE: + days = now / (60 * 60 * 24); + now %= (60 * 60 * 24); + hours = now / (60 * 60); + now %= (60 * 60); + mins = now / 60; + now %= 60; + secs = now; + + if (days > 1) + snprintf(s, sz, "%ddays %02d:%02d:%02d", days, hours, mins, secs); + else if (days == 1) + snprintf(s, sz, "%dday %02d:%02d:%02d", days, hours, mins, secs); + else + snprintf(s, sz, "%02d:%02d:%02d", hours, mins, secs); + RETVAL = s; + OUTPUT: + RETVAL + +int +pmda_long() + CODE: + RETVAL = (sizeof(long) == 4) ? PM_TYPE_32 : PM_TYPE_64; + OUTPUT: + RETVAL + +int +pmda_ulong() + CODE: + RETVAL = (sizeof(unsigned long) == 4) ? PM_TYPE_32 : PM_TYPE_64; + OUTPUT: + RETVAL + + +void +error(self,message) + pmdaInterface *self + char * message + CODE: + __pmNotifyErr(LOG_ERR, "%s", message); + +int +set_user(self,username) + pmdaInterface *self + char * username + CODE: + RETVAL = __pmSetProcessIdentity(username); + OUTPUT: + RETVAL + +void +set_fetch(self,function) + pmdaInterface *self + SV * function + CODE: + if (function != (SV *)NULL) { + fetch_func = newSVsv(function); + } + +void +set_refresh(self,function) + pmdaInterface *self + SV * function + CODE: + if (function != (SV *)NULL) { + refresh_func = newSVsv(function); + } + +void +set_instance(self,function) + pmdaInterface *self + SV * function + CODE: + if (function != (SV *)NULL) { + instance_func = newSVsv(function); + } + +void +set_store_callback(self,cb_function) + pmdaInterface *self + SV * cb_function + CODE: + if (cb_function != (SV *)NULL) { + store_cb_func = newSVsv(cb_function); + self->version.four.store = store; + } + +void +set_fetch_callback(self,cb_function) + pmdaInterface *self + SV * cb_function + CODE: + if (cb_function != (SV *)NULL) { + fetch_cb_func = newSVsv(cb_function); + pmdaSetFetchCallBack(self, fetch_callback); + } + +void +set_inet_socket(self,port) + pmdaInterface *self + int port + CODE: + self->version.four.ext->e_io = pmdaInet; + self->version.four.ext->e_port = port; + +void +set_ipv6_socket(self,port) + pmdaInterface *self + int port + CODE: + self->version.four.ext->e_io = pmdaIPv6; + self->version.four.ext->e_port = port; + +void +set_unix_socket(self,socket_name) + pmdaInterface *self + char * socket_name + CODE: + self->version.four.ext->e_io = pmdaUnix; + self->version.four.ext->e_sockname = socket_name; + +void +clear_metrics(self) + pmdaInterface *self + CODE: + need_refresh = 1; + if (clustertab) + free(clustertab); + ctab_size = 0; + if (metrictab) + free(metrictab); + mtab_size = 0; + clearHV(metric_names); + clearHV(metric_oneline); + clearHV(metric_helptext); + +void +add_metric(self,pmid,type,indom,sem,units,name,help,longhelp) + pmdaInterface *self + int pmid + int type + int indom + int sem + int units + char * name + char * help + char * longhelp + PREINIT: + pmdaMetric * p; + __pmID_int * pmidp; + const char * hash; + int size; + CODE: + (void)self; + need_refresh = 1; + pmidp = (__pmID_int *)&pmid; + if (!clustertab_lookup(pmidp->cluster)) { + size = sizeof(int) * (ctab_size + 1); + clustertab = (int *)realloc(clustertab, size); + if (clustertab) + clustertab[ctab_size++] = pmidp->cluster; + else { + warn("unable to allocate memory for cluster table"); + ctab_size = 0; + XSRETURN_UNDEF; + } + } + + size = sizeof(pmdaMetric) * (mtab_size + 1); + metrictab = (pmdaMetric *)realloc(metrictab, size); + if (metrictab == NULL) { + warn("unable to allocate memory for metric table"); + mtab_size = 0; + XSRETURN_UNDEF; + } + + p = metrictab + mtab_size++; + p->m_user = NULL; p->m_desc.pmid = *(pmID *)&pmid; + p->m_desc.type = type; p->m_desc.indom = *(pmInDom *)&indom; + p->m_desc.sem = sem; p->m_desc.units = *(pmUnits *)&units; + + hash = pmIDStr(pmid); + size = strlen(hash); + hv_store(metric_names, hash, size, newSVpv(name,0), 0); + if (help) + hv_store(metric_oneline, hash, size, newSVpv(help,0), 0); + if (longhelp) + hv_store(metric_helptext, hash, size, newSVpv(longhelp,0), 0); + +void +clear_indoms(self) + pmdaInterface *self + CODE: + if (indomtab) + free(indomtab); + itab_size = 0; + if (metrictab) + free(metrictab); + mtab_size = 0; + clearHV(indom_oneline); + clearHV(indom_helptext); + +int +add_indom(self,indom,insts,help,longhelp) + pmdaInterface * self + int indom + SV * insts + char * help + char * longhelp + PREINIT: + pmdaIndom * p; + const char * hash; + int sts, size; + CODE: + size = sizeof(pmdaIndom) * (itab_size + 1); + indomtab = (pmdaIndom *)realloc(indomtab, size); + if (indomtab == NULL) { + warn("unable to allocate memory for indom table"); + itab_size = 0; + XSRETURN_UNDEF; + } + + p = indomtab + itab_size; + memset(p, 0, sizeof(pmdaIndom)); + p->it_indom = pmInDom_build(self->domain, indom); + + sts = update_indom(insts, p->it_indom, &p->it_set); + if (sts < 0) + XSRETURN_UNDEF; + if (p->it_set) + p->it_numinst = sts; + RETVAL = itab_size++; /* used in calls to replace_indom() */ + + hash = pmInDomStr(indom); + size = strlen(hash); + if (help) + hv_store(indom_oneline, hash, size, newSVpv(help,0), 0); + if (longhelp) + hv_store(indom_helptext, hash, size, newSVpv(longhelp,0), 0); + OUTPUT: + RETVAL + +int +replace_indom(self,index,insts) + pmdaInterface * self + unsigned int index + SV * insts + PREINIT: + pmdaIndom * p; + int sts; + CODE: + if (index >= itab_size) { + warn("attempt to replace non-existent instance domain"); + XSRETURN_UNDEF; + } + else { + p = indomtab + index; + /* was this indom previously setup via an array? */ + if (p->it_set) + release_list_indom(p->it_set, p->it_numinst); + sts = update_indom(insts, p->it_indom, &p->it_set); + if (sts < 0) + XSRETURN_UNDEF; + if (p->it_set) + p->it_numinst = sts; + RETVAL = sts; + } + OUTPUT: + RETVAL + +int +add_timer(self,timeout,callback,data) + pmdaInterface * self + double timeout + SV * callback + int data + CODE: + if (getenv("PCP_PERL_PMNS") || getenv("PCP_PERL_DOMAIN") || !callback) + XSRETURN_UNDEF; + RETVAL = local_timer(timeout, newSVsv(callback), data); + OUTPUT: + RETVAL + +int +add_pipe(self,command,callback,data) + pmdaInterface *self + char * command + SV * callback + int data + CODE: + if (getenv("PCP_PERL_PMNS") || getenv("PCP_PERL_DOMAIN") || !callback) + XSRETURN_UNDEF; + RETVAL = local_pipe(command, newSVsv(callback), data); + OUTPUT: + RETVAL + +int +add_tail(self,filename,callback,data) + pmdaInterface *self + char * filename + SV * callback + int data + CODE: + if (getenv("PCP_PERL_PMNS") || getenv("PCP_PERL_DOMAIN") || !callback) + XSRETURN_UNDEF; + RETVAL = local_tail(filename, newSVsv(callback), data); + OUTPUT: + RETVAL + +int +add_sock(self,hostname,port,callback,data) + pmdaInterface *self + char * hostname + int port + SV * callback + int data + CODE: + if (getenv("PCP_PERL_PMNS") || getenv("PCP_PERL_DOMAIN") || !callback) + XSRETURN_UNDEF; + RETVAL = local_sock(hostname, port, newSVsv(callback), data); + OUTPUT: + RETVAL + +int +put_sock(self,id,output) + pmdaInterface *self + int id + char * output + CODE: + size_t length = strlen(output); + RETVAL = __pmWrite(local_files_get_descriptor(id), output, length); + OUTPUT: + RETVAL + +void +log(self,message) + pmdaInterface *self + char * message + CODE: + __pmNotifyErr(LOG_INFO, "%s", message); + +void +err(self,message) + pmdaInterface *self + char * message + CODE: + __pmNotifyErr(LOG_ERR, "%s", message); + +void +connect_pmcd(self) + pmdaInterface *self + CODE: + /* + * Need to mimic the same special cases handled in run() + * that explicitly do NOT connect to pmcd and treat these + * as no-ops here + * + * Otherwise call pmdaConnet() to complete the PMDA's IPC + * channel setup and complete the connection handshake with + * pmcd. + */ + if (getenv("PCP_PERL_PMNS") != NULL) + ; + else if (getenv("PCP_PERL_DOMAIN") != NULL) + ; + else { + /* + * On success pmdaConnect sets PMDA_EXT_CONNECTED in e_flags ... + * this used in the guard below to stop run() calling + * pmdaConnect() again. + */ + pmdaConnect(self); + } + +void +run(self) + pmdaInterface *self + CODE: + if (getenv("PCP_PERL_PMNS") != NULL) + pmns_write(); /* generate ascii namespace */ + else if (getenv("PCP_PERL_DOMAIN") != NULL) + domain_write(); /* generate the domain header */ + else { /* or normal operating mode ... */ + pmns_refresh(); + pmdaInit(self, indomtab, itab_size, metrictab, mtab_size); + if ((self->version.any.ext->e_flags & PMDA_EXT_CONNECTED) != PMDA_EXT_CONNECTED) { + /* + * connect_pmcd() not called before, so need pmdaConnect() + * here before falling into the PDU-driven mainloop + */ + pmdaConnect(self); + } + local_pmdaMain(self); + } + +void +debug_metric(self) + pmdaInterface *self + PREINIT: + int i; + CODE: + /* NB: debugging only (used in test.pl to verify state) */ + fprintf(stderr, "metric table size = %d\n", mtab_size); + for (i = 0; i < mtab_size; i++) { + fprintf(stderr, "metric idx = %d\n\tpmid = %s\n\ttype = %u\n" + "\tindom= %d\n\tsem = %u\n\tunits= %u\n", + i, pmIDStr(metrictab[i].m_desc.pmid), metrictab[i].m_desc.type, + (int)metrictab[i].m_desc.indom, metrictab[i].m_desc.sem, + *(unsigned int *)&metrictab[i].m_desc.units); + } + (void)self; + +void +debug_indom(self) + pmdaInterface *self + PREINIT: + int i,j; + CODE: + /* NB: debugging only (used in test.pl to verify state) */ + fprintf(stderr, "indom table size = %d\n", itab_size); + for (i = 0; i < itab_size; i++) { + fprintf(stderr, "indom idx = %d\n\tindom = %d\n" + "\tninst = %u\n\tiptr = 0x%p\n", + i, *(int *)&indomtab[i].it_indom, indomtab[i].it_numinst, + indomtab[i].it_set); + for (j = 0; j < indomtab[i].it_numinst; j++) { + fprintf(stderr, "\t\tid=%d name=%s\n", + indomtab[i].it_set[j].i_inst, indomtab[i].it_set[j].i_name); + } + } + (void)self; + +void +debug_init(self) + pmdaInterface *self + CODE: + /* NB: debugging only (used in test.pl to verify state) */ + pmdaInit(self, indomtab, itab_size, metrictab, mtab_size); + |