Page MenuHomeFreeBSD

D49163.1778436660.diff
No OneTemporary

Size
26 KB
Referenced Files
None
Subscribers
None

D49163.1778436660.diff

diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3
--- a/lib/libc/gen/sysctl.3
+++ b/lib/libc/gen/sysctl.3
@@ -511,6 +511,7 @@
.It Dv KERN_PROC_NFDS Ta "Integer"
.It Dv KERN_PROC_SIGFASTBLK Ta "Integer"
.It Dv KERN_PROC_VM_LAYOUT Ta "struct kinfo_vm_layout"
+.It Dv KERN_PROC_KQUEUE Ta "struct kinfo_knote []"
.El
.Pp
.Bl -tag -compact
@@ -584,6 +585,15 @@
location, if active.
.It Dv KERN_PROC_VM_LAYOUT
Fills a structure describing process virtual address space layout.
+.It Dv KERN_PROC_KQUEUE
+Fills an array of structures describing events registered with
+the specified kqueue.
+The next two node's values are the
+.Va pid
+and
+.Va kqfd ,
+the process ID of the process, and the file descriptor of the kqueue
+in that process, to query.
.El
.It Li KERN_PS_STRINGS
Reports the location of the process
diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map
--- a/lib/libprocstat/Symbol.map
+++ b/lib/libprocstat/Symbol.map
@@ -50,6 +50,8 @@
};
FBSD_1.8 {
+ procstat_get_kqueue_info;
procstat_getrlimitusage;
+ procstat_freekqinfo;
procstat_freerlimitusage;
};
\ No newline at end of file
diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h
--- a/lib/libprocstat/libprocstat.h
+++ b/lib/libprocstat/libprocstat.h
@@ -110,6 +110,7 @@
struct kinfo_kstack;
struct kinfo_proc;
struct kinfo_vmentry;
+struct kinfo_knote;
struct procstat;
struct ptrace_lwpinfo;
struct rlimit;
@@ -204,6 +205,7 @@
#endif
void procstat_freeenvv(struct procstat *procstat);
void procstat_freegroups(struct procstat *procstat, gid_t *groups);
+void procstat_freekqinfo(struct procstat *procstat, struct kinfo_knote *kni);
void procstat_freekstack(struct procstat *procstat,
struct kinfo_kstack *kkstp);
void procstat_freeprocs(struct procstat *procstat, struct kinfo_proc *p);
@@ -219,6 +221,8 @@
struct kinfo_proc *kp, int mmapped);
struct kinfo_proc *procstat_getprocs(struct procstat *procstat,
int what, int arg, unsigned int *count);
+struct kinfo_knote *procstat_get_kqueue_info(struct procstat *procstat,
+ struct kinfo_proc *kp, int kqfd, unsigned int *count, char *errbuf);
int procstat_get_pipe_info(struct procstat *procstat, struct filestat *fst,
struct pipestat *pipe, char *errbuf);
int procstat_get_pts_info(struct procstat *procstat, struct filestat *fst,
diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c
--- a/lib/libprocstat/libprocstat.c
+++ b/lib/libprocstat/libprocstat.c
@@ -2817,3 +2817,69 @@
{
free(resusage);
}
+
+static struct kinfo_knote *
+procstat_get_kqueue_info_sysctl(pid_t pid, int kqfd, unsigned int *cntp,
+ char *errbuf)
+{
+ int error, name[5];
+ struct kinfo_knote *val;
+ size_t len;
+
+ name[0] = CTL_KERN;
+ name[1] = KERN_PROC;
+ name[2] = KERN_PROC_KQUEUE;
+ name[3] = pid;
+ name[4] = kqfd;
+
+ len = 0;
+ error = sysctl(name, nitems(name), NULL, &len, NULL, 0);
+ if (error == -1) {
+ snprintf(errbuf, _POSIX2_LINE_MAX,
+ "KERN_PROC_KQUEUE.pid<%d>.kq<%d> (size q) failed: %s",
+ pid, kqfd, strerror(errno));
+ return (NULL);
+ }
+ val = malloc(len);
+ if (val == NULL) {
+ snprintf(errbuf, _POSIX2_LINE_MAX, "no memory");
+ return (NULL);
+ }
+
+ error = sysctl(name, nitems(name), val, &len, NULL, 0);
+ if (error == -1) {
+ snprintf(errbuf, _POSIX2_LINE_MAX,
+ "KERN_PROC_KQUEUE.pid<%d>.kq<%d> failed: %s",
+ pid, kqfd, strerror(errno));
+ free(val);
+ return (NULL);
+ }
+ *cntp = len / sizeof(*val);
+ return (val);
+}
+
+struct kinfo_knote *
+procstat_get_kqueue_info(struct procstat *procstat,
+ struct kinfo_proc *kp, int kqfd, unsigned int *count, char *errbuf)
+{
+ switch (procstat->type) {
+ case PROCSTAT_KVM:
+ warnx("kvm method is not supported");
+ return (NULL);
+ case PROCSTAT_SYSCTL:
+ return (procstat_get_kqueue_info_sysctl(kp->ki_pid, kqfd,
+ count, errbuf));
+ case PROCSTAT_CORE:
+ warnx("core method is not supported");
+ return (NULL);
+ default:
+ warnx("unknown access method: %d", procstat->type);
+ return (NULL);
+ }
+}
+
+void
+procstat_freekqinfo(struct procstat *procstat __unused, struct kinfo_knote *v)
+{
+ free(v);
+}
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -64,6 +64,7 @@
#include <sys/socketvar.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
+#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/syscallsubr.h>
#include <sys/taskqueue.h>
@@ -2829,3 +2830,103 @@
fdrop(fp, td);
return (error);
}
+
+static int
+sysctl_kern_proc_kqueue_report_one(struct proc *p, struct sysctl_req *req,
+ struct kqueue *kq, struct knote *kn)
+{
+ struct kinfo_knote kin;
+ int error;
+
+ if (kn->kn_status == KN_MARKER)
+ return (0);
+#if 0
+ if (kn_in_flux(kn) && (kn->kn_status & KN_SCAN) == 0)
+ return (0);
+#endif
+ memset(&kin, 0, sizeof(kin));
+ memcpy(&kin.knt_event, &kn->kn_kevent, sizeof(struct kevent));
+ kin.knt_status = kn->kn_status;
+ kn_enter_flux(kn);
+ KQ_UNLOCK_FLUX(kq);
+ if (kn->kn_fop->f_userdump != NULL)
+ (void)kn->kn_fop->f_userdump(p, kn, &kin);
+ error = SYSCTL_OUT(req, &kin, sizeof(kin));
+ maybe_yield();
+ KQ_LOCK(kq);
+ kn_leave_flux(kn);
+ return (error);
+}
+
+static int
+sysctl_kern_proc_kqueue(SYSCTL_HANDLER_ARGS)
+{
+ struct thread *td;
+ struct proc *p;
+ struct file *fp;
+ struct kqueue *kq;
+ struct knote *kn;
+ int error, i, *name;
+
+ name = (int *)arg1;
+ if ((u_int)arg2 != 2)
+ return (EINVAL);
+
+ error = pget((pid_t)name[0], PGET_HOLD | PGET_CANDEBUG, &p);
+ if (error != 0)
+ return (error);
+#ifdef COMPAT_FREEBSD32
+ if (SV_CURPROC_FLAG(SV_ILP32)) {
+ /* XXXKIB */
+ error = EOPNOTSUPP;
+ goto out1;
+ }
+#endif
+
+ td = curthread;
+ error = fget_remote(td, p, name[1] /* kqfd */, &fp);
+ if (error != 0)
+ goto out1;
+ if (fp->f_type != DTYPE_KQUEUE) {
+ error = EINVAL;
+ goto out2;
+ }
+
+ kq = fp->f_data;
+ if (req->oldptr == NULL) {
+ error = SYSCTL_OUT(req, NULL, sizeof(struct kinfo_knote) *
+ kq->kq_knlistsize * 11 / 10);
+ goto out2;
+ }
+
+ KQ_LOCK(kq);
+ for (i = 0; i < kq->kq_knlistsize; i++) {
+ SLIST_FOREACH(kn, &kq->kq_knlist[i], kn_link) {
+ error = sysctl_kern_proc_kqueue_report_one(p, req,
+ kq, kn);
+ if (error != 0)
+ goto out3;
+ }
+ }
+ if (kq->kq_knhashmask == 0)
+ goto out3;
+ for (i = 0; i <= kq->kq_knhashmask; i++) {
+ SLIST_FOREACH(kn, &kq->kq_knhash[i], kn_link) {
+ error = sysctl_kern_proc_kqueue_report_one(p, req,
+ kq, kn);
+ if (error != 0)
+ goto out3;
+ }
+ }
+out3:
+ KQ_UNLOCK_FLUX(kq);
+out2:
+ fdrop(fp, td);
+out1:
+ PRELE(p);
+ return (error);
+}
+
+static SYSCTL_NODE(_kern_proc, KERN_PROC_KQUEUE, kq,
+ CTLFLAG_RD | CTLFLAG_MPSAFE,
+ sysctl_kern_proc_kqueue, "KQueue events");
diff --git a/sys/kern/sys_eventfd.c b/sys/kern/sys_eventfd.c
--- a/sys/kern/sys_eventfd.c
+++ b/sys/kern/sys_eventfd.c
@@ -25,27 +25,25 @@
* SUCH DAMAGE.
*/
-#include <sys/param.h>
#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/limits.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/types.h>
-#include <sys/user.h>
+#include <sys/event.h>
+#include <sys/eventfd.h>
+#include <sys/errno.h>
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/filio.h>
-#include <sys/stat.h>
-#include <sys/errno.h>
-#include <sys/event.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
#include <sys/poll.h>
#include <sys/proc.h>
-#include <sys/uio.h>
#include <sys/selinfo.h>
-#include <sys/eventfd.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/user.h>
#include <security/audit/audit.h>
diff --git a/sys/kern/sys_pipe.c b/sys/kern/sys_pipe.c
--- a/sys/kern/sys_pipe.c
+++ b/sys/kern/sys_pipe.c
@@ -175,21 +175,26 @@
static int filt_pipenotsup(struct knote *kn, long hint);
static int filt_piperead(struct knote *kn, long hint);
static int filt_pipewrite(struct knote *kn, long hint);
+static int filt_pipedump(struct proc *p, struct knote *kn,
+ struct kinfo_knote *kin);
static const struct filterops pipe_nfiltops = {
.f_isfd = 1,
.f_detach = filt_pipedetach_notsup,
.f_event = filt_pipenotsup
+ /* no userdump */
};
static const struct filterops pipe_rfiltops = {
.f_isfd = 1,
.f_detach = filt_pipedetach,
- .f_event = filt_piperead
+ .f_event = filt_piperead,
+ .f_userdump = filt_pipedump,
};
static const struct filterops pipe_wfiltops = {
.f_isfd = 1,
.f_detach = filt_pipedetach,
- .f_event = filt_pipewrite
+ .f_event = filt_pipewrite,
+ .f_userdump = filt_pipedump,
};
/*
@@ -1900,3 +1905,14 @@
return (0);
}
+
+static int
+filt_pipedump(struct proc *p, struct knote *kn,
+ struct kinfo_knote *kin)
+{
+ struct pipe *pipe = kn->kn_hook;
+
+ kin->knt_extdata = KNOTE_EXTDATA_PIPE;
+ kin->knt_pipe.knt_pipe_ino = pipe->pipe_ino;
+ return (0);
+}
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -79,6 +79,7 @@
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
+#include <sys/user.h>
#include <sys/vmmeter.h>
#include <sys/vnode.h>
#include <sys/watchdog.h>
@@ -6483,7 +6484,7 @@
.f_isfd = 0,
.f_attach = filt_fsattach,
.f_detach = filt_fsdetach,
- .f_event = filt_fsevent
+ .f_event = filt_fsevent,
};
static int
@@ -6559,20 +6560,26 @@
static int filt_vfswrite(struct knote *kn, long hint);
static int filt_vfsvnode(struct knote *kn, long hint);
static void filt_vfsdetach(struct knote *kn);
+static int filt_vfsdump(struct proc *p, struct knote *kn,
+ struct kinfo_knote *kin);
+
static const struct filterops vfsread_filtops = {
.f_isfd = 1,
.f_detach = filt_vfsdetach,
- .f_event = filt_vfsread
+ .f_event = filt_vfsread,
+ .f_userdump = filt_vfsdump,
};
static const struct filterops vfswrite_filtops = {
.f_isfd = 1,
.f_detach = filt_vfsdetach,
- .f_event = filt_vfswrite
+ .f_event = filt_vfswrite,
+ .f_userdump = filt_vfsdump,
};
static const struct filterops vfsvnode_filtops = {
.f_isfd = 1,
.f_detach = filt_vfsdetach,
- .f_event = filt_vfsvnode
+ .f_event = filt_vfsvnode,
+ .f_userdump = filt_vfsdump,
};
static void
@@ -6721,6 +6728,41 @@
return (res);
}
+static int
+filt_vfsdump(struct proc *p, struct knote *kn, struct kinfo_knote *kin)
+{
+ struct vattr va;
+ struct vnode *vp;
+ char *fullpath, *freepath;
+ int error;
+
+ kin->knt_extdata = KNOTE_EXTDATA_VNODE;
+
+ vp = kn->kn_fp->f_vnode;
+ kin->knt_vnode.knt_vnode_type = vntype_to_kinfo(vp->v_type);
+
+ va.va_fsid = VNOVAL;
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ error = VOP_GETATTR(vp, &va, curthread->td_ucred);
+ VOP_UNLOCK(vp);
+ if (error != 0)
+ return (error);
+ kin->knt_vnode.knt_vnode_fsid = va.va_fsid;
+ kin->knt_vnode.knt_vnode_fileid = va.va_fileid;
+
+ freepath = NULL;
+ fullpath = "-";
+ error = vn_fullpath(vp, &fullpath, &freepath);
+ if (error == 0) {
+ strlcpy(kin->knt_vnode.knt_vnode_fullpath, fullpath,
+ sizeof(kin->knt_vnode.knt_vnode_fullpath));
+ }
+ if (freepath != NULL)
+ free(freepath, M_TEMP);
+
+ return (0);
+}
+
int
vfs_read_dirent(struct vop_readdir_args *ap, struct dirent *dp, off_t off)
{
diff --git a/sys/sys/event.h b/sys/sys/event.h
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -262,12 +262,17 @@
#define EVENT_REGISTER 1
#define EVENT_PROCESS 2
+struct kinfo_knote;
+struct proc;
+
struct filterops {
int f_isfd; /* true if ident == filedescriptor */
int (*f_attach)(struct knote *kn);
void (*f_detach)(struct knote *kn);
int (*f_event)(struct knote *kn, long hint);
void (*f_touch)(struct knote *kn, struct kevent *kev, u_long type);
+ int (*f_userdump)(struct proc *p, struct knote *kn,
+ struct kinfo_knote *kin);
};
/*
diff --git a/sys/sys/sysctl.h b/sys/sys/sysctl.h
--- a/sys/sys/sysctl.h
+++ b/sys/sys/sysctl.h
@@ -1041,6 +1041,7 @@
#define KERN_PROC_SIGFASTBLK 44 /* address of fastsigblk magic word */
#define KERN_PROC_VM_LAYOUT 45 /* virtual address space layout info */
#define KERN_PROC_RLIMIT_USAGE 46 /* array of rlim_t */
+#define KERN_PROC_KQUEUE 47 /* array of struct kinfo_knote */
/*
* KERN_IPC identifiers
diff --git a/sys/sys/user.h b/sys/sys/user.h
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -38,6 +38,7 @@
#ifndef _KERNEL
/* stuff that *used* to be included by user.h, or is now needed */
#include <sys/errno.h>
+#include <sys/event.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/ucred.h>
@@ -665,6 +666,27 @@
uintptr_t kvm_spare[12];
};
+#define KNOTE_EXTDATA_NONE 0
+#define KNOTE_EXTDATA_VNODE 1
+#define KNOTE_EXTDATA_PIPE 2
+
+struct kinfo_knote {
+ struct kevent knt_event;
+ int knt_status;
+ int knt_extdata;
+ union {
+ struct knt_vnode_t {
+ int knt_vnode_type;
+ uint64_t knt_vnode_fsid;
+ uint64_t knt_vnode_fileid;
+ char knt_vnode_fullpath[PATH_MAX];
+ } knt_vnode ;
+ struct knt_pipe_t {
+ ino_t knt_pipe_ino;
+ } knt_pipe;
+ };
+};
+
#ifdef _KERNEL
/* Flags for kern_proc_out function. */
#define KERN_PROC_NOTHREADS 0x1
diff --git a/sys/vm/sg_pager.c b/sys/vm/sg_pager.c
--- a/sys/vm/sg_pager.c
+++ b/sys/vm/sg_pager.c
@@ -34,6 +34,7 @@
*/
#include <sys/param.h>
+#include <sys/event.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/rwlock.h>
diff --git a/usr.bin/procstat/Makefile b/usr.bin/procstat/Makefile
--- a/usr.bin/procstat/Makefile
+++ b/usr.bin/procstat/Makefile
@@ -11,6 +11,7 @@
procstat_cred.c \
procstat_cs.c \
procstat_files.c \
+ procstat_kqueue.c \
procstat_kstack.c \
procstat_penv.c \
procstat_ptlwpinfo.c \
diff --git a/usr.bin/procstat/procstat.h b/usr.bin/procstat/procstat.h
--- a/usr.bin/procstat/procstat.h
+++ b/usr.bin/procstat/procstat.h
@@ -64,6 +64,7 @@
void procstat_cs(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_env(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_files(struct procstat *prstat, struct kinfo_proc *kipp);
+void procstat_kqueues(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_kstack(struct procstat *prstat, struct kinfo_proc *kipp);
void procstat_rlimitusage(struct procstat *procstat,
struct kinfo_proc *kipp);
diff --git a/usr.bin/procstat/procstat.1 b/usr.bin/procstat/procstat.1
--- a/usr.bin/procstat/procstat.1
+++ b/usr.bin/procstat/procstat.1
@@ -159,16 +159,24 @@
.Va pid
list can be used to limit the display of the locks, mostly because
some types of locks do not have local (or any) owning processes.
+.It Ar argument(s) | Fl c
+Display command line arguments for the process.
+.Pp
+Substring commands are accepted.
+.It Ar auxv | Fl x
+Display ELF auxiliary vector for the process.
.It Ar basic
Print basic process statistics (this is the default).
.It Ar binary | Fl b
Display binary information for the process.
.Pp
Substring commands are accepted.
-.It Ar argument(s) | Fl c
-Display command line arguments for the process.
+.It Ar credential(s) | Fl s
+Display security credential information for the process.
.Pp
Substring commands are accepted.
+.It Ar cpuset | Ar cs | Fl S
+Display the cpuset information for the thread.
.It Ar environment | Fl e
Display environment variables for the process.
.Pp
@@ -179,24 +187,8 @@
If the
.Fl C
subcommand flag is used then additional capability information is printed.
-.It Ar signal(s) | Fl i
-Display signal pending and disposition information for the process.
-.Pp
-If the
-.Fl n
-subcommand option is used, the signal numbers are shown instead of signal
-names.
-.Pp
-Substring commands are accepted.
-.It Ar tsignal(s) | Fl j
-Display signal pending and blocked information for the process's threads.
-.Pp
-If the
-.Fl n
-subcommand option is used, the signal numbers are shown instead of signal
-names.
-.Pp
-Substring commands are accepted.
+.It Ar kqueue(s)
+Display the events registered in the process kqueues.
.It Ar kstack | Fl k
Display the stacks of kernel threads in the process, excluding stacks of
threads currently running on a CPU and threads with stacks swapped to disk.
@@ -205,10 +197,18 @@
.Fl v
subcommand option is used (or the command flag is repeated), function
offsets as well as function names are printed.
-.It Ar rlimit | Fl l
-Display resource limits for the process.
+.It Ar pargs
+Display arguments for the process.
+.It Ar penv
+Display environment variables for the process.
.It Ar ptlwpinfo | Fl L
Display LWP info for the process pertaining to its signal driven exit.
+.It Ar pwdx
+Display current working directory for the process.
+.It Ar rlimit | Fl l
+Display resource limits for the process.
+.It Ar rlimitusage
+Display the usage of the resource limits for the process.
.It Ar rusage | Fl r
Display resource usage information for the process.
.Pp
@@ -220,24 +220,28 @@
statistics.
The second field in the table will list the thread ID to which the row of
information corresponds.
-.It Ar credential(s) | Fl s
-Display security credential information for the process.
+.It Ar signal(s) | Fl i
+Display signal pending and disposition information for the process.
+.Pp
+If the
+.Fl n
+subcommand option is used, the signal numbers are shown instead of signal
+names.
.Pp
Substring commands are accepted.
-.It Ar cpuset | Ar cs | Fl S
-Display the cpuset information for the thread.
.It Ar thread(s) | Fl t
Display thread information for the process.
+.It Ar tsignal(s) | Fl j
+Display signal pending and blocked information for the process's threads.
+.Pp
+If the
+.Fl n
+subcommand option is used, the signal numbers are shown instead of signal
+names.
+.Pp
+Substring commands are accepted.
.It Ar vm | Fl v
Display virtual memory mappings for the process.
-.It Ar auxv | Fl x
-Display ELF auxiliary vector for the process.
-.It Ar pargs
-Display arguments for the process.
-.It Ar penv
-Display environment variables for the process.
-.It Ar pwdx
-Display current working directory for the process.
.El
.Pp
All options generate output in the format of a table, the first field of
diff --git a/usr.bin/procstat/procstat.c b/usr.bin/procstat/procstat.c
--- a/usr.bin/procstat/procstat.c
+++ b/usr.bin/procstat/procstat.c
@@ -103,6 +103,8 @@
PS_CMP_PLURAL },
{ "file", "files", "[-C]", &procstat_files, &cmdopt_files,
PS_CMP_PLURAL },
+ { "kqueue", "kqueues", NULL, &procstat_kqueues, &cmdopt_none,
+ PS_CMP_PLURAL },
{ "kstack", "kstack", "[-v]", &procstat_kstack, &cmdopt_verbose,
PS_CMP_NORMAL },
{ "pargs", "args", NULL, &procstat_pargs, &cmdopt_none,
diff --git a/usr.bin/procstat/procstat_kqueue.c b/usr.bin/procstat/procstat_kqueue.c
new file mode 100644
--- /dev/null
+++ b/usr.bin/procstat/procstat_kqueue.c
@@ -0,0 +1,311 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 The FreeBSD Foundation
+ *
+ * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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.
+ *
+ * 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/param.h>
+#define _KERNEL
+#include <sys/event.h>
+#undef _KERNEL
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <errno.h>
+#include <libprocstat.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "procstat.h"
+
+static const char kqs[] = "kqueues";
+static const char kq[] = "kqueue";
+
+#define FILT_ELEM(name) [-EVFILT_##name] = #name,
+static const char *filter_names[] = {
+ [0] = "invalid",
+ FILT_ELEM(READ)
+ FILT_ELEM(WRITE)
+ FILT_ELEM(AIO)
+ FILT_ELEM(VNODE)
+ FILT_ELEM(PROC)
+ FILT_ELEM(SIGNAL)
+ FILT_ELEM(TIMER)
+ FILT_ELEM(PROCDESC)
+ FILT_ELEM(FS)
+ FILT_ELEM(LIO)
+ FILT_ELEM(USER)
+ FILT_ELEM(SENDFILE)
+ FILT_ELEM(EMPTY)
+};
+#undef FILT_ELEM
+
+#define PK_FLAG_ELEM(prefix, fname) { .flag = prefix##fname, .name = #fname }
+#define PK_FLAG_LAST_ELEM() { .flag = -1, .name = 0 }
+struct pk_elem {
+ unsigned int flag;
+ const char *name;
+};
+
+static const struct pk_elem kn_status_names[] = {
+ PK_FLAG_ELEM(KN_, ACTIVE),
+ PK_FLAG_ELEM(KN_, QUEUED),
+ PK_FLAG_ELEM(KN_, DISABLED),
+ PK_FLAG_ELEM(KN_, DETACHED),
+ PK_FLAG_ELEM(KN_, MARKER),
+ PK_FLAG_ELEM(KN_, KQUEUE),
+ PK_FLAG_ELEM(KN_, SCAN),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static const struct pk_elem ev_flags_names[] = {
+ PK_FLAG_ELEM(EV_, ONESHOT),
+ PK_FLAG_ELEM(EV_, CLEAR),
+ PK_FLAG_ELEM(EV_, RECEIPT),
+ PK_FLAG_ELEM(EV_, DISPATCH),
+ PK_FLAG_ELEM(EV_, DROP),
+ PK_FLAG_ELEM(EV_, FLAG1),
+ PK_FLAG_ELEM(EV_, FLAG2),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static char *
+procstat_kqueue_flags(const struct pk_elem *names, unsigned flags)
+{
+ char *bres, *res;
+ const struct pk_elem *pl;
+ size_t len;
+ int i;
+ bool first;
+
+ first = true;
+ len = 0;
+ for (i = 0;; i++) {
+ pl = &names[i];
+ if (pl->flag == (unsigned)-1)
+ break;
+ if ((flags & pl->flag) != 0) {
+ if (first)
+ first = false;
+ else
+ len += sizeof(",");
+ len += strlen(pl->name);
+ }
+ }
+ len++;
+
+ res = malloc(len);
+ first = true;
+ res[0] = '\0';
+ for (i = 0;; i++) {
+ pl = &names[i];
+ if (pl->flag == (unsigned)-1)
+ break;
+ if ((flags & pl->flag) != 0) {
+ if (first)
+ first = false;
+ else
+ strlcat(res, ",", len);
+ strlcat(res, pl->name, len);
+ }
+ }
+
+ if (strlen(res) == 0)
+ return (res);
+ asprintf(&bres, "(%s)", res);
+ free(res);
+ return (bres);
+}
+
+static const struct pk_elem rw_filter_names[] = {
+ PK_FLAG_ELEM(NOTE_, LOWAT),
+ PK_FLAG_ELEM(NOTE_, FILE_POLL),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static const struct pk_elem user_filter_names[] = {
+ PK_FLAG_ELEM(NOTE_, FFAND),
+ PK_FLAG_ELEM(NOTE_, FFOR),
+ PK_FLAG_ELEM(NOTE_, TRIGGER),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static const struct pk_elem vnode_filter_names[] = {
+ PK_FLAG_ELEM(NOTE_, DELETE),
+ PK_FLAG_ELEM(NOTE_, WRITE),
+ PK_FLAG_ELEM(NOTE_, EXTEND),
+ PK_FLAG_ELEM(NOTE_, ATTRIB),
+ PK_FLAG_ELEM(NOTE_, LINK),
+ PK_FLAG_ELEM(NOTE_, RENAME),
+ PK_FLAG_ELEM(NOTE_, REVOKE),
+ PK_FLAG_ELEM(NOTE_, OPEN),
+ PK_FLAG_ELEM(NOTE_, CLOSE),
+ PK_FLAG_ELEM(NOTE_, CLOSE_WRITE),
+ PK_FLAG_ELEM(NOTE_, READ),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static const struct pk_elem proc_filter_names[] = {
+ PK_FLAG_ELEM(NOTE_, EXIT),
+ PK_FLAG_ELEM(NOTE_, FORK),
+ PK_FLAG_ELEM(NOTE_, EXEC),
+ PK_FLAG_ELEM(NOTE_, TRACK),
+ PK_FLAG_ELEM(NOTE_, TRACKERR),
+ PK_FLAG_ELEM(NOTE_, CHILD),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static const struct pk_elem timer_filter_names[] = {
+ PK_FLAG_ELEM(NOTE_, SECONDS),
+ PK_FLAG_ELEM(NOTE_, MSECONDS),
+ PK_FLAG_ELEM(NOTE_, USECONDS),
+ PK_FLAG_ELEM(NOTE_, NSECONDS),
+ PK_FLAG_ELEM(NOTE_, ABSTIME),
+ PK_FLAG_LAST_ELEM(),
+};
+
+#define FILT_ELEM(name) [-EVFILT_##name] = "EVFILT_"#name,
+static const struct pk_elem *filter_pk_names[] = {
+ [0] = NULL,
+ [-EVFILT_READ] = rw_filter_names,
+ [-EVFILT_WRITE] = rw_filter_names,
+ [-EVFILT_AIO] = rw_filter_names,
+ [-EVFILT_VNODE] = vnode_filter_names,
+ [-EVFILT_PROC] = proc_filter_names,
+ [-EVFILT_SIGNAL] = NULL,
+ [-EVFILT_TIMER] = timer_filter_names,
+ [-EVFILT_PROCDESC] = proc_filter_names,
+ [-EVFILT_FS] = NULL,
+ [-EVFILT_LIO] = rw_filter_names,
+ [-EVFILT_USER] = user_filter_names,
+ [-EVFILT_SENDFILE] = NULL,
+ [-EVFILT_EMPTY] = NULL,
+};
+
+static char *
+procstat_kqueue_fflags(int filter, unsigned fflags)
+{
+ const struct pk_elem *names;
+
+ names = NULL;
+ if (filter < 0 && -filter < (int)nitems(filter_pk_names))
+ names = filter_pk_names[-filter];
+ if (names == NULL)
+ return (strdup(""));
+ return (procstat_kqueue_flags(names, fflags));
+}
+
+static const char *
+procstat_kqueue_get_filter_name(int filter)
+{
+ filter = -filter;
+ if (filter < 0 || filter >= (int)nitems(filter_names))
+ filter = 0;
+ return (filter_names[filter]);
+}
+
+static void
+procstat_kqueue(struct procstat *procstat, struct kinfo_proc *kipp, int fd)
+{
+ struct kinfo_knote *kni, *knis;
+ char *flags, *fflags, *status;
+ unsigned int count, i;
+ char errbuf[_POSIX2_LINE_MAX];
+
+ errbuf[0] = '\0';
+ knis = procstat_get_kqueue_info(procstat, kipp, fd, &count, errbuf);
+ if (knis == NULL) {
+ warnx("%s\n", errbuf);
+ return;
+ }
+
+ for (i = 0; i < count; i++) {
+ kni = &knis[i];
+ flags = procstat_kqueue_flags(ev_flags_names,
+ kni->knt_event.flags);
+ fflags = procstat_kqueue_fflags(kni->knt_event.filter,
+ kni->knt_event.fflags);
+ status = procstat_kqueue_flags(kn_status_names,
+ kni->knt_status);
+ xo_open_instance(kq);
+ xo_emit("{dk:process_id/%7d} ", kipp->ki_pid);
+ xo_emit("{:kqueue_fd/%10d} ", fd);
+ xo_emit("{:filter/%8s} ", procstat_kqueue_get_filter_name(
+ kni->knt_event.filter));
+ xo_emit("{:ident/%10d} ", kni->knt_event.ident);
+ xo_emit("{:flags/%#10x%s} ", kni->knt_event.flags, flags);
+ xo_emit("{:fflags/%#10x%s} ", kni->knt_event.fflags, fflags);
+ xo_emit("{:data/%#10jx} ", (uintmax_t)kni->knt_event.data);
+ xo_emit("{:udata/%10p} ", (uintmax_t)kni->knt_event.udata);
+ xo_emit("{:ext0/%#10jx} ", (uintmax_t)kni->knt_event.ext[0]);
+ xo_emit("{:ext1/%#10jx} ", (uintmax_t)kni->knt_event.ext[1]);
+ xo_emit("{:ext2/%#10jx} ", (uintmax_t)kni->knt_event.ext[2]);
+ xo_emit("{:ext3/%#10jx} ", (uintmax_t)kni->knt_event.ext[3]);
+ xo_emit("{:status/%#10x%s}\n", (uintmax_t)kni->knt_status,
+ status);
+ free(flags);
+ free(fflags);
+ free(status);
+ xo_close_instance(kq);
+ }
+
+ procstat_freekqinfo(procstat, knis);
+}
+
+void
+procstat_kqueues(struct procstat *procstat, struct kinfo_proc *kipp)
+{
+ struct filestat_list *fl;
+ struct filestat *f;
+
+ if ((procstat_opts & PS_OPT_NOHEADER) == 0)
+ xo_emit("{T:/%7s %10s %8s %10s %10s %10s %10s %10s "
+ "%10s %10s %10s %10s %10s}\n",
+ "PID", "KQFD", "FILTER", "IDENT", "FLAGS", "FFLAGS",
+ "DATA", "UDATA", "EXT0", "EXT1","EXT2","EXT3", "STATUS");
+
+ xo_emit("{ek:process_id/%d}", kipp->ki_pid);
+
+ fl = procstat_getfiles(procstat, kipp, 0);
+ if (fl == NULL)
+ return;
+ xo_open_list(kqs);
+ STAILQ_FOREACH(f, fl, next) {
+ if (f->fs_type != PS_FST_TYPE_KQUEUE)
+ continue;
+ xo_emit("{ek:kqueue/%d}", f->fs_fd);
+ xo_open_list(kq);
+ procstat_kqueue(procstat, kipp, f->fs_fd);
+ xo_close_list(kq);
+ }
+ xo_close_list(kqs);
+ procstat_freefiles(procstat, fl);
+}

File Metadata

Mime Type
text/plain
Expires
Sun, May 10, 6:11 PM (16 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28642560
Default Alt Text
D49163.1778436660.diff (26 KB)

Event Timeline