Public issue detail

Runaway CPU investigation for htop: file not found retry at memset_orig

htop is stuck in a likely file not found retry loop: 3.41% of sampled CPU passed through memset_orig, with repeated openat x5360, close x4956, read x2441.

highpackage: htopsource: htopscore: 106reports: 1

Last seen: 2026-05-01 21:25 UTC. Public JSON: /v1/issues/019dc185-1f9e-7802-a1ce-09bced65c64b

Technical snapshot

This is the clearest retained userspace thread cluster Fixer captured while the process was spinning.

Representative thread backtrace

  • Why Fixer classified it this way: The trace keeps retrying file lookups that fail with ENOENT, which suggests a missing-file retry loop.
  • Wait site: poll_schedule_timeout.constprop.0
  • Hot path: memset_orig (3.41% sampled CPU)
  • Repeated loop: openat -> close -> openat
  • Top syscalls: openat x5360, close x4956, read x2441, fcntl x2224
  • Package: htop 3.5.0-1
  • Kernel: 6.17.10+deb14-amd64
  • Distribution: debian

Possible duplicates

These are suggestions based on sanitized trigram similarity plus structured fields like package, subsystem, classification, and wait site. They are not auto-merged.

sshd-session is stuck in a likely unclassified userspace loop: 18.73% of sampled CPU passed through memset_orig, with repeated thread backtraces show 1 thread(s) around 0x00007f4c71e9a7d2 in ?? () from target:<path>.

highpackage: openssh-serversource: opensshscore: 106reports: 2patch attempt readysimilarity: 50%

Why this looks related: same subsystem, same wait site

Last seen: 2026-05-19 04:12 UTC. Public page: /issues/019dfb88-84b0-7961-b77d-94d71b584731. Public JSON: /v1/issues/019dfb88-84b0-7961-b77d-94d71b584731

Worker outcome summary

This issue has 1 recorded worker attempt. Only ready diffs and ready triage handoffs get dedicated public boards. Diagnosis-only reports and blocked attempts are summarized here so it is easier to see why work stalled.

1 failed patch attempts

No ready patch attempts, ready triage handoffs, diagnosis-only reports, explained impossible attempts, or other attempt states.

Most common blockers

  • execution (1 attempt)

Published attempts

failed patch attempt

patch

htop likely remains stuck in a file not found retry loop. The diagnosis was captured, but the patch proposal did not complete cleanly.

state: failedcreated: 2026-04-01 21:40 UTCvalidation: failed

Why it stopped

execution

Failure details

  • Failure kind: execution
  • Exit status: 1
  • Error: closedir(dir); return true; 2026-04-01T21:40:33.160399Z ERROR codex_core::compact_remote: remote compaction failed turn_id=019d4afa-c190-7c50-8e83-e43a20d6bdef last_api_response_total_tokens=114764 all_history_items_model_visible_bytes=392823 estimated_tokens_of_items_added_since_last_successful_api_response=3502 estimated_bytes_of_items_added_since_last_successful_api_response=14005 model_context_window_tokens=Some(121600) failing_compaction_request_model_visible_bytes=407229 compact_error=We're currently experiencing high demand, which may cause temporary errors. ERROR: Error running remote compact task: We're currently experiencing high demand, which may cause temporary errors. ERROR: Error running remote compact task: We're currently experiencing high demand, which may cause temporary errors. tokens used 262 453

stderr excerpt

closedir(dir);
    return true;

2026-04-01T21:40:33.160399Z ERROR codex_core::compact_remote: remote compaction failed turn_id=019d4afa-c190-7c50-8e83-e43a20d6bdef last_api_response_total_tokens=114764 all_history_items_model_visible_bytes=392823 estimated_tokens_of_items_added_since_last_successful_api_response=3502 estimated_bytes_of_items_added_since_last_successful_api_response=14005 model_context_window_tokens=Some(121600) failing_compaction_request_model_visible_bytes=407229 compact_error=We're currently experiencing high demand, which may cause temporary errors.
ERROR: Error running remote compact task: We're currently experiencing high demand, which may cause temporary errors.
ERROR: Error running remote compact task: We're currently experiencing high demand, which may cause temporary errors.
tokens used
262 453

Collected context

  • Subsystem: runaway-process
  • Diagnosis family: file-not-found-retry
  • Hot path: memset_orig
  • Source package: htop
  • Workspace source: debian-source
  • Workspace acquisition: Fetched Debian source package via apt-get source.
  • Homepage: https://htop.dev/
  • Implicated packages: libncursesw6, linux-image-6.17.10+deb14-amd64

The trace keeps retrying file lookups that fail with ENOENT, which suggests a missing-file retry loop.

Published session

Prompt

## Plan Pass

You are planning a fixer patch before any edits happen.

Read the evidence bundle at `./evidence.json`. The prepared workspace is `./workspace` and it was acquired via `debian-source`. The original pre-edit snapshot is available at `./source` if you need to inspect it. Inspect the relevant code, but do not edit files in this pass.

Return a short markdown plan with these exact sections:

## Problem
## Proposed Subject
## Patch Plan
## Risks
## Validation

The plan must explain how the proposed code change addresses the observed issue evidence, call out any prior Fixer patch that should be improved or replaced, and reject awkward control flow such as avoidable `goto` if there is a cleaner bounded alternative.

## Patch Pass

You are working on a bounded fixer proposal.

Read the evidence bundle at `./evidence.json`. The prepared workspace is `./workspace` and it was acquired via `debian-source`. Produce the smallest reasonable patch for the target repository, keep the change upstreamable, prefer the clearest control flow available, and do not keep avoidable `goto` when a simpler structure would read better. The final explanation must connect the observed issue evidence to the actual code change, not just paraphrase the diff.

Start by explaining the likely root cause from the collected perf, strace, and /proc evidence. If you cannot land a safe patch, leave a diagnosis that is strong enough for an upstream bug report. 

Keep the change narrowly scoped and summarize validation clearly.

In every authoring pass, your final response must start with `Subject: <single-line git commit subject>` and then include these markdown sections exactly:

## Commit Message
A short upstream-friendly explanation of what changed and why.

## Issue Connection
Explain how the code change addresses the observed issue evidence instead of merely paraphrasing the diff.

## Git Add Paths
List the repo-relative paths that belong in the final patch, one per line. Include intentionally new files, and do not list generated build artifacts.

## Validation
List the checks you ran, or say clearly that you could not run them.

Before editing, read the plan at `./plan-output.txt` and follow it unless the code proves part of it wrong. If you change course, say so explicitly in the final write-up instead of silently drifting from the plan.

Response

## Plan Pass

## Problem
Evidence `file-not-found-retry` shows htop’s `/proc` walk repeatedly issues `openat` calls (10k+) in tight succession, which aligns with stale process/task entries disappearing between discovery and file access (race window in `/proc`). The current flow appears to retry or continue scanning in a way that keeps re-touching missing paths (`ENOENT`) instead of treating them as a definitive skip condition for that iteration, increasing CPU work and noisy kernel lookup churn.

## Proposed Subject
Avoid unbounded `/proc` file re-attempt loops in the Linux process table walk by treating missing `/proc` paths as terminal for the current process/task read path, with bounded, structured handling for stale entries and cleanup.

## Patch Plan
1. Target file: `linux/LinuxProcessTable.c` (primarily the process-tree/proc-entry scanning path).
   - Focus on `LinuxProcessTable_recurseProcTree` and the immediate `/proc/<pid>/...` read sequence where `openat` is retried/continued.
2. Introduce explicit per-attempt handling for `openat` failures:
   - If `openat` returns `ENOENT`, mark the current item as stale and skip further reads for that process/task without re-trying the same path in-place.
   - Keep retries only where they are semantically useful (e.g., signal `EINTR`/temporary interruptions), not for vanished paths.
3. Keep process-table state consistent by centralizing the fail-fast path:
   - Skip stale entries cleanly via a `bool shouldSkipEntry` (or equivalent) instead of re-entering a read path.
4. Replace avoidable `goto`-based control flow in the touched block with bounded structured control flow:
   - Use explicit branch flow (`if` + `continue`/`return`) and small helper return codes (`Ok/Skip/Fatal`) to make retry/skip decisions local and clear.
5. If this patch is overlaid on any previous Fixer attempt that adds broad retry wrappers around `openat`/proc reads, replace that change with the narrower bounded strategy above (do not broaden retries globally).

## Risks
1. Higher skip rate in rare races:
   - Some short-lived processes may now be dropped sooner from the display cycle. This is preferred for correctness under proc races, but behavior changes from “best effort + noise” to “stable skip”.
2. Potential loss of visibility into transient parse errors:
   - If we over-match `ENOENT` handling, unrelated failures may be misclassified. We should keep errno checks explicit and narrow.
3. Refactor risk from `goto` removal:
   - Slightly more complex branching may reduce readability if not tightly scoped; keep scope limited to one helper or one loop region.

## Validation
1. Static validation:
   - Confirm `linux/LinuxProcessTable.c` no longer retries the same `/proc` path on `ENOENT` within a single loop iteration.
2. Dynamic validation (next step after patch approval):
   - Compare `strace`/syscall counts around `openat` and `getdents64` in steady-state runtime to verify lower `openat` churn.
   - Confirm no functional regressions in process disappearance/reappearance scenarios (`ps` churn, short-lived processes).

## Patch Pass



## Workflow Note

    closedir(dir);
    return true;

2026-04-01T21:40:33.160399Z ERROR codex_core::compact_remote: remote compaction failed turn_id=019d4afa-c190-7c50-8e83-e43a20d6bdef last_api_response_total_tokens=114764 all_history_items_model_visible_bytes=392823 estimated_tokens_of_items_added_since_last_successful_api_response=3502 estimated_bytes_of_items_added_since_last_successful_api_response=14005 model_context_window_tokens=Some(121600) failing_compaction_request_model_visible_bytes=407229 compact_error=We're currently experiencing high demand, which may cause temporary errors.
ERROR: Error running remote compact task: We're currently experiencing high demand, which may cause temporary errors.
ERROR: Error running remote compact task: We're currently experiencing high demand, which may cause temporary errors.
tokens used
262 453

Diff

diff --git a/linux/LinuxProcessTable.c b/linux/LinuxProcessTable.c
index 3d8dc96..c34fa56 100644
--- a/linux/LinuxProcessTable.c
+++ b/linux/LinuxProcessTable.c
@@ -14,6 +14,7 @@ in the source distribution for its full text.
 #include <dirent.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <errno.h>
 #include <limits.h>
 #include <math.h>
 #include <stdbool.h>
@@ -1600,6 +1601,21 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar
       proc->isUserlandThread = Process_getPid(proc) != Process_getThreadGroup(proc);
       assert(proc->isUserlandThread == (mainTask != NULL));
 
+#ifdef HAVE_OPENAT
+      struct stat procStat;
+      const bool processDisappeared = fstat(procFd, &procStat) == -1 && errno == ENOENT;
+#else
+      const bool processDisappeared = false;
+#endif
+      if (processDisappeared) {
+         if (!preExisting) {
+            assert(ProcessTable_findProcess(pt, Process_getPid(proc)) == NULL);
+            Process_delete((Object*)proc);
+         }
+         Compat_openatArgClose(procFd);
+         continue;
+      }
+
       LinuxProcessTable_recurseProcTree(this, procFd, lhost, "task", lp);
 
       /*
@@ -1632,11 +1648,12 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar
       }
 
       const bool scanMainThread = !hideUserlandThreads && !Process_isKernelThread(proc) && !mainTask;
+      bool shouldSkipProcess = false;
 
-      if (!LinuxProcessTable_readStatmFile(lp, procFd, lhost, mainTask))
-         goto errorReadingProcess;
+      if (!shouldSkipProcess && !LinuxProcessTable_readStatmFile(lp, procFd, lhost, mainTask))
+         shouldSkipProcess = true;
 
-      {
+      if (!shouldSkipProcess) {
          bool prev = proc->usesDeletedLib;
 
          if (!proc->isKernelThread && !proc->isUserlandThread &&
@@ -1662,34 +1679,40 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar
       }
 
       char statCommand[MAX_NAME + 1];
-      unsigned long long int lasttimes = (lp->utime + lp->stime);
-      unsigned long int last_tty_nr = proc->tty_nr;
-      if (!LinuxProcessTable_readStatFile(lp, procFd, lhost, scanMainThread, statCommand, sizeof(statCommand)))
-         goto errorReadingProcess;
+      unsigned long long int lasttimes;
+      unsigned long int last_tty_nr;
+      if (!shouldSkipProcess) {
+         lasttimes = (lp->utime + lp->stime);
+         last_tty_nr = proc->tty_nr;
+         if (!LinuxProcessTable_readStatFile(lp, procFd, lhost, scanMainThread, statCommand, sizeof(statCommand)))
+            shouldSkipProcess = true;
+      }
+
+      if (!shouldSkipProcess) {
+         if (lp->flags & PF_KTHREAD) {
+            proc->isKernelThread = true;
+         }
 
-      if (lp->flags & PF_KTHREAD) {
-         proc->isKernelThread = true;
-      }
+         if (last_tty_nr != proc->tty_nr && this->ttyDrivers) {
+            free(proc->tty_name);
+            proc->tty_name = LinuxProcessTable_updateTtyDevice(this->ttyDrivers, proc->tty_nr);
+         }
 
-      if (last_tty_nr != proc->tty_nr && this->ttyDrivers) {
-         free(proc->tty_name);
-         proc->tty_name = LinuxProcessTable_updateTtyDevice(this->ttyDrivers, proc->tty_nr);
-      }
+         proc->percent_cpu = NAN;
+         /* lhost->period might be 0 after system sleep */
+         if (lhost->period > 0.0) {
+            float percent_cpu = saturatingSub(lp->utime + lp->stime, lasttimes) / lhost->period * 100.0;
+            proc->percent_cpu = MINIMUM(percent_cpu, host->activeCPUs * 100.0F);
+         }
+         proc->percent_mem = proc->m_resident / (double)(host->totalMem) * 100.0;
+         Process_updateCPUFieldWidths(proc->percent_cpu);
 
-      proc->percent_cpu = NAN;
-      /* lhost->period might be 0 after system sleep */
-      if (lhost->period > 0.0) {
-         float percent_cpu = saturatingSub(lp->utime + lp->stime, lasttimes) / lhost->period * 100.0;
-         proc->percent_cpu = MINIMUM(percent_cpu, host->activeCPUs * 100.0F);
+         if (!LinuxProcessTable_updateUser(host, proc, procFd, mainTask))
+            shouldSkipProcess = true;
       }
-      proc->percent_mem = proc->m_resident / (double)(host->totalMem) * 100.0;
-      Process_updateCPUFieldWidths(proc->percent_cpu);
-
-      if (!LinuxProcessTable_updateUser(host, proc, procFd, mainTask))
-         goto errorReadingProcess;
 
       /* Check if the process is inside a different PID namespace. */
-      if (proc->isRunningInContainer == TRI_INITIAL && rootPidNs != (ino_t)-1) {
+      if (!shouldSkipProcess && proc->isRunningInContainer == TRI_INITIAL && rootPidNs != (ino_t)-1) {
          struct stat sb;
 #if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT)
          int res = fstatat(procFd, "ns/pid", &sb, 0);
@@ -1710,11 +1733,14 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar
 #endif
       ) {
          proc->isRunningInContainer = TRI_OFF;
-         if (!LinuxProcessTable_readStatusFile(proc, procFd))
-            goto errorReadingProcess;
+         if (!shouldSkipProcess) {
+            if (!LinuxProcessTable_readStatusFile(proc, procFd))
+               shouldSkipProcess = true;
+         }
       }
 
-      if (!preExisting) {
+      if (!shouldSkipProcess) {
+         if (!preExisting) {
 
          #ifdef HAVE_OPENVZ
          if (ss->flags & PROCESS_FLAG_LINUX_OPENVZ) {
@@ -1734,7 +1760,7 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar
          Process_fillStarttimeBuffer(proc);
 
          ProcessTable_add(pt, proc);
-      } else {
+         } else {
          if (settings->updateProcessNames && proc->state != ZOMBIE) {
             if (proc->isKernelThread) {
                Process_updateCmdline(proc, NULL, 0, 0);
@@ -1745,141 +1771,122 @@ static bool LinuxProcessTable_recurseProcTree(LinuxProcessTable* this, openat_ar
                LinuxProcessList_readComm(proc, procFd);
             }
          }
+         }
       }
 
-      /*
-       * Section gathering non-critical information that is independent from
-       * each other.
-       */
+      if (!shouldSkipProcess) {
+         /*
+          * Section gathering non-critical information that is independent from
+          * each other.
+          */
 
-      /* Gather permitted capabilities (thread-specific data) for non-root process. */
-      if (proc->st_uid != 0 && proc->elevated_priv != TRI_OFF) {
-         struct __user_cap_header_struct header = { .version = _LINUX_CAPABILITY_VERSION_3, .pid = Process_getPid(proc) };
-         struct __user_cap_data_struct data;
+         /* Gather permitted capabilities (thread-specific data) for non-root process. */
+         if (proc->st_uid != 0 && proc->elevated_priv != TRI_OFF) {
+            struct __user_cap_header_struct header = { .version = _LINUX_CAPABILITY_VERSION_3, .pid = Process_getPid(proc) };
+            struct __user_cap_data_struct data;
 
-         long res = syscall(SYS_capget, &header, &data);
-         if (res == 0) {
-            proc->elevated_priv = (data.permitted != 0) ? TRI_ON : TRI_OFF;
-         } else {
-            proc->elevated_priv = TRI_OFF;
+            long res = syscall(SYS_capget, &header, &data);
+            if (res == 0) {
+               proc->elevated_priv = (data.permitted != 0) ? TRI_ON : TRI_OFF;
+            } else {
+               proc->elevated_priv = TRI_OFF;
+            }
          }
-      }
 
-      if (ss->flags & PROCESS_FLAG_LINUX_CGROUP)
-         LinuxProcessTable_readCGroupFile(lp, procFd);
+         if (ss->flags & PROCESS_FLAG_LINUX_CGROUP)
+            LinuxProcessTable_readCGroupFile(lp, procFd);
 
-      if ((ss->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)) {
-         if (!mainTask) {
-            // Read smaps file of each process only every second pass to improve performance
-            static int smaps_flag = 0;
-            if ((pid & 1) == smaps_flag) {
-               LinuxProcessTable_readSmapsFile(lp, procFd, this->haveSmapsRollup);
-            }
-            if (pid == 1) {
-               smaps_flag = !smaps_flag;
+         if ((ss->flags & PROCESS_FLAG_LINUX_SMAPS) && !Process_isKernelThread(proc)) {
+            if (!mainTask) {
+               // Read smaps file of each process only every second pass to improve performance
+               static int smaps_flag = 0;
+               if ((pid & 1) == smaps_flag) {
+                  LinuxProcessTable_readSmapsFile(lp, procFd, this->haveSmapsRollup);
+               }
+               if (pid == 1) {
+                  smaps_flag = !smaps_flag;
+               }
+            } else {
+               lp->m_pss   = mainTask->m_pss;
+               lp->m_swap  = mainTask->m_swap;
+               lp->m_psswp = mainTask->m_psswp;
             }
-         } else {
-            lp->m_pss   = mainTask->m_pss;
-            lp->m_swap  = mainTask->m_swap;
-            lp->m_psswp = mainTask->m_psswp;
          }
-      }
-
-      if (ss->flags & PROCESS_FLAG_IO) {
-         LinuxProcessTable_readIoFile(lp, procFd, scanMainThread);
-      }
-
-      #ifdef HAVE_DELAYACCT
-      if (ss->flags & PROCESS_FLAG_LINUX_DELAYACCT) {
-         LibNl_readDelayAcctData(this, lp);
-      }
-      #endif
-
-      if (ss->flags & PROCESS_FLAG_LINUX_OOM) {
-         LinuxProcessTable_readOomData(lp, procFd, mainTask);
-      }
-
-      if (ss->flags & PROCESS_FLAG_LINUX_IOPRIO) {
-         LinuxProcess_updateIOPriority(proc);
-      }
 
-      if (ss->flags & PROCESS_FLAG_LINUX_SECATTR) {
-         LinuxProcessTable_readSecattrData(lp, procFd, mainTask);
-      }
-
-      if (ss->flags & PROCESS_FLAG_CWD) {
-         LinuxProcessTable_readCwd(lp, procFd, mainTask);
-      }
-
-      if ((ss->flags & PROCESS_FLAG_LINUX_AUTOGROUP) && this->haveAutogroup) {
-         LinuxProcessTable_readAutogroup(lp, procFd, mainTask);
-      }
+         if (ss->flags & PROCESS_FLAG_IO) {
+            LinuxProcessTable_readIoFile(lp, procFd, scanMainThread);
+         }
 
-      #ifdef SCHEDULER_SUPPORT
-      if (ss->flags & PROCESS_FLAG_SCHEDPOL) {
-         Scheduling_readProcessPolicy(proc);
-      }
-      #endif
+         #ifdef HAVE_DELAYACCT
+         if (ss->flags & PROCESS_FLAG_LINUX_DELAYACCT) {
+            LibNl_readDelayAcctData(this, lp);
+         }
+         #endif
 
-      if (ss->flags & PROCESS_FLAG_LINUX_GPU || GPUMeter_active()) {
-         if (mainTask) {
-            lp->gpu_time = mainTask->gpu_time;
-         } else {
-            GPU_readProcessData(this, lp, procFd);
+         if (ss->flags & PROCESS_FLAG_LINUX_OOM) {
+            LinuxProcessTable_readOomData(lp, procFd, mainTask);
          }
-      }
 
-      /*
-       * Final section after all data has been gathered
-       */
+         if (ss->flags & PROCESS_FLAG_LINUX_IOPRIO) {
+            LinuxProcess_updateIOPriority(proc);
+         }
 
-      if (!proc->cmdline && statCommand[0] &&
-          (proc->state == ZOMBIE || Process_isKernelThread(proc) || settings->showThreadNames)) {
-         Process_updateCmdline(proc, statCommand, 0, strlen(statCommand));
-      }
+         if (ss->flags & PROCESS_FLAG_LINUX_SECATTR) {
+            LinuxProcessTable_readSecattrData(lp, procFd, mainTask);
+         }
 
-      proc->super.updated = true;
-      Compat_openatArgClose(procFd);
+         if (ss->flags & PROCESS_FLAG_CWD) {
+            LinuxProcessTable_readCwd(lp, procFd, mainTask);
+         }
 
-      if (hideRunningInContainer && proc->isRunningInContainer == TRI_ON) {
-         proc->super.show = false;
-         continue;
-      }
+         if ((ss->flags & PROCESS_FLAG_LINUX_AUTOGROUP) && this->haveAutogroup) {
+            LinuxProcessTable_readAutogroup(lp, procFd, mainTask);
+         }
 
-      if (Process_isKernelThread(proc)) {
-         pt->kernelThreads++;
-      } else if (Process_isUserlandThread(proc)) {
-         pt->userlandThreads++;
-      }
+         #ifdef SCHEDULER_SUPPORT
+         if (ss->flags & PROCESS_FLAG_SCHEDPOL) {
+            Scheduling_readProcessPolicy(proc);
+         }
+         #endif
 
-      /* Set at the end when we know if a new entry is a thread */
-      proc->super.show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
+         if (ss->flags & PROCESS_FLAG_LINUX_GPU || GPUMeter_active()) {
+            if (mainTask) {
+               lp->gpu_time = mainTask->gpu_time;
+            } else {
+               GPU_readProcessData(this, lp, procFd);
+            }
+         }
 
-      pt->totalTasks++;
-      /* runningTasks is set in Machine_scanCPUTime() from /proc/stat */
-      continue;
+         /*
+          * Final section after all data has been gathered
+          */
 
-      // Exception handler.
+         if (!proc->cmdline && statCommand[0] &&
+             (proc->state == ZOMBIE || Process_isKernelThread(proc) || settings->showThreadNames)) {
+            Process_updateCmdline(proc, statCommand, 0, strlen(statCommand));
+         }
+         proc->super.updated = true;
 
-errorReadingProcess:
-      {
-#ifdef HAVE_OPENAT
-         if (procFd >= 0)
-            close(procFd);
-#endif
+         if (hideRunningInContainer && proc->isRunningInContainer == TRI_ON) {
+            proc->super.show = false;
+         } else if (Process_isKernelThread(proc)) {
+            pt->kernelThreads++;
+         } else if (Process_isUserlandThread(proc)) {
+            pt->userlandThreads++;
+         }
 
-         if (preExisting) {
-            /*
-             * The only real reason for coming here (apart from Linux violating the /proc API)
-             * would be the process going away with its /proc files disappearing (!HAVE_OPENAT).
-             * However, we want to keep in the process list for now for the "highlight dying" mode.
-             */
-         } else {
+         /* Set at the end when we know if a new entry is a thread */
+         proc->super.show = ! ((hideKernelThreads && Process_isKernelThread(proc)) || (hideUserlandThreads && Process_isUserlandThread(proc)));
+         pt->totalTasks++;
+      } else {
+         if (!preExisting) {
             /* A really short-lived process that we don't have full info about */
             assert(ProcessTable_findProcess(pt, Process_getPid(proc)) == NULL);
             Process_delete((Object*)proc);
          }
       }
+      Compat_openatArgClose(procFd);
+      continue;
    }
    closedir(dir);
    return true;