1/*
2
3Copyright (c) 1989  X Consortium
4
5Permission is hereby granted, free of charge, to any person obtaining
6a copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sublicense, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice shall be included
14in all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of the X Consortium shall
25not be used in advertising or otherwise to promote the sale, use or
26other dealings in this Software without prior written authorization
27from the X Consortium.
28
29*/
30
31/*
32 * get_load - get system load
33 *
34 * Authors:  Many and varied...
35 *
36 * Call InitLoadPoint() to initialize.
37 * GetLoadPoint() is a callback for the StripChart widget.
38 */
39
40#ifdef HAVE_CONFIG_H
41# include "config.h"
42#endif
43
44#include <X11/Xos.h>
45#include <X11/Intrinsic.h>
46#include <X11/Xlocale.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include "xload.h"
50
51#if defined(__CYGWIN__) || defined(_WIN32)
52# define WIN32_LEAN_AND_MEAN
53# include <X11/Xwindows.h>
54typedef struct {
55  DWORD stat;
56  union {
57    LONG vLong;
58    double vDouble;
59    LONGLONG vLongLong;
60    void *string;
61  } u;
62} COUNTER;
63static HANDLE query;
64static HANDLE counter;
65static HINSTANCE hdll;
66static long (__stdcall *pdhopen)(LPCSTR, DWORD, HANDLE);
67static long (__stdcall *pdhaddcounter)(HANDLE, LPCSTR, DWORD, HANDLE*);
68static long (__stdcall *pdhcollectquerydata)(HANDLE);
69static long (__stdcall *pdhgetformattedcountervalue)(HANDLE, DWORD, LPDWORD, COUNTER*);
70# define CYGWIN_PERF
71void InitLoadPoint(void)
72{
73  long ret;
74  hdll=LoadLibrary("pdh.dll");
75  if (!hdll) exit(-1);
76  pdhopen=(void*)GetProcAddress(hdll, "PdhOpenQueryA");
77  if (!pdhopen) exit(-1);
78  pdhaddcounter=(void*)GetProcAddress(hdll, "PdhAddCounterA");
79  if (!pdhaddcounter) exit(-1);
80  pdhcollectquerydata=(void*)GetProcAddress(hdll, "PdhCollectQueryData");
81  if (!pdhcollectquerydata) exit(-1);
82  pdhgetformattedcountervalue=(void*)GetProcAddress(hdll, "PdhGetFormattedCounterValue");
83  if (!pdhgetformattedcountervalue) exit(-1);
84  ret = pdhopen( NULL , 0, &query );
85  if (ret!=0) exit(-1);
86  ret = pdhaddcounter(query, "\\Processor(_Total)\\% Processor Time", 0, &counter);
87  if (ret!=0) exit(-1);
88}
89void GetLoadPoint(
90     Widget  w,              /* unused */
91     XtPointer    closure,        /* unused */
92     XtPointer    call_data)      /* pointer to (double) return value */
93{
94  double *loadavg = (double *)call_data;
95  COUNTER fmtvalue;
96  long ret;
97  *loadavg = 0.0;
98  ret = pdhcollectquerydata(query);
99  if (ret!=0) return;
100  ret = pdhgetformattedcountervalue(counter, 0x200, NULL, &fmtvalue);
101  if (ret!=0) return;
102  *loadavg = (fmtvalue.u.vDouble-0.01)/100.0;
103}
104#else /* not CYGWIN */
105
106static void xload_error(const char *, const char *) _X_NORETURN;
107
108# ifdef HAVE_GETLOADAVG
109#  include <stdlib.h>
110#  ifdef HAVE_SYS_LOADAVG_H
111#   include <sys/loadavg.h>	/* Solaris definition of getloadavg */
112#  endif
113
114void InitLoadPoint(void)
115{
116}
117
118void GetLoadPoint(
119    Widget w,            /* unused */
120    XtPointer closure,   /* unused */
121    XtPointer call_data) /* ptr to (double) return value */
122{
123    double *loadavg = (double *)call_data;
124
125    if (getloadavg(loadavg, 1) < 0)
126        xload_error("couldn't obtain load average", "");
127}
128
129# else /* not HAVE_GETLOADAVG */
130
131
132#  if !defined(linux) && !defined(__GLIBC__)
133#   include <nlist.h>
134#  endif /* !linux && ... */
135
136#  ifdef CSRG_BASED
137#   include <sys/param.h>
138#  endif
139
140#  if defined(linux) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__))
141
142void InitLoadPoint(void)
143{
144      return;
145}
146
147void GetLoadPoint(
148    Widget	w,		/* unused */
149    XtPointer	closure,	/* unused */
150    XtPointer	call_data)      /* pointer to (double) return value */
151{
152      static int fd = -1;
153      int n;
154      char buf[10] = {0, };
155#   ifndef X_LOCALE
156      char *dp;
157      static char ldp = 0;
158#   endif
159
160
161      if (fd < 0)
162      {
163              if (fd == -2 ||
164                  (fd = open("/proc/loadavg", O_RDONLY)) < 0)
165              {
166                      fd = -2;
167                      *(double *)call_data = 0.0;
168                      return;
169              }
170#   ifndef X_LOCALE
171	      ldp = *localeconv()->decimal_point;
172#   endif
173      }
174      else
175              lseek(fd, 0, 0);
176
177      if ((n = read(fd, buf, sizeof(buf)-1)) > 0) {
178#   ifndef X_LOCALE
179	  if (ldp != '.')
180	      while ((dp = memchr(buf,'.',sizeof(buf)-1)) != NULL) {
181		  *(char *)dp = ldp;
182	      }
183
184#   endif
185	  if (sscanf(buf, "%lf", (double *)call_data) == 1)
186	      return;
187      }
188
189
190      *(double *)call_data = 0.0;     /* temporary hiccup */
191
192      return;
193}
194
195#  else /* linux */
196
197#   ifdef __GNU__
198
199#    include <mach.h>
200
201static processor_set_t default_set;
202
203void InitLoadPoint(void)
204{
205  if (processor_set_default (mach_host_self (), &default_set) != KERN_SUCCESS)
206    xload_error("cannot get processor_set_default", "");
207}
208
209/* ARGSUSED */
210void GetLoadPoint(
211    Widget	w,		/* unused */
212    XtPointer	closure,	/* unused */
213    XtPointer	call_data)	/* pointer to (double) return value */
214{
215  host_t host;
216  struct processor_set_basic_info info;
217  unsigned info_count;
218
219  info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
220  if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
221			  (processor_set_info_t) &info, &info_count)
222      != KERN_SUCCESS)
223    {
224      InitLoadPoint();
225      info.load_average = 0;
226    }
227
228  *(double *)call_data = info.load_average * 1000 / LOAD_SCALE;
229
230  return;
231}
232
233#   else /* __GNU__ */
234
235#    ifdef __APPLE__
236
237#     include <mach/mach.h>
238
239static mach_port_t host_priv_port;
240
241void InitLoadPoint(void)
242{
243    host_priv_port = mach_host_self();
244}
245
246/* ARGSUSED */
247void GetLoadPoint(
248    Widget	w,		/* unused */
249    XtPointer	closure,	/* unused */
250    XtPointer	call_data)	/* pointer to (double) return value */
251{
252    double *loadavg = (double *)call_data;
253
254    struct host_load_info load_data;
255    int host_count;
256    kern_return_t kr;
257
258    host_count = sizeof(load_data)/sizeof(integer_t);
259    kr = host_statistics(host_priv_port, HOST_LOAD_INFO,
260                        (host_info_t)&load_data, &host_count);
261    if (kr != KERN_SUCCESS)
262        xload_error("cannot get host statistics", "");
263    *loadavg = (double)load_data.avenrun[0]/LOAD_SCALE;
264    return;
265}
266
267#    else /* __APPLE__ */
268
269
270
271#     ifdef __QNXNTO__
272#      include <time.h>
273#      include <sys/neutrino.h>
274static _Uint64t          nto_idle = 0, nto_idle_last = 0;
275static  int       nto_idle_id;
276static  struct timespec nto_now, nto_last;
277
278void
279InitLoadPoint(void)
280{
281  nto_idle_id = ClockId(1, 1); /* Idle thread */
282  ClockTime(nto_idle_id, NULL, &nto_idle_last);
283  clock_gettime( CLOCK_REALTIME, &nto_last);
284}
285
286/* ARGSUSED */
287void
288GetLoadPoint(			/* QNX NTO version */
289    Widget	w,		/* unused */
290    XtPointer	closure,	/* unused */
291    XtPointer	call_data)	/* pointer to (double) return value */
292{
293    double *loadavg = (double *)call_data;
294    double timediff;
295    double temp = 0.0;
296
297    ClockTime(nto_idle_id, NULL, &nto_idle);
298    clock_gettime( CLOCK_REALTIME, &nto_now);
299    timediff = 1000000000.0 * (nto_now.tv_sec - nto_last.tv_sec)
300               + (nto_now.tv_nsec - nto_last.tv_nsec);
301    temp = 1.0 - (nto_idle-nto_idle_last)/timediff;
302    *loadavg = temp >= 0 ? temp : 0;
303    nto_idle_last = nto_idle;
304    nto_last = nto_now;
305}
306#     else /* not __QNXNTO__ */
307
308#      ifndef KMEM_FILE
309#       define KMEM_FILE "/dev/kmem"
310#      endif
311
312#      ifndef KERNEL_FILE
313/*
314 * provide default for everyone else
315 */
316/* If <paths.h> exists, check in it */
317#       ifdef HAVE_PATHS_H
318#        include <paths.h>
319#        ifdef _PATH_UNIX
320#         define KERNEL_FILE _PATH_UNIX
321#        else
322#         ifdef _PATH_KERNEL
323#          define KERNEL_FILE _PATH_KERNEL
324#         else
325#          define KERNEL_FILE "/vmunix"
326#         endif
327#        endif
328#       else /* HAVE_PATHS_H */
329#        define KERNEL_FILE "/vmunix"
330#       endif /* HAVE_PATHS_H */
331#      endif /* KERNEL_FILE */
332
333
334#      ifndef KERNEL_LOAD_VARIABLE
335#       if defined(BSD) && (BSD >= 199103)
336#        define KERNEL_LOAD_VARIABLE "_averunnable"
337#       else /* BSD >= 199103 */
338#        define KERNEL_LOAD_VARIABLE "_avenrun"
339#       endif /* BSD >= 199103 */
340#      endif /* KERNEL_LOAD_VARIABLE */
341
342static struct nlist namelist[] = {	    /* namelist for vmunix grubbing */
343#      define LOADAV 0
344    {KERNEL_LOAD_VARIABLE},
345    {0}
346};
347
348static int kmem;
349static long loadavg_seek;
350
351void InitLoadPoint()
352{
353#      if !defined(AIXV5) && !(BSD >= 199103) && !defined(__APPLE__)
354    extern void nlist();
355#      endif
356
357    nlist( KERNEL_FILE, namelist);
358    /*
359     * Some systems appear to set only one of these to Zero if the entry could
360     * not be found, I hope no_one returns Zero as a good value, or bad things
361     * will happen to you.  (I have a hard time believing the value will
362     * ever really be zero anyway).   CDP 5/17/89.
363     */
364    if (namelist[LOADAV].n_type == 0 ||
365	namelist[LOADAV].n_value == 0) {
366	xload_error("cannot get name list from", KERNEL_FILE);
367	exit(-1);
368    }
369    loadavg_seek = namelist[LOADAV].n_value;
370    kmem = open(KMEM_FILE, O_RDONLY);
371    if (kmem < 0) xload_error("cannot open", KMEM_FILE);
372}
373
374/* ARGSUSED */
375void GetLoadPoint( w, closure, call_data )
376     Widget	w;		/* unused */
377     XtPointer	closure;	/* unused */
378     XtPointer	call_data;	/* pointer to (double) return value */
379{
380  	double *loadavg = (double *)call_data;
381
382	(void) lseek(kmem, loadavg_seek, 0);
383
384#      if (BSD >= 199103)
385	{
386		long temp;
387		(void) read(kmem, (char *)&temp, sizeof(long));
388		*loadavg = (double)temp/FSCALE;
389	}
390#      else /* else not BSD */
391	(void) read(kmem, (char *)loadavg, sizeof(double));
392#      endif /* or ... else */
393	return;
394}
395#     endif /* __QNXNTO__ else */
396#    endif /* __APPLE__ else */
397#   endif /* __GNU__ else */
398#  endif /* linux else */
399# endif /* HAVE_GETLOADAVG else */
400
401static void xload_error(const char *str1, const char *str2)
402{
403    (void) fprintf(stderr,"xload: %s %s\n", str1, str2);
404    exit(-1);
405}
406
407#endif /* END of __CYGWIN__ */
408