Skip to content

Commit 440c845

Browse files
committed
fix(ui): enumerate codebase-memory-mcp processes on Windows
Windows handle_processes previously returned an empty processes array because it only queried the current process via GetProcessMemoryInfo/ GetProcessTimes. POSIX uses popen("ps") to enumerate all instances. Add process enumeration via CreateToolhelp32Snapshot + Process32First/ Process32Next to find all codebase-memory-mcp.exe processes, query per- process CPU/memory/elapsed time via OpenProcess + GetProcessTimes + GetProcessMemoryInfo, and return them in the JSON response. Closes #950 Signed-off-by: 周凯 <851708184@qq.com>
1 parent b637e33 commit 440c845

1 file changed

Lines changed: 76 additions & 2 deletions

File tree

‎src/ui/http_server.c‎

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include <windows.h>
5151
#include <process.h>
5252
#include <psapi.h> /* GetProcessMemoryInfo */
53+
#include <tlhelp32.h> /* CreateToolhelp32Snapshot, Process32First/Next */
5354
#else
5455
#include <sys/stat.h>
5556
#include <unistd.h>
@@ -501,7 +502,7 @@ static void handle_processes(cbm_http_conn_t *c) {
501502
int pos = 0;
502503

503504
#ifdef _WIN32
504-
/* Windows: GetProcessMemoryInfo + GetProcessTimes */
505+
/* Windows: GetProcessMemoryInfo + GetProcessTimes for the current process */
505506
PROCESS_MEMORY_COUNTERS pmc;
506507
FILETIME ft_create, ft_exit, ft_kernel, ft_user;
507508
double user_s = 0, sys_s = 0;
@@ -519,8 +520,81 @@ static void handle_processes(cbm_http_conn_t *c) {
519520
}
520521
http_appendf(buf, sizeof(buf), &pos,
521522
"{\"self_pid\":%d,\"self_rss_mb\":%.1f,"
522-
"\"self_user_cpu_s\":%.1f,\"self_sys_cpu_s\":%.1f,\"processes\":[]}",
523+
"\"self_user_cpu_s\":%.1f,\"self_sys_cpu_s\":%.1f,\"processes\":[",
523524
(int)_getpid(), (double)rss_bytes / (1024.0 * 1024.0), user_s, sys_s);
525+
526+
/* Enumerate all codebase-memory-mcp.exe processes via toolhelp snapshot */
527+
int proc_count = 0;
528+
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
529+
if (hSnap != INVALID_HANDLE_VALUE) {
530+
PROCESSENTRY32 pe;
531+
pe.dwSize = sizeof(pe);
532+
for (BOOL ok = Process32First(hSnap, &pe); ok; ok = Process32Next(hSnap, &pe)) {
533+
if (_stricmp(pe.szExeFile, "codebase-memory-mcp.exe") == 0) {
534+
HANDLE hProc = OpenProcess(
535+
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
536+
FALSE, pe.th32ProcessID);
537+
if (hProc) {
538+
PROCESS_MEMORY_COUNTERS ppmc;
539+
FILETIME ftc, fte, ftk, ftu;
540+
double cpu_user = 0, cpu_sys = 0;
541+
size_t proc_rss = 0;
542+
DWORD elapsed_sec = 0;
543+
544+
if (GetProcessMemoryInfo(hProc, &ppmc, sizeof(ppmc)))
545+
proc_rss = ppmc.WorkingSetSize;
546+
547+
if (GetProcessTimes(hProc, &ftc, &fte, &ftk, &ftu)) {
548+
ULARGE_INTEGER pu, pk;
549+
pu.LowPart = ftu.dwLowDateTime;
550+
pu.HighPart = ftu.dwHighDateTime;
551+
pk.LowPart = ftk.dwLowDateTime;
552+
pk.HighPart = ftk.dwHighDateTime;
553+
cpu_user = (double)pu.QuadPart / 1e7;
554+
cpu_sys = (double)pk.QuadPart / 1e7;
555+
556+
/* 进程创建以来的运行时间 */
557+
FILETIME now_ft;
558+
GetSystemTimeAsFileTime(&now_ft);
559+
ULARGE_INTEGER now_uli, start_uli;
560+
now_uli.LowPart = now_ft.dwLowDateTime;
561+
now_uli.HighPart = now_ft.dwHighDateTime;
562+
start_uli.LowPart = ftc.dwLowDateTime;
563+
start_uli.HighPart = ftc.dwHighDateTime;
564+
/* 时钟偏移保护:防止创建时间微偏未来导致 unsigned 下溢 */
565+
if (now_uli.QuadPart > start_uli.QuadPart) {
566+
ULONGLONG elapsed_100ns = now_uli.QuadPart - start_uli.QuadPart;
567+
elapsed_sec = (DWORD)(elapsed_100ns / 10000000ULL);
568+
}
569+
}
570+
571+
if (proc_count > 0)
572+
buf[pos++] = ',';
573+
http_appendf(buf, sizeof(buf), &pos,
574+
"{\"pid\":%lu,\"cpu\":%.1f,\"rss_mb\":%.1f,"
575+
"\"elapsed\":\"%lu-%02lu:%02lu:%02lu\","
576+
"\"command\":\"codebase-memory-mcp\","
577+
"\"is_self\":%s}",
578+
pe.th32ProcessID, cpu_user + cpu_sys,
579+
(double)proc_rss / (1024.0 * 1024.0),
580+
elapsed_sec / 86400,
581+
(elapsed_sec % 86400) / 3600,
582+
(elapsed_sec % 3600) / 60,
583+
elapsed_sec % 60,
584+
pe.th32ProcessID == (DWORD)_getpid()
585+
? "true" : "false");
586+
if (pos >= (int)sizeof(buf)) {
587+
pos = (int)sizeof(buf) - 1;
588+
}
589+
proc_count++;
590+
CloseHandle(hProc);
591+
}
592+
}
593+
}
594+
CloseHandle(hSnap);
595+
}
596+
597+
http_appendf(buf, sizeof(buf), &pos, "]}");
524598
#else
525599
struct rusage ru;
526600
getrusage(RUSAGE_SELF, &ru);

0 commit comments

Comments
 (0)