[newlib-cygwin] Cygwin: proc: Cache system process information

Takashi Yano tyan0@sourceware.org
Mon Sep 7 11:47:30 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=dae171e433cd381e9b3ac48c1d2716b8168c9241

commit dae171e433cd381e9b3ac48c1d2716b8168c9241
Author: Takashi Yano <takashi.yano@nifty.ne.jp>
Date:   Fri Sep 4 12:40:02 2026 +0900

    Cygwin: proc: Cache system process information
    
    If a process reads /proc/<pid>/stat for multiple PIDs, current code
    every time calls NtQuerySystemInformation(SystemProcessInformation).
    In addition, the buffer size is estimated by calling that function
    with increasing buffer size. This takes 15 - 20 msec. This looks
    short time, however it is not negligible in some situation. If the
    number of processes is 100, reading /proc/<pid>/stat takes 1.5 - 2.0
    sec. Due to this behaviour, process pane of the btop is very heavy.
    
    With this patch, system process information is cached per process
    for a short time (20 msec) to improve efficiency. The buffer is
    allocated first time when the corresponding /proc file system is
    read, and held until process exits. If the buffer size needed by
    NtQuerySystemInformation() is increased, the buffer will be re-
    allocated, however never freed. The buffer pointer and the buffer
    size are stored in the static area, so that the number of the
    function call is reduced much. As a result, the process pane of
    btop becomes significantly light. It takes only ~15 msec for 100
    processes.
    
    Fixes: 9ba913a56dd6 ("* fhandler_process.cc (process_listing): Add 'stat' and 'statm'.")
    Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
    Reviewed-by: Mark Geisert <mark@maxrnd.com>

Diff:
---
 winsup/cygwin/fhandler/process.cc | 22 +++++++++++++++++-----
 1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/winsup/cygwin/fhandler/process.cc b/winsup/cygwin/fhandler/process.cc
index 537a4b370..404668661 100644
--- a/winsup/cygwin/fhandler/process.cc
+++ b/winsup/cygwin/fhandler/process.cc
@@ -1524,14 +1524,24 @@ get_process_state (DWORD dwProcessId, DWORD *num_threads)
 {
   /* This isn't really heavy magic - just go through the processes' threads
      one by one and return a value accordingly.  Errors are silently ignored. */
+  const ULONGLONG cache_time = 20;
+  static NO_COPY muto cache_guard;
   NTSTATUS status;
-  PSYSTEM_PROCESS_INFORMATION p, sp;
-  ULONG n = 0x4000;
+  static PSYSTEM_PROCESS_INFORMATION p = NULL;
+  static ULONGLONG t0 = 0;
+  PSYSTEM_PROCESS_INFORMATION sp;
+  static ULONG n = 0x4000;
   int state =' ';
 
-  p = (PSYSTEM_PROCESS_INFORMATION) malloc (n);
+  cache_guard.init ("get_process_state")->acquire ();
+
+  if (GetTickCount64 () - t0 < cache_time && p)
+    goto reuse_query;
+
+  if (!p)
+    p = (PSYSTEM_PROCESS_INFORMATION) malloc (n);
   if (!p)
-    return state;
+    goto out;
   while (true)
     {
       status = NtQuerySystemInformation (SystemProcessInformation,
@@ -1550,6 +1560,8 @@ get_process_state (DWORD dwProcessId, DWORD *num_threads)
 		    status, RtlNtStatusToDosError (status));
       goto out;
     }
+  t0 = GetTickCount64 ();
+reuse_query:
   state = 'Z';
   sp = p;
   for (;;)
@@ -1579,7 +1591,7 @@ get_process_state (DWORD dwProcessId, DWORD *num_threads)
       sp = (PSYSTEM_PROCESS_INFORMATION) ((char *) sp + sp->NextEntryOffset);
     }
 out:
-  free (p);
+  cache_guard.release ();
   return state;
 }


More information about the Cygwin-cvs mailing list