From 9ba913a56dd6eb5af664cb3e29fa3e9a8d7a3752 Mon Sep 17 00:00:00 2001 From: Christopher Faylor Date: Sun, 12 May 2002 01:37:48 +0000 Subject: * autoload.cc: Add dynamic load statements for 'ZwQueryInformationProcess' and 'ZwQueryVirtualMemory'. * fhandler.h: Change type of bufalloc and filesize members of fhandler_virtual from int to size_t. Change type of position member from __off32_t to __off64_t. Add new fileid member to fhandler_virtual class. Make seekdir take an __off64_t argument. Make lseek take an __off64_t argument. Add fill_filebuf method to fhandler_virtual. Add fill_filebuf method to fhandler_proc. Add fill_filebuf method to fhandler_registry. Add fill_filebuf method to fhandler_process. Add saved_pid and saved_p members to fhandler_process. * fhandler_proc.cc (proc_listing_array): Add 'loadavg', 'meminfo', and 'stat'. (proc_fhandlers array): Ditto. (fhandler_proc::open): Use fill_filebuf to flesh out the file contents. (fhandler_proc::fill_filebuf): New method. (fhandler_proc::format_proc_meminfo): Ditto. (fhandler_proc::format_proc_stat): Ditto. (fhandler_proc::format_proc_uptime): Ditto. * fhandler_process.cc (process_listing): Add 'stat' and 'statm'. (fhandler_process::fstat): Find the _pinfo structure for the process named in the filename. Return ENOENT if the process is no longer around. Set the gid and uid fields of the stat structure. (fhandler_process::open): Store pid and pointer to _pinfo structure in saved_pid and saved_p respectively. Use fill_filebuf to flesh out file contents. (fhandler_proc::fill_filebuf): New method. (format_process_stat): New function. (format_process_status): Ditto. (format_process_statm): Ditto. (get_process_state): Ditto. (get_mem_values): Ditto. * fhandler_registry.cc (fhandler_registry::seekdir): Change argument type from __off32_t to __off64_t. (fhandler_registry::fill_filebuf): New method. * fhandler_virtual.cc (fhandler_virtual::seekdir): Change argument type from __off32_t to __off64_t. (fhandler_virtual::lseek): Ditto. (fhandler_virtual::fill_filebuf): New method. (fhandler_virtual::fhandler_virtual): Initialise fileid to -1. * wincap.cc: Set flag has_process_io_counters appropriately. * wincap.h: Add flag has_process_io_counters. --- winsup/cygwin/fhandler_proc.cc | 237 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 211 insertions(+), 26 deletions(-) (limited to 'winsup/cygwin/fhandler_proc.cc') diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc index 3d4946998..60e95780d 100644 --- a/winsup/cygwin/fhandler_proc.cc +++ b/winsup/cygwin/fhandler_proc.cc @@ -14,6 +14,7 @@ details. */ #include #include #include +#include #include "cygerrno.h" #include "security.h" #include "fhandler.h" @@ -24,20 +25,27 @@ details. */ #include "cygheap.h" #include #include +#include "ntdll.h" #define _COMPILING_NEWLIB #include /* offsets in proc_listing */ -static const int PROC_REGISTRY = 2; // /proc/registry -static const int PROC_VERSION = 3; // /proc/version -static const int PROC_UPTIME = 4; // /proc/uptime +static const int PROC_LOADAVG = 2; // /proc/loadavg +static const int PROC_MEMINFO = 3; // /proc/meminfo +static const int PROC_REGISTRY = 4; // /proc/registry +static const int PROC_STAT = 5; // /proc/stat +static const int PROC_VERSION = 6; // /proc/version +static const int PROC_UPTIME = 7; // /proc/uptime /* names of objects in /proc */ static const char *proc_listing[] = { ".", "..", + "loadavg", + "meminfo", "registry", + "stat", "version", "uptime", NULL @@ -48,11 +56,14 @@ static const int PROC_LINK_COUNT = (sizeof(proc_listing) / sizeof(const char *)) /* FH_PROC in the table below means the file/directory is handles by * fhandler_proc. */ -static const DWORD proc_fhandlers[] = { +static const DWORD proc_fhandlers[PROC_LINK_COUNT] = { + FH_PROC, + FH_PROC, FH_PROC, FH_PROC, FH_REGISTRY, FH_PROC, + FH_PROC, FH_PROC }; @@ -60,6 +71,10 @@ static const DWORD proc_fhandlers[] = { const char proc[] = "/proc"; const int proc_len = sizeof (proc) - 1; +static off_t format_proc_meminfo (char *destbuf, size_t maxsize); +static off_t format_proc_stat (char *destbuf, size_t maxsize); +static off_t format_proc_uptime (char *destbuf, size_t maxsize); + /* auxillary function that returns the fhandler associated with the given path * this is where it would be nice to have pattern matching in C - polymorphism * just doesn't cut it @@ -291,44 +306,214 @@ fhandler_proc::open (path_conv *pc, int flags, mode_t mode) res = 0; goto out; } - switch (proc_file_no) + + fileid = proc_file_no; + fill_filebuf (); + + if (flags & O_APPEND) + position = filesize; + else + position = 0; + +success: + res = 1; + set_open_status (); + set_flags (flags); +out: + syscall_printf ("%d = fhandler_proc::open (%p, %d)", res, flags, mode); + return res; +} + +void +fhandler_proc::fill_filebuf () +{ + switch (fileid) { case PROC_VERSION: { + if (!filebuf) + { struct utsname uts_name; uname (&uts_name); - filesize = bufalloc = strlen (uts_name.sysname) + 1 + - strlen (uts_name.release) + 1 + strlen (uts_name.version) + 2; + bufalloc = strlen (uts_name.sysname) + 1 + strlen (uts_name.release) + + 1 + strlen (uts_name.version) + 2; filebuf = (char *) cmalloc (HEAP_BUF, bufalloc); - __small_sprintf (filebuf, "%s %s %s\n", uts_name.sysname, + filesize = __small_sprintf (filebuf, "%s %s %s\n", uts_name.sysname, uts_name.release, uts_name.version); + } break; } case PROC_UPTIME: { - /* GetTickCount() wraps after 49 days - on WinNT/2000/XP, should use - * perfomance counters but I don't know Redhat's policy on - * NT only dependancies. + if (!filebuf) + filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 80); + filesize = format_proc_uptime (filebuf, bufalloc); + break; + } + case PROC_STAT: + { + if (!filebuf) + filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048); + filesize = format_proc_stat (filebuf, bufalloc); + break; + } + case PROC_LOADAVG: + { + /* + * not really supported - Windows doesn't keep track of these values + * Windows 95/98/me does have the KERNEL/CPUUsage performance counter + * which is similar. */ - DWORD ticks = GetTickCount (); - filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 40); - __small_sprintf (filebuf, "%d.%02d\n", ticks / 1000, - (ticks / 10) % 100); - filesize = strlen (filebuf); + if (!filebuf) + filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 16); + filesize = __small_sprintf (filebuf, "%u.%02u %u.%02u %u.%02u\n", + 0, 0, 0, 0, 0, 0); + break; + } + case PROC_MEMINFO: + { + if (!filebuf) + filebuf = (char *) cmalloc (HEAP_BUF, bufalloc = 2048); + filesize = format_proc_meminfo (filebuf, bufalloc); break; } } +} - if (flags & O_APPEND) - position = filesize; +static +off_t +format_proc_meminfo (char *destbuf, size_t maxsize) +{ + unsigned long mem_total = 0UL, mem_free = 0UL, swap_total = 0UL, + swap_free = 0UL; + MEMORYSTATUS memory_status; + GlobalMemoryStatus (&memory_status); + mem_total = memory_status.dwTotalPhys; + mem_free = memory_status.dwAvailPhys; + swap_total = memory_status.dwTotalPageFile; + swap_free = memory_status.dwAvailPageFile; + return __small_sprintf (destbuf, " total: used: free:\n" + "Mem: %10lu %10lu %10lu\n" + "Swap: %10lu %10lu %10lu\n" + "MemTotal: %10lu kB\n" + "MemFree: %10lu kB\n" + "MemShared: 0 kB\n" + "HighTotal: 0 kB\n" + "HighFree: 0 kB\n" + "LowTotal: %10lu kB\n" + "LowFree: %10lu kB\n" + "SwapTotal: %10lu kB\n" + "SwapFree: %10lu kB\n", + mem_total, mem_total - mem_free, mem_free, + swap_total, swap_total - swap_free, swap_free, + mem_total >> 10, mem_free >> 10, + mem_total >> 10, mem_free >> 10, + swap_total >> 10, swap_free >> 10); +} + +static +off_t +format_proc_uptime (char *destbuf, size_t maxsize) +{ + unsigned long long uptime = 0ULL, idle_time = 0ULL; + SYSTEM_PROCESSOR_TIMES spt; + + NTSTATUS ret = ZwQuerySystemInformation (SystemProcessorTimes, (PVOID) &spt, + sizeof spt, NULL); + if (!ret && GetLastError () == ERROR_PROC_NOT_FOUND) + uptime = GetTickCount() / 10; + else if (ret != STATUS_SUCCESS) + { + __seterrno_from_win_error (RtlNtStatusToDosError (ret)); + debug_printf("NtQuerySystemInformation: ret = %d, " + "Dos(ret) = %d", + ret, RtlNtStatusToDosError (ret)); + return 0; + } else - position = 0; + { + idle_time = spt.IdleTime.QuadPart / 100000ULL; + uptime = (spt.InterruptTime.QuadPart + spt.KernelTime.QuadPart + + spt.IdleTime.QuadPart + spt.UserTime.QuadPart + + spt.DpcTime.QuadPart) / 100000ULL; + } -success: - res = 1; - set_open_status (); - set_flags (flags); -out: - syscall_printf ("%d = fhandler_proc::open (%p, %d)", res, flags, mode); - return res; + return __small_sprintf (destbuf, "%U.%02u %U.%02u\n", + uptime / 100, long (uptime % 100), + idle_time / 100, long (idle_time % 100)); +} + +static +off_t +format_proc_stat (char *destbuf, size_t maxsize) +{ + unsigned long long user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL; + unsigned long pages_in = 0UL, pages_out = 0UL, interrupt_count = 0UL, + context_switches = 0UL, swap_in = 0UL, swap_out = 0UL; + time_t boot_time = 0; + + if (wincap.is_winnt ()) + { + NTSTATUS ret; + SYSTEM_PROCESSOR_TIMES spt; + SYSTEM_PERFORMANCE_INFORMATION spi; + SYSTEM_TIME_OF_DAY_INFORMATION stodi; + ret = ZwQuerySystemInformation (SystemProcessorTimes, + (PVOID) &spt, + sizeof spt, NULL); + if (ret == STATUS_SUCCESS) + ret = ZwQuerySystemInformation (SystemPerformanceInformation, + (PVOID) &spi, + sizeof spi, NULL); + if (ret == STATUS_SUCCESS) + ret = ZwQuerySystemInformation (SystemTimeOfDayInformation, + (PVOID) &stodi, + sizeof stodi, NULL); + if (ret != STATUS_SUCCESS) + { + __seterrno_from_win_error (RtlNtStatusToDosError (ret)); + debug_printf("NtQuerySystemInformation: ret = %d, " + "Dos(ret) = %d", + ret, RtlNtStatusToDosError (ret)); + return 0; + } + kernel_time = (spt.KernelTime.QuadPart + spt.InterruptTime.QuadPart + spt.DpcTime.QuadPart) / 100000ULL; + user_time = spt.UserTime.QuadPart / 100000ULL; + idle_time = spt.IdleTime.QuadPart / 100000ULL; + interrupt_count = spt.InterruptCount; + pages_in = spi.PagesRead; + pages_out = spi.PagefilePagesWritten + spi.MappedFilePagesWritten; + /* + * Note: there is no distinction made in this structure between pages + * read from the page file and pages read from mapped files, but there + * is such a distinction made when it comes to writing. Goodness knows + * why. The value of swap_in, then, will obviously be wrong but its our + * best guess. + */ + swap_in = spi.PagesRead; + swap_out = spi.PagefilePagesWritten; + context_switches = spi.ContextSwitches; + boot_time = to_time_t ((FILETIME *) &stodi.BootTime.QuadPart); + } + /* + * else + * { + * There are only two relevant performance counters on Windows 95/98/me, + * VMM/cPageIns and VMM/cPageOuts. The extra effort needed to read these + * counters is by no means worth it. + * } + */ + return __small_sprintf (destbuf, "cpu %U %U %U %U\n" + "page %u %u\n" + "swap %u %u\n" + "intr %u\n" + "ctxt %u\n" + "btime %u\n", + user_time, 0ULL, + kernel_time, idle_time, + pages_in, pages_out, + swap_in, swap_out, + interrupt_count, + context_switches, + boot_time); } -- cgit v1.2.3