diff options
Diffstat (limited to 'src/libpcp_pmda/src/events.c')
-rw-r--r-- | src/libpcp_pmda/src/events.c | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/src/libpcp_pmda/src/events.c b/src/libpcp_pmda/src/events.c new file mode 100644 index 0000000..09abb8d --- /dev/null +++ b/src/libpcp_pmda/src/events.c @@ -0,0 +1,391 @@ +/* + * Service routines for managing a packed array of event records + * + * Copyright (c) 2010 Ken McDonell. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public + * License for more details. + */ + +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" + +typedef struct { + char *baddr; /* base address of the buffer */ + char *bptr; /* next location to be filled in the buffer */ + void *berp; /* current pmEvent[HighRes]Record in buffer */ + int blen; /* buffer size */ + int bstate; +} bufctl_t; + +#define B_FREE 0 +#define B_INUSE 1 + +static int nbuf; +static bufctl_t *bufs; + +static int +check_buf(bufctl_t *bp, int need) +{ + int offset = bp->bptr - bp->baddr; + int er_offset = (char *)bp->berp - bp->baddr; + + while (bp->blen == 0 || &bp->bptr[need] >= &bp->baddr[bp->blen-1]) { + if (bp->blen == 0) + /* first time, punt on a 512 byte buffer */ + bp->blen = 512; + else + bp->blen *= 2; + if ((bp->baddr = (char *)realloc(bp->baddr, bp->blen)) == NULL) + return -oserror(); + bp->bptr = &bp->baddr[offset]; + bp->berp = (void *)&bp->baddr[er_offset]; + } + return 0; +} + +static int +event_array(void) +{ + int i; + + for (i = 0; i < nbuf; i++) { + if (bufs[i].bstate == B_FREE) + break; + } + + if (i == nbuf) { + nbuf++; + bufs = (bufctl_t *)realloc(bufs, nbuf*sizeof(bufs[0])); + if (bufs == NULL) { + nbuf = 0; + return -oserror(); + } + } + + bufs[i].bptr = bufs[i].baddr = NULL; + bufs[i].blen = 0; + bufs[i].bstate = B_INUSE; + return i; +} + +int +pmdaEventNewArray(void) +{ + int sts = event_array(); + + if (sts >= 0) + pmdaEventResetArray(sts); + return sts; +} + +int +pmdaEventNewHighResArray(void) +{ + int sts = event_array(); + + if (sts >= 0) + pmdaEventResetHighResArray(sts); + return sts; +} + +/* prepare to reuse an array */ +int +pmdaEventResetArray(int idx) +{ + bufctl_t *bp; + pmEventArray *eap; + int sts; + + if (idx < 0 || idx >= nbuf || bufs[idx].bstate == B_FREE) + return PM_ERR_NOCONTEXT; + bp = &bufs[idx]; + if ((sts = check_buf(bp, sizeof(pmEventArray) - sizeof(pmEventRecord))) < 0) + return sts; + + eap = (pmEventArray *)bp->baddr; + eap->ea_nrecords = 0; + bp->bptr = bp->baddr + sizeof(pmEventArray) - sizeof(pmEventRecord); + return 0; +} + +int +pmdaEventResetHighResArray(int idx) +{ + bufctl_t *bp; + pmHighResEventArray *hreap; + int sts; + + if (idx < 0 || idx >= nbuf || bufs[idx].bstate == B_FREE) + return PM_ERR_NOCONTEXT; + bp = &bufs[idx]; + if ((sts = check_buf(bp, sizeof(*hreap) - sizeof(pmHighResEventRecord))) < 0) + return sts; + + hreap = (pmHighResEventArray *)bp->baddr; + hreap->ea_nrecords = 0; + bp->bptr = bp->baddr + sizeof(*hreap) - sizeof(pmHighResEventRecord); + return 0; +} + +/* release buffer space associated with a packed event array */ +int +pmdaEventReleaseArray(int idx) +{ + if (idx < 0 || idx >= nbuf || bufs[idx].bstate == B_FREE) + return PM_ERR_NOCONTEXT; + + free(bufs[idx].baddr); + bufs[idx].bstate = B_FREE; + return 0; +} + +int +pmdaEventReleaseHighResArray(int idx) +{ + return pmdaEventReleaseArray(idx); +} + +int +pmdaEventAddRecord(int idx, struct timeval *tp, int flags) +{ + int sts; + bufctl_t *bp; + pmEventArray *eap; + pmEventRecord *erp; + + if (idx < 0 || idx >= nbuf || bufs[idx].bstate == B_FREE) + return PM_ERR_NOCONTEXT; + bp = &bufs[idx]; + + /* use pmdaEventAddMissedRecord for missed records ... */ + if (flags & PM_EVENT_FLAG_MISSED) + return PM_ERR_CONV; + + if ((sts = check_buf(bp, sizeof(*erp) - sizeof(pmEventParameter))) < 0) + return sts; + eap = (pmEventArray *)bp->baddr; + eap->ea_nrecords++; + erp = (pmEventRecord *)bp->bptr; + erp->er_timestamp.tv_sec = (__int32_t)tp->tv_sec; + erp->er_timestamp.tv_usec = (__int32_t)tp->tv_usec; + erp->er_nparams = 0; + erp->er_flags = flags; + bp->berp = (void *)erp; + bp->bptr += sizeof(pmEventRecord) - sizeof(pmEventParameter); + return 0; +} + +int +pmdaEventAddHighResRecord(int idx, struct timespec *ts, int flags) +{ + int sts; + bufctl_t *bp; + pmHighResEventArray *hreap; + pmHighResEventRecord *hrerp; + + if (idx < 0 || idx >= nbuf || bufs[idx].bstate == B_FREE) + return PM_ERR_NOCONTEXT; + bp = &bufs[idx]; + + /* use pmdaEventAddMissedRecord for missed records ... */ + if (flags & PM_EVENT_FLAG_MISSED) + return PM_ERR_CONV; + + if ((sts = check_buf(bp, sizeof(*hrerp) - sizeof(pmEventParameter))) < 0) + return sts; + hreap = (pmHighResEventArray *)bp->baddr; + hreap->ea_nrecords++; + hrerp = (pmHighResEventRecord *)bp->bptr; + hrerp->er_timestamp.tv_sec = (__int64_t)ts->tv_sec; + hrerp->er_timestamp.tv_nsec = (__int64_t)ts->tv_nsec; + hrerp->er_nparams = 0; + hrerp->er_flags = flags; + bp->berp = (void *)hrerp; + bp->bptr += sizeof(pmHighResEventRecord) - sizeof(pmEventParameter); + return 0; +} + +int +pmdaEventAddMissedRecord(int idx, struct timeval *tp, int missed) +{ + int sts; + bufctl_t *bp; + pmEventArray *eap; + pmEventRecord *erp; + + if (idx < 0 || idx >= nbuf || bufs[idx].bstate == B_FREE) + return PM_ERR_NOCONTEXT; + bp = &bufs[idx]; + + if ((sts = check_buf(bp, sizeof(*erp) - sizeof(pmEventParameter))) < 0) + return sts; + eap = (pmEventArray *)bp->baddr; + eap->ea_nrecords++; + erp = (pmEventRecord *)bp->bptr; + erp->er_timestamp.tv_sec = (__int32_t)tp->tv_sec; + erp->er_timestamp.tv_usec = (__int32_t)tp->tv_usec; + erp->er_nparams = missed; + erp->er_flags = PM_EVENT_FLAG_MISSED; + bp->berp = (void *)erp; + bp->bptr += sizeof(pmEventRecord) - sizeof(pmEventParameter); + return 0; +} + +int +pmdaEventAddHighResMissedRecord(int idx, struct timespec *ts, int missed) +{ + int sts; + bufctl_t *bp; + pmHighResEventArray *hreap; + pmHighResEventRecord *hrerp; + + if (idx < 0 || idx >= nbuf || bufs[idx].bstate == B_FREE) + return PM_ERR_NOCONTEXT; + bp = &bufs[idx]; + + if ((sts = check_buf(bp, sizeof(*hrerp) - sizeof(pmEventParameter))) < 0) + return sts; + hreap = (pmHighResEventArray *)bp->baddr; + hreap->ea_nrecords++; + hrerp = (pmHighResEventRecord *)bp->bptr; + hrerp->er_timestamp.tv_sec = (__int32_t)ts->tv_sec; + hrerp->er_timestamp.tv_nsec = (__int32_t)ts->tv_nsec; + hrerp->er_nparams = missed; + hrerp->er_flags = PM_EVENT_FLAG_MISSED; + bp->berp = (void *)hrerp; + bp->bptr += sizeof(pmHighResEventRecord) - sizeof(pmEventParameter); + return 0; +} + +int +add_param(int idx, pmID pmid, int type, pmAtomValue *avp, bufctl_t **bpp) +{ + int sts; + int need; /* bytes in the buffer */ + int vlen; /* value only length */ + void *src; + pmEventParameter *epp; + bufctl_t *bp; + + if (idx < 0 || idx >= nbuf || bufs[idx].bstate == B_FREE) + return PM_ERR_NOCONTEXT; + bp = &bufs[idx]; + + need = sizeof(pmEventParameter); + switch (type) { + case PM_TYPE_32: + case PM_TYPE_U32: + vlen = sizeof(avp->l); + need += vlen; + src = &avp->l; + break; + case PM_TYPE_64: + case PM_TYPE_U64: + vlen = sizeof(avp->ll); + need += vlen; + src = &avp->ll; + break; + case PM_TYPE_FLOAT: + vlen = sizeof(avp->f); + need += vlen; + src = &avp->f; + break; + case PM_TYPE_DOUBLE: + vlen = sizeof(avp->d); + need += vlen; + src = &avp->d; + break; + case PM_TYPE_STRING: + vlen = strlen(avp->cp); + need += PM_PDU_SIZE_BYTES(vlen); + src = avp->cp; + break; + case PM_TYPE_AGGREGATE: + /* PM_VAL_HDR_SIZE is added back in below */ + vlen = avp->vbp->vlen - PM_VAL_HDR_SIZE; + need += PM_PDU_SIZE_BYTES(vlen); + src = avp->vbp->vbuf; + break; + default: + return PM_ERR_TYPE; + } + if ((sts = check_buf(bp, need)) < 0) + return sts; + epp = (pmEventParameter *)bp->bptr; + epp->ep_pmid = pmid; + epp->ep_len = PM_VAL_HDR_SIZE + vlen; + epp->ep_type = type; + memcpy((void *)(bp->bptr + sizeof(pmEventParameter)), src, vlen); + bp->bptr += need; + *bpp = bp; + return 0; +} + +int +pmdaEventAddParam(int idx, pmID pmid, int type, pmAtomValue *avp) +{ + int sts; + bufctl_t *bp; + pmEventRecord *erp; + + if ((sts = add_param(idx, pmid, type, avp, &bp)) >= 0) { + erp = (pmEventRecord *)bp->berp; + erp->er_nparams++; + } + return sts; +} + +int +pmdaEventHighResAddParam(int idx, pmID pmid, int type, pmAtomValue *avp) +{ + int sts; + bufctl_t *bp; + pmHighResEventRecord *hrerp; + + if ((sts = add_param(idx, pmid, type, avp, &bp)) >= 0) { + hrerp = (pmHighResEventRecord *)bp->berp; + hrerp->er_nparams++; + } + return sts; +} + +/* + * fill in the vlen/vtype header and return the address of the whole + * structure + */ +pmEventArray * +pmdaEventGetAddr(int idx) +{ + pmEventArray *eap; + + if (idx < 0 || idx >= nbuf || bufs[idx].bstate == B_FREE) + return NULL; + + eap = (pmEventArray *)bufs[idx].baddr; + eap->ea_type = PM_TYPE_EVENT; + eap->ea_len = bufs[idx].bptr - bufs[idx].baddr; + return eap; +} + +pmHighResEventArray * +pmdaEventHighResGetAddr(int idx) +{ + pmHighResEventArray *hreap; + + if (idx < 0 || idx >= nbuf || bufs[idx].bstate == B_FREE) + return NULL; + + hreap = (pmHighResEventArray *)bufs[idx].baddr; + hreap->ea_type = PM_TYPE_HIGHRES_EVENT; + hreap->ea_len = bufs[idx].bptr - bufs[idx].baddr; + return hreap; +} |