I encountered an issue when running runj on FreeBSD through containerd and nerdctl. The command inside the container executes successfully, but nerdctl run does not return to the shell prompt after the command completes.
While investigating the issue, I found that procReapAcquire() in containerd/reaper.go uses unix.Syscall() to invoke FreeBSD's procctl(PROC_REAP_ACQUIRE). In the current implementation, only three arguments are passed after the syscall number: P_PID, the target PID, and PROC_REAP_ACQUIRE. However, FreeBSD's procctl() interface takes four arguments: idtype, id, cmd, and data. Therefore, it appears that the fourth data argument is not being passed.
Reference: https://man.freebsd.org/cgi/man.cgi?query=procctl
In my environment, this caused the shim to fail to become a process reaper. After runj create exited, runj-entrypoint was reparented to PID 1 instead of the runj shim. As a result, when the container process exited, the shim did not receive the child's exit notification, and the shim's Wait() remained blocked. This caused nerdctl run to hang even though the command inside the container had already completed.
I changed the implementation from unix.Syscall() to unix.Syscall6() and explicitly passed 0, corresponding to NULL, as the fourth data argument. After this change, the container process was reparented to the runj shim instead of PID 1, and nerdctl run correctly returned to the shell after the container command completed.
I also verified on the same FreeBSD system that calling procctl(P_PID, 0, PROC_REAP_ACQUIRE, NULL) directly from a C program succeeds. This suggests that the issue is not caused by PROC_REAP_ACQUIRE being unsupported on FreeBSD 14.0, but rather by the raw syscall invocation in runj potentially missing the fourth argument.
Is the current use of unix.Syscall() here intentional, or could this be a bug in the FreeBSD process reaper setup? If so, I can submit a pull request changing the implementation to use unix.Syscall6() and explicitly pass the fourth argument.
Note: English is not my first language, so I used AI assistance for translation.
I encountered an issue when running runj on FreeBSD through containerd and nerdctl. The command inside the container executes successfully, but nerdctl run does not return to the shell prompt after the command completes.
While investigating the issue, I found that procReapAcquire() in containerd/reaper.go uses unix.Syscall() to invoke FreeBSD's procctl(PROC_REAP_ACQUIRE). In the current implementation, only three arguments are passed after the syscall number: P_PID, the target PID, and PROC_REAP_ACQUIRE. However, FreeBSD's procctl() interface takes four arguments: idtype, id, cmd, and data. Therefore, it appears that the fourth data argument is not being passed.
Reference: https://man.freebsd.org/cgi/man.cgi?query=procctl
In my environment, this caused the shim to fail to become a process reaper. After runj create exited, runj-entrypoint was reparented to PID 1 instead of the runj shim. As a result, when the container process exited, the shim did not receive the child's exit notification, and the shim's Wait() remained blocked. This caused nerdctl run to hang even though the command inside the container had already completed.
I changed the implementation from unix.Syscall() to unix.Syscall6() and explicitly passed 0, corresponding to NULL, as the fourth data argument. After this change, the container process was reparented to the runj shim instead of PID 1, and nerdctl run correctly returned to the shell after the container command completed.
I also verified on the same FreeBSD system that calling procctl(P_PID, 0, PROC_REAP_ACQUIRE, NULL) directly from a C program succeeds. This suggests that the issue is not caused by PROC_REAP_ACQUIRE being unsupported on FreeBSD 14.0, but rather by the raw syscall invocation in runj potentially missing the fourth argument.
Is the current use of unix.Syscall() here intentional, or could this be a bug in the FreeBSD process reaper setup? If so, I can submit a pull request changing the implementation to use unix.Syscall6() and explicitly pass the fourth argument.
Note: English is not my first language, so I used AI assistance for translation.