Skip to content

Commit

Permalink
proc: use pidfd_open(..., PIDFD_THREAD) if available
Browse files Browse the repository at this point in the history
With luck this approach might possibly perhaps go upstream!

We still fall back to waitfd if using PIDFD_THREAD doesn't work.
Complicated somewhat by having to use SYS_syscall() if a glibc too old
to support pidfd_open() isn't available (i.e. all released ones: it'll
be in 2.36), and by the likelihood that PIDFD_THREAD isn't in the
header even if the header is present, but otherwise fairly trivial.

Signed-off-by: Nick Alcock <nick.alcock@oracle.com>
  • Loading branch information
nickalcock committed Dec 14, 2022
1 parent 7c655ca commit 2120a70
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 12 deletions.
1 change: 1 addition & 0 deletions Makeconfig
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,4 @@ $(eval $(call check-symbol-rule,LIBFUSE3,fuse_session_receive_buf,fuse3))
endif
$(eval $(call check-header-rule,FUSE_NUMA,fuse_set_numa,fuse/fuse_lowlevel))
$(eval $(call check-header-symbol-rule,CLOSE_RANGE,close_range(3,~0U,0),c,unistd))
$(eval $(call check-header-rule,SYS_PIDFD_H,pidfd_open,sys/pidfd))
2 changes: 2 additions & 0 deletions include/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ unsigned long linux_version_code(void);
#define elf_getshdrnum elf_getshnum
#endif

int pid_fd(pid_t pid);

#ifndef HAVE_WAITFD
int waitfd(int which, pid_t upid, int options, int flags);
#endif
Expand Down
16 changes: 8 additions & 8 deletions libdtrace/dt_proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@
* (proxy_call()->dt_proc_loop(), wwith a special case for cleanup).
*/

#include <sys/wait.h>
#include <sys/eventfd.h>
#include <string.h>
#include <signal.h>
Expand Down Expand Up @@ -937,11 +936,11 @@ dt_proc_control(void *arg)
Pset_ptrace_wrapper(dpr->dpr_proc, proxy_ptrace);

/*
* Make a waitfd to this process, and set up polling structures
* appropriately. WEXITED | WSTOPPED is what Pwait() waits for.
* Make a pidfd or (failing that) a pidfd to this process, and set up
* polling structures appropriately.
*/
if ((dpr->dpr_fd = waitfd(P_PID, dpr->dpr_pid, WEXITED | WSTOPPED, 0)) < 0) {
dt_proc_error(dtp, dpr, "failed to get waitfd() for pid %li: %s\n",
if ((dpr->dpr_fd = pid_fd(dpr->dpr_pid)) < 0) {
dt_proc_error(dtp, dpr, "failed to get pidfd or waitfd for pid %li: %s\n",
(long)dpr->dpr_pid, strerror(errno));
/*
* Demote this to a mandatorily noninvasive grab: if we
Expand All @@ -950,7 +949,8 @@ dt_proc_control(void *arg)
* we can do but hope.
*
* The dt_consume_proc_exits() function, called by
* dtrace_consume(), checks for termination of such processes * (since nothing else will).
* dtrace_consume(), checks for termination of such processes
* (since nothing else will).
*/
Prelease(dpr->dpr_proc, PS_RELEASE_NORMAL);
if ((dpr->dpr_proc = Pgrab(dpr->dpr_pid, 2, 0,
Expand Down Expand Up @@ -1056,7 +1056,7 @@ dt_proc_loop(dt_proc_t *dpr, int awaiting_continue)

/*
* We always want to listen on the proxy pipe; we only want to listen on
* the process's waitfd pipe sometimes.
* the process's pidfd pipe sometimes.
*/

pfd[0].events = POLLIN;
Expand Down Expand Up @@ -1244,7 +1244,7 @@ dt_proc_loop(dt_proc_t *dpr, int awaiting_continue)

/*
* The process needs attention. Pwait() for it (which will make
* the waitfd transition back to empty).
* the pidfd transition back to empty).
*/
if (pfd[0].revents != 0) {
dt_dprintf("%d: Handling a process state change\n",
Expand Down
9 changes: 5 additions & 4 deletions libport/Build
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ LIBS += libport

libport_TARGET = libport
libport_DIR := $(current-dir)
ifdef HAVE_CLOSE_RANGE
libport_SOURCES = gmatch.c linux_version_code.c strlcat.c strlcpy.c p_online.c time.c daemonize.c $(ARCHINC)/waitfd.c
else
libport_SOURCES = gmatch.c linux_version_code.c strlcat.c strlcpy.c p_online.c time.c daemonize.c close_range.c $(ARCHINC)/waitfd.c
libport_SOURCES = gmatch.c linux_version_code.c strlcat.c strlcpy.c p_online.c time.c daemonize.c pid_fd.c $(ARCHINC)/waitfd.c

ifndef HAVE_CLOSE_RANGE
libport_SOURCES += close_range.c
endif

libport_LIBSOURCES := libport
libport_CPPFLAGS := -Ilibdtrace
40 changes: 40 additions & 0 deletions libport/pid_fd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/

#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <port.h> /* for waitfd, etc */
#ifdef HAVE_SYS_PIDFD_H
#include <sys/pidfd.h>
#endif

#ifndef __NR_pidfd_open
#define __NR_pidfd_open 434
#endif

#ifndef PIDFD_THREAD
/* An arbitrary value unlikely ever to be useful for pidfds. */
#define PIDFD_THREAD O_NOCTTY
#endif

int
pid_fd(pid_t pid)
{
int fd;
#ifdef HAVE_SYS_PIDFD_H
if ((fd = pidfd_open(pid, PIDFD_THREAD)) >= 0)
return fd;
#else
if ((fd = syscall(__NR_pidfd_open, pid, PIDFD_THREAD)) >= 0)
return fd;
#endif

/*
* WEXITED | WSTOPPED is what Pwait() waits for.
*/
return waitfd(P_PID, pid, WEXITED | WSTOPPED, 0);
}

0 comments on commit 2120a70

Please sign in to comment.