Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144639435
D49163.id152062.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
29 KB
Referenced Files
None
Subscribers
None
D49163.id152062.diff
View Options
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>
@@ -2730,8 +2731,15 @@
KQ_NOTOWNED(kq);
KQ_LOCK(kq);
- KASSERT(kn->kn_influx == 1,
- ("knote_drop called on %p with influx %d", kn, kn->kn_influx));
+ for (;;) {
+ KASSERT(kn->kn_influx >= 1,
+ ("knote_drop called on %p with influx %d",
+ kn, kn->kn_influx));
+ if (kn->kn_influx == 1)
+ break;
+ kq->kq_state |= KQ_FLUXWAIT;
+ msleep(kq, &kq->kq_lock, PSOCK, "kqflxwt", 0);
+ }
if (kn->kn_fop->f_isfd)
list = &kq->kq_knlist[kn->kn_id];
@@ -2829,3 +2837,132 @@
fdrop(fp, td);
return (error);
}
+
+struct knote_status_export_bit {
+ int kn_status_bit;
+ int knt_status_bit;
+};
+
+#define ST(name) \
+ { .kn_status_bit = KN_##name, .knt_status_bit = KNOTE_STATUS_##name }
+static const struct knote_status_export_bit knote_status_export_bits[] = {
+ ST(ACTIVE),
+ ST(QUEUED),
+ ST(DISABLED),
+ ST(DETACHED),
+ ST(KQUEUE),
+};
+#undef ST
+
+static int
+knote_status_export(int kn_status)
+{
+ const struct knote_status_export_bit *b;
+ unsigned i;
+ int res;
+
+ res = 0;
+ for (i = 0; i < nitems(knote_status_export_bits); i++) {
+ b = &knote_status_export_bits[i];
+ if ((kn_status & b->kn_status_bit) != 0)
+ res |= b->knt_status_bit;
+ }
+ return (res);
+}
+
+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);
+
+ memset(&kin, 0, sizeof(kin));
+ memcpy(&kin.knt_event, &kn->kn_kevent, sizeof(struct kevent));
+ kin.knt_status = knote_status_export(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,33 @@
uintptr_t kvm_spare[12];
};
+#define KNOTE_STATUS_ACTIVE 0x00000001
+#define KNOTE_STATUS_QUEUED 0x00000002
+#define KNOTE_STATUS_DISABLED 0x00000004
+#define KNOTE_STATUS_DETACHED 0x00000008
+#define KNOTE_STATUS_KQUEUE 0x00000010
+
+#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 {
+ int knt_vnode_type;
+ uint64_t knt_vnode_fsid;
+ uint64_t knt_vnode_fileid;
+ char knt_vnode_fullpath[PATH_MAX];
+ } knt_vnode;
+ struct {
+ 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,36 +187,67 @@
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
+.It Ar kqueue(s) Op Fl v
+Display the events registered in the process kqueues.
+The filter name, filter-specific identifier, flags, filter-specific flags,
+system and user data, and event status are displayed.
If the
-.Fl n
-subcommand option is used, the signal numbers are shown instead of signal
-names.
+.Fl v
+verbose flag is provided to the subcommand, the values of the ext array
+are displayed as well.
.Pp
-Substring commands are accepted.
-.It Ar tsignal(s) | Fl j
-Display signal pending and blocked information for the process's threads.
+For flags, the string consisting of the following symbols corresponding
+to the set flags, is printed:
+.Bl -tag -width X -compact
+.It O
+.Va EV_ONESHOT
+.It C
+.Va EV_CLEAR
+.It R
+.Va EV_RECEIPT
+.It D
+.Va EV_DISPATCH
+.It d
+.Va EV_DROP
+.It 1
+.Va EV_FLAG1
+.It 2
+.Va EV_FLAG2
+.El
.Pp
-If the
-.Fl n
-subcommand option is used, the signal numbers are shown instead of signal
-names.
-.Pp
-Substring commands are accepted.
+For status:
+.Bl -tag -width X -compact
+.It A
+.Va KNOTE_STATUS_ACTIVE
+.It A
+.Va KNOTE_STATUS_QUEUED
+.It D
+.Va KNOTE_STATUS_DISABLED
+.It d
+.Va KNOTE_STATUS_DETACHED
+.It K
+.Va KNOTE_STATUS_KQUEUE
+.El
.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.
+threads currently running on a CPU in userspace.
.Pp
If the
.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 +259,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
@@ -65,6 +65,7 @@
static void cmdopt_rusage(int argc, char * const argv[]);
static void cmdopt_files(int argc, char * const argv[]);
static void cmdopt_cpuset(int argc, char * const argv[]);
+static void cmdopt_kqueue(int argc, char * const argv[]);
static const char *progname;
@@ -103,6 +104,8 @@
PS_CMP_PLURAL },
{ "file", "files", "[-C]", &procstat_files, &cmdopt_files,
PS_CMP_PLURAL },
+ { "kqueue", "kqueues", NULL, &procstat_kqueues, &cmdopt_kqueue,
+ PS_CMP_PLURAL },
{ "kstack", "kstack", "[-v]", &procstat_kstack, &cmdopt_verbose,
PS_CMP_NORMAL },
{ "pargs", "args", NULL, &procstat_pargs, &cmdopt_none,
@@ -631,3 +634,20 @@
procstat_opts |= PS_OPT_PERTHREAD;
cmdopt_none(argc, argv);
}
+
+void
+cmdopt_kqueue(int argc, char * const argv[])
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "v")) != -1) {
+ switch (ch) {
+ case 'v':
+ procstat_opts |= PS_OPT_VERBOSE;
+ break;
+ case '?':
+ default:
+ usage(NULL);
+ }
+ }
+}
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,322 @@
+/*-
+ * 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>
+#include <sys/event.h>
+#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 *const 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(fname, str) { .flag = fname, .dispstr = str }
+#define PK_NAME_ELEM(prefix, fname) { .flag = prefix##fname, .dispstr = #fname }
+#define PK_FLAG_LAST_ELEM() { .flag = -1, .dispstr = NULL }
+struct pk_elem {
+ unsigned int flag;
+ const char *dispstr;
+};
+
+static const struct pk_elem kn_status_names[] = {
+ PK_FLAG_ELEM(KNOTE_STATUS_ACTIVE, "A"),
+ PK_FLAG_ELEM(KNOTE_STATUS_QUEUED, "Q"),
+ PK_FLAG_ELEM(KNOTE_STATUS_DISABLED, "D"),
+ PK_FLAG_ELEM(KNOTE_STATUS_DETACHED, "d"),
+ PK_FLAG_ELEM(KNOTE_STATUS_KQUEUE, "K"),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static const struct pk_elem ev_flags_names[] = {
+ PK_FLAG_ELEM(EV_ONESHOT, "O"),
+ PK_FLAG_ELEM(EV_CLEAR, "C"),
+ PK_FLAG_ELEM(EV_RECEIPT, "R"),
+ PK_FLAG_ELEM(EV_DISPATCH, "D"),
+ PK_FLAG_ELEM(EV_DROP, "d"),
+ PK_FLAG_ELEM(EV_FLAG1, "1"),
+ PK_FLAG_ELEM(EV_FLAG2, "2"),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static char *
+procstat_kqueue_flags(const struct pk_elem *names, unsigned flags, bool commas)
+{
+ 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 if (commas)
+ len += sizeof(",");
+ len += strlen(pl->dispstr);
+ }
+ }
+ 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 if (commas)
+ strlcat(res, ",", len);
+ strlcat(res, pl->dispstr, len);
+ }
+ }
+
+ if (strlen(res) == 0)
+ return (res);
+ asprintf(&bres, "(%s)", res);
+ free(res);
+ return (bres);
+}
+
+static const struct pk_elem rw_filter_names[] = {
+ PK_NAME_ELEM(NOTE_, LOWAT),
+ PK_NAME_ELEM(NOTE_, FILE_POLL),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static const struct pk_elem user_filter_names[] = {
+ PK_NAME_ELEM(NOTE_, FFAND),
+ PK_NAME_ELEM(NOTE_, FFOR),
+ PK_NAME_ELEM(NOTE_, TRIGGER),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static const struct pk_elem vnode_filter_names[] = {
+ PK_NAME_ELEM(NOTE_, DELETE),
+ PK_NAME_ELEM(NOTE_, WRITE),
+ PK_NAME_ELEM(NOTE_, EXTEND),
+ PK_NAME_ELEM(NOTE_, ATTRIB),
+ PK_NAME_ELEM(NOTE_, LINK),
+ PK_NAME_ELEM(NOTE_, RENAME),
+ PK_NAME_ELEM(NOTE_, REVOKE),
+ PK_NAME_ELEM(NOTE_, OPEN),
+ PK_NAME_ELEM(NOTE_, CLOSE),
+ PK_NAME_ELEM(NOTE_, CLOSE_WRITE),
+ PK_NAME_ELEM(NOTE_, READ),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static const struct pk_elem proc_filter_names[] = {
+ PK_NAME_ELEM(NOTE_, EXIT),
+ PK_NAME_ELEM(NOTE_, FORK),
+ PK_NAME_ELEM(NOTE_, EXEC),
+ PK_NAME_ELEM(NOTE_, TRACK),
+ PK_NAME_ELEM(NOTE_, TRACKERR),
+ PK_NAME_ELEM(NOTE_, CHILD),
+ PK_FLAG_LAST_ELEM(),
+};
+
+static const struct pk_elem timer_filter_names[] = {
+ PK_NAME_ELEM(NOTE_, SECONDS),
+ PK_NAME_ELEM(NOTE_, MSECONDS),
+ PK_NAME_ELEM(NOTE_, USECONDS),
+ PK_NAME_ELEM(NOTE_, NSECONDS),
+ PK_NAME_ELEM(NOTE_, ABSTIME),
+ PK_FLAG_LAST_ELEM(),
+};
+
+#define FILT_ELEM(name) [-EVFILT_##name] = "EVFILT_"#name
+static const struct pk_elem *const 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, true));
+}
+
+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,
+ bool verbose)
+{
+ struct kinfo_knote *kni, *knis;
+ char *flags, *fflags, *status;
+ unsigned int count, i, j;
+ 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, false);
+ fflags = procstat_kqueue_fflags(kni->knt_event.filter,
+ kni->knt_event.fflags);
+ status = procstat_kqueue_flags(kn_status_names,
+ kni->knt_status, false);
+ 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);
+ if (verbose) {
+ for (j = 0; j < nitems(kni->knt_event.ext); j++) {
+ xo_emit("{:ext%u/%#10jx} ", j,
+ (uintmax_t)kni->knt_event.ext[j]);
+ }
+ }
+ 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;
+ bool verbose;
+
+ verbose = (procstat_opts & PS_OPT_VERBOSE) != 0;
+ if ((procstat_opts & PS_OPT_NOHEADER) == 0) {
+ if (verbose) {
+ 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");
+ } else {
+ xo_emit("{T:/%7s %10s %8s %10s %10s %10s %10s %10s "
+ "%10s}\n",
+ "PID", "KQFD", "FILTER", "IDENT", "FLAGS", "FFLAGS",
+ "DATA", "UDATA", "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, verbose);
+ xo_close_list(kq);
+ }
+ xo_close_list(kqs);
+ procstat_freefiles(procstat, fl);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Feb 11, 12:57 PM (12 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28651664
Default Alt Text
D49163.id152062.diff (29 KB)
Attached To
Mode
D49163: procstat kqueues: query and display events registered in the process kqueues
Attached
Detach File
Event Timeline
Log In to Comment