summaryrefslogtreecommitdiff
path: root/src/w32.c
diff options
context:
space:
mode:
authorEli Zaretskii <eliz@gnu.org>2009-07-04 10:42:45 +0000
committerEli Zaretskii <eliz@gnu.org>2009-07-04 10:42:45 +0000
commitd1190ba5c5317eea63e733b21a051c5c6b819c1e (patch)
treeb04a60753fffb245523c1da5fcde2078039f5a06 /src/w32.c
parentdcf8f912731d6612a60f251fba3cfbdc6583709f (diff)
downloademacs-d1190ba5c5317eea63e733b21a051c5c6b819c1e.tar.gz
Emulation of `getloadavg' on MS-Windows:
Include float.h (g_b_init_get_native_system_info, g_b_init_get_system_times) (GetNativeSystemInfo_Proc, GetSystemTimes_Proc): Declare. (get_native_system_info, get_system_times): New functions. (buf_next, buf_prev, sample_system_load, getavg): New subroutines. (getloadavg): Rewrite using GetSystemTimes and GetNativeSystemInfo. (globals_of_w32): Initialize g_b_init_get_native_system_info, g_b_init_get_system_times, and num_of_processors.
Diffstat (limited to 'src/w32.c')
-rw-r--r--src/w32.c206
1 files changed, 201 insertions, 5 deletions
diff --git a/src/w32.c b/src/w32.c
index 23da0bad937..ef0272259c4 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -23,6 +23,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <stddef.h> /* for offsetof */
#include <stdlib.h>
#include <stdio.h>
+#include <float.h> /* for DBL_EPSILON */
#include <io.h>
#include <errno.h>
#include <fcntl.h>
@@ -191,6 +192,8 @@ static BOOL g_b_init_global_memory_status_ex;
static BOOL g_b_init_get_length_sid;
static BOOL g_b_init_equal_sid;
static BOOL g_b_init_copy_sid;
+static BOOL g_b_init_get_native_system_info;
+static BOOL g_b_init_get_system_times;
/*
BEGIN: Wrapper functions around OpenProcessToken
@@ -293,6 +296,12 @@ typedef BOOL (WINAPI * EqualSid_Proc) (
PSID pSid2);
typedef DWORD (WINAPI * GetLengthSid_Proc) (
PSID pSid);
+typedef void (WINAPI * GetNativeSystemInfo_Proc) (
+ LPSYSTEM_INFO lpSystemInfo);
+typedef BOOL (WINAPI * GetSystemTimes_Proc) (
+ LPFILETIME lpIdleTime,
+ LPFILETIME lpKernelTime,
+ LPFILETIME lpUserTime);
@@ -723,6 +732,47 @@ BOOL WINAPI copy_sid (
supported in Windows NT / 2k / XP
*/
+void WINAPI get_native_system_info (
+ LPSYSTEM_INFO lpSystemInfo)
+{
+ static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
+ if (is_windows_9x () != TRUE)
+ {
+ if (g_b_init_get_native_system_info == 0)
+ {
+ g_b_init_get_native_system_info = 1;
+ s_pfn_Get_Native_System_Info =
+ (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
+ "GetNativeSystemInfo");
+ }
+ if (s_pfn_Get_Native_System_Info != NULL)
+ s_pfn_Get_Native_System_Info (lpSystemInfo);
+ }
+ else
+ lpSystemInfo->dwNumberOfProcessors = -1;
+}
+
+BOOL WINAPI get_system_times(
+ LPFILETIME lpIdleTime,
+ LPFILETIME lpKernelTime,
+ LPFILETIME lpUserTime)
+{
+ static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
+ if (is_windows_9x () == TRUE)
+ {
+ return FALSE;
+ }
+ if (g_b_init_get_system_times == 0)
+ {
+ g_b_init_get_system_times = 1;
+ s_pfn_Get_System_times =
+ (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
+ "GetSystemTimes");
+ }
+ if (s_pfn_Get_System_times == NULL)
+ return FALSE;
+ return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
+}
/* Equivalent of strerror for W32 error codes. */
char *
@@ -795,17 +845,160 @@ gethostname (char *buffer, int size)
#endif /* HAVE_SOCKETS */
/* Emulate getloadavg. */
+
+struct load_sample {
+ time_t sample_time;
+ ULONGLONG idle;
+ ULONGLONG kernel;
+ ULONGLONG user;
+};
+
+/* Number of processors on this machine. */
+static unsigned num_of_processors;
+
+/* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
+static struct load_sample samples[16*60];
+static int first_idx = -1, last_idx = -1;
+static int max_idx = sizeof (samples) / sizeof (samples[0]);
+
+static int
+buf_next (int from)
+{
+ int next_idx = from + 1;
+
+ if (next_idx >= max_idx)
+ next_idx = 0;
+
+ return next_idx;
+}
+
+static int
+buf_prev (int from)
+{
+ int prev_idx = from - 1;
+
+ if (prev_idx < 0)
+ prev_idx = max_idx - 1;
+
+ return prev_idx;
+}
+
+static void
+sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
+{
+ SYSTEM_INFO sysinfo;
+ FILETIME ft_idle, ft_user, ft_kernel;
+
+ /* Initialize the number of processors on this machine. */
+ if (num_of_processors <= 0)
+ {
+ get_native_system_info (&sysinfo);
+ num_of_processors = sysinfo.dwNumberOfProcessors;
+ if (num_of_processors <= 0)
+ {
+ GetSystemInfo (&sysinfo);
+ num_of_processors = sysinfo.dwNumberOfProcessors;
+ }
+ if (num_of_processors <= 0)
+ num_of_processors = 1;
+ }
+
+ /* TODO: Take into account threads that are ready to run, by
+ sampling the "\System\Processor Queue Length" performance
+ counter. The code below accounts only for threads that are
+ actually running. */
+
+ if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
+ {
+ ULARGE_INTEGER uidle, ukernel, uuser;
+
+ memcpy (&uidle, &ft_idle, sizeof (ft_idle));
+ memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
+ memcpy (&uuser, &ft_user, sizeof (ft_user));
+ *idle = uidle.QuadPart;
+ *kernel = ukernel.QuadPart;
+ *user = uuser.QuadPart;
+ }
+ else
+ {
+ *idle = 0;
+ *kernel = 0;
+ *user = 0;
+ }
+}
+
+/* Produce the load average for a given time interval, using the
+ samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
+ 1-minute, 5-minute, or 15-minute average, respectively. */
+static double
+getavg (int which)
+{
+ double retval = -1.0;
+ double tdiff;
+ int idx;
+ double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
+ time_t now = samples[last_idx].sample_time;
+
+ if (first_idx != last_idx)
+ {
+ for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
+ {
+ tdiff = difftime (now, samples[idx].sample_time);
+ if (tdiff >= span - 2*DBL_EPSILON*now)
+ {
+ long double sys =
+ samples[last_idx].kernel + samples[last_idx].user
+ - (samples[idx].kernel + samples[idx].user);
+ long double idl = samples[last_idx].idle - samples[idx].idle;
+
+ retval = (1.0 - idl / sys) * num_of_processors;
+ break;
+ }
+ if (idx == first_idx)
+ break;
+ }
+ }
+
+ return retval;
+}
+
int
getloadavg (double loadavg[], int nelem)
{
- int i;
+ int elem;
+ ULONGLONG idle, kernel, user;
+ time_t now = time (NULL);
+
+ /* Store another sample. We ignore samples that are less than 1 sec
+ apart. */
+ if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
+ {
+ sample_system_load (&idle, &kernel, &user);
+ last_idx = buf_next (last_idx);
+ samples[last_idx].sample_time = now;
+ samples[last_idx].idle = idle;
+ samples[last_idx].kernel = kernel;
+ samples[last_idx].user = user;
+ /* If the buffer has more that 15 min worth of samples, discard
+ the old ones. */
+ if (first_idx == -1)
+ first_idx = last_idx;
+ while (first_idx != last_idx
+ && (difftime (now, samples[first_idx].sample_time)
+ >= 15.0*60 + 2*DBL_EPSILON*now))
+ first_idx = buf_next (first_idx);
+ }
- /* A faithful emulation is going to have to be saved for a rainy day. */
- for (i = 0; i < nelem; i++)
+ for (elem = 0; elem < nelem; elem++)
{
- loadavg[i] = 0.0;
+ double avg = getavg (elem);
+
+ if (avg < 0)
+ break;
+ loadavg[elem] = avg;
}
- return i;
+
+ return elem;
}
/* Emulate getpwuid, getpwnam and others. */
@@ -5693,6 +5886,9 @@ globals_of_w32 ()
g_b_init_equal_sid = 0;
g_b_init_copy_sid = 0;
g_b_init_get_length_sid = 0;
+ g_b_init_get_native_system_info = 0;
+ g_b_init_get_system_times = 0;
+ num_of_processors = 0;
/* The following sets a handler for shutdown notifications for
console apps. This actually applies to Emacs in both console and
GUI modes, since we had to fool windows into thinking emacs is a