diff options
-rw-r--r-- | lib/libkvm/Makefile | 7 | ||||
-rw-r--r-- | lib/libkvm/kvm.h | 2 | ||||
-rw-r--r-- | lib/libkvm/kvm_getpcpu.3 | 93 | ||||
-rw-r--r-- | lib/libkvm/kvm_pcpu.c | 152 |
4 files changed, 251 insertions, 3 deletions
diff --git a/lib/libkvm/Makefile b/lib/libkvm/Makefile index 50b254b..1204217 100644 --- a/lib/libkvm/Makefile +++ b/lib/libkvm/Makefile @@ -10,15 +10,16 @@ CFLAGS+=-DSUN4V .endif SRCS= kvm.c kvm_${MACHINE_ARCH}.c kvm_file.c kvm_getloadavg.c \ - kvm_getswapinfo.c kvm_proc.c + kvm_getswapinfo.c kvm_pcpu.c kvm_proc.c .if ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "i386" SRCS+= kvm_minidump_${MACHINE_ARCH}.c .endif INCS= kvm.h -MAN= kvm.3 kvm_geterr.3 kvm_getfiles.3 kvm_getloadavg.3 kvm_getprocs.3 \ - kvm_getswapinfo.3 kvm_nlist.3 kvm_open.3 kvm_read.3 +MAN= kvm.3 kvm_geterr.3 kvm_getfiles.3 kvm_getloadavg.3 kvm_getpcpu.3 \ + kvm_getprocs.3 kvm_getswapinfo.3 kvm_nlist.3 kvm_open.3 +MLINKS+=kvm_getpcpu.3 kvm_getmaxcpu.3 MLINKS+=kvm_getprocs.3 kvm_getargv.3 kvm_getprocs.3 kvm_getenvv.3 MLINKS+=kvm_open.3 kvm_close.3 kvm_open.3 kvm_openfiles.3 MLINKS+=kvm_read.3 kvm_write.3 diff --git a/lib/libkvm/kvm.h b/lib/libkvm/kvm.h index 8d40ed3..c60d211 100644 --- a/lib/libkvm/kvm.h +++ b/lib/libkvm/kvm.h @@ -74,6 +74,8 @@ char **kvm_getenvv(kvm_t *, const struct kinfo_proc *, int); char *kvm_geterr(kvm_t *); char *kvm_getfiles(kvm_t *, int, int, int *); int kvm_getloadavg(kvm_t *, double [], int); +int kvm_getmaxcpu(kvm_t *); +void *kvm_getpcpu(kvm_t *, int); struct kinfo_proc * kvm_getprocs(kvm_t *, int, int, int *); int kvm_getswapinfo(kvm_t *, struct kvm_swap *, int, int); diff --git a/lib/libkvm/kvm_getpcpu.3 b/lib/libkvm/kvm_getpcpu.3 new file mode 100644 index 0000000..87cd139 --- /dev/null +++ b/lib/libkvm/kvm_getpcpu.3 @@ -0,0 +1,93 @@ +.\" Copyright (c) 2008 Yahoo!, Inc. +.\" All rights reserved. +.\" Written by: John Baldwin <jhb@FreeBSD.org> +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd August 19, 2008 +.Dt KVM_GETPCPU 3 +.Os +.Sh NAME +.Nm kvm_getmaxcpu , +.Nm kvm_getpcpu +.Nd access per-CPU data +.Sh LIBRARY +.Lb libkvm +.Sh SYNOPSIS +.In sys/param.h +.In sys/pcpu.h +.In sys/sysctl.h +.In kvm.h +.Ft int +.Fn kvm_getmaxcpu "kvm_t *kd" +.Ft void * +.Fn kvm_getpcpu "kvm_t *kd" "int cpu" +.Sh DESCRIPTION +The +.Fn kvm_getmaxcpu +and +.Fn kvm_getpcpu +functions are used to access the per-CPU data of active processors in the +kernel indicated by +.Fa kd . +The +.Fn kvm_getmaxcpu +function returns the maximum number of CPUs supported by the kernel. +The +.Fn kvm_getpcpu +function returns a buffer holding the per-CPU data for a single CPU. +This buffer is described by the +.Vt "struct pcpu" +type. +The caller is responsible for releasing the buffer via a call to +.Xr free 3 +when it is no longer needed. +If +.Fa cpu +is not active, then +.Dv NULL +is returned instead. +.Sh RETURN VALUES +On success, the +.Fn kvm_getmaxcpu +function returns the maximum number of CPUs supported by the kernel. +If an error occurs, +it returns -1 instead. +.Pp +On success, the +.Fn kvm_getpcpu +function returns a pointer to an allocated buffer or +.Dv NULL. +If an error occurs, +it returns -1 instead. +.Pp +If either function encounters an error, +then an error message may be retrieved via +.Xr kvm_geterr 3. +.Sh SEE ALSO +.Xr free 3 , +.Xr kvm 3 diff --git a/lib/libkvm/kvm_pcpu.c b/lib/libkvm/kvm_pcpu.c new file mode 100644 index 0000000..e4f8909 --- /dev/null +++ b/lib/libkvm/kvm_pcpu.c @@ -0,0 +1,152 @@ +/*- + * Copyright (c) 2008 Yahoo!, Inc. + * All rights reserved. + * Written by: John Baldwin <jhb@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/pcpu.h> +#include <sys/sysctl.h> +#include <kvm.h> +#include <limits.h> +#include <stdlib.h> + +#include "kvm_private.h" + +static struct nlist kvm_pcpu_nl[] = { + { "_cpuid_to_pcpu" }, + { "_mp_maxcpus" }, + { NULL }, +}; + +/* + * Kernel per-CPU data state. We cache this stuff on the first + * access. + */ +static void **pcpu_data; +static int maxcpu; + +#define NL_CPUID_TO_PCPU 0 +#define NL_MP_MAXCPUS 1 + +static int +_kvm_pcpu_init(kvm_t *kd) +{ + size_t len; + int max; + void *data; + + if (kvm_nlist(kd, kvm_pcpu_nl) < 0) + return (-1); + if (kvm_pcpu_nl[NL_CPUID_TO_PCPU].n_value == 0) { + _kvm_err(kd, kd->program, "unable to find cpuid_to_pcpu"); + return (-1); + } + if (kvm_pcpu_nl[NL_MP_MAXCPUS].n_value == 0) { + _kvm_err(kd, kd->program, "unable to find mp_maxcpus"); + return (-1); + } + if (kvm_read(kd, kvm_pcpu_nl[NL_MP_MAXCPUS].n_value, &max, + sizeof(max)) != sizeof(max)) { + _kvm_err(kd, kd->program, "cannot read mp_maxcpus"); + return (-1); + } + len = max * sizeof(void *); + data = malloc(len); + if (data == NULL) { + _kvm_err(kd, kd->program, "out of memory"); + return (-1); + } + if (kvm_read(kd, kvm_pcpu_nl[NL_CPUID_TO_PCPU].n_value, data, len) != + len) { + _kvm_err(kd, kd->program, "cannot read cpuid_to_pcpu array"); + free(data); + return (-1); + } + pcpu_data = data; + maxcpu = max; + return (0); +} + +static void +_kvm_pcpu_clear(void) +{ + + maxcpu = 0; + free(pcpu_data); + pcpu_data = NULL; +} + +void * +kvm_getpcpu(kvm_t *kd, int cpu) +{ + char *buf; + int i; + + if (kd == NULL) { + _kvm_pcpu_clear(); + return (NULL); + } + + if (maxcpu == 0) + if (_kvm_pcpu_init(kd) < 0) + return ((void *)-1); + + if (cpu >= maxcpu || pcpu_data[cpu] == NULL) + return (NULL); + + buf = malloc(sizeof(struct pcpu)); + if (buf == NULL) { + _kvm_err(kd, kd->program, "out of memory"); + return ((void *)-1); + } + if (kvm_read(kd, (uintptr_t)pcpu_data[cpu], buf, sizeof(struct pcpu)) != + sizeof(struct pcpu)) { + _kvm_err(kd, kd->program, "unable to read per-CPU data"); + free(buf); + return ((void *)-1); + } + return (buf); +} + +int +kvm_getmaxcpu(kvm_t *kd) +{ + + if (kd == NULL) { + _kvm_pcpu_clear(); + return (0); + } + + if (maxcpu == 0) + if (_kvm_pcpu_init(kd) < 0) + return (-1); + return (maxcpu); +} |