get_load.c revision a8bb11d0
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__)
52#define WIN32_LEAN_AND_MEAN
53#include <windows.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
105
106
107#if defined(att) || defined(QNX4)
108#define LOADSTUB
109#endif
110
111#ifndef LOADSTUB
112#if !defined(linux) && !defined(__UNIXOS2__) && !defined(__GLIBC__)
113#include <nlist.h>
114#endif /* !linux && ... */
115#endif /* LOADSTUB */
116
117#if defined(MOTOROLA) && defined(SYSV)
118#include <sys/sysinfo.h>
119#endif
120
121#ifdef CSRG_BASED
122#include <sys/param.h>
123#endif
124
125#if defined(umips) || (defined(ultrix) && defined(mips))
126#include <sys/fixpoint.h>
127#endif
128
129#if  defined(CRAY) || defined(AIXV3)
130#include <sys/param.h>
131#define word word_t
132#include <sys/sysinfo.h>
133#undef word
134#undef n_type
135#define n_type n_value
136#endif	/* CRAY */
137
138#ifdef sequent
139#include <sys/vm.h>
140#endif /* sequent */
141
142
143#ifdef hcx
144#include <sys/param.h>
145#endif /* hcx */
146
147#if defined(UTEK) || defined(alliant) || (defined(MOTOROLA) && defined(SVR4))
148#define FSCALE	100.0
149#endif
150
151#ifdef sequent
152#define FSCALE	1000.0
153#endif
154
155#ifdef sgi
156#define FSCALE	1024.0
157#endif
158
159#if defined(sony) && OSMAJORVERSION == 4
160#ifdef mips
161#include <sys/fixpoint.h>
162#else
163#include <sys/param.h>
164#endif
165#endif
166
167#ifdef __osf__
168/*
169 * Use the table(2) interface; it doesn't require setuid root.
170 *
171 * Select 0, 1, or 2 for 5, 30, or 60 second load averages.
172 */
173#ifndef WHICH_AVG
174#define WHICH_AVG 1
175#endif
176#include <sys/table.h>
177#endif
178
179#ifdef SVR4
180#ifndef FSCALE
181#define FSCALE	(1 << 8)
182#endif
183#endif
184
185#ifdef X_NOT_POSIX
186extern long lseek();
187#endif
188
189static void xload_error(const char *, const char *) _X_NORETURN;
190
191
192#if defined(SYSV) && defined(i386)
193/*
194 * inspired by 'avgload' by John F. Haugh II
195 */
196#include <sys/param.h>
197#include <sys/buf.h>
198#include <sys/immu.h>
199#include <sys/region.h>
200#include <sys/var.h>
201#include <sys/proc.h>
202#define KERNEL_FILE "/unix"
203#define KMEM_FILE "/dev/kmem"
204#define VAR_NAME "v"
205#define PROC_NAME "proc"
206#define BUF_NAME "buf"
207#define DECAY 0.8
208struct nlist namelist[] = {
209  {VAR_NAME},
210  {PROC_NAME},
211  {BUF_NAME},
212  {0},
213};
214
215static int kmem;
216static struct var v;
217static struct proc *p;
218static XtPointer first_buf, last_buf;
219
220void InitLoadPoint()				/* SYSV386 version */
221{
222    int i;
223
224    nlist( KERNEL_FILE, namelist);
225
226    for (i=0; namelist[i].n_name; i++)
227	if (namelist[i].n_value == 0)
228	    xload_error("cannot get name list from", KERNEL_FILE);
229
230    if ((kmem = open(KMEM_FILE, O_RDONLY)) < 0)
231	xload_error("cannot open", KMEM_FILE);
232
233    if (lseek(kmem, namelist[0].n_value, 0) == -1)
234	xload_error("cannot seek", VAR_NAME);
235
236    if (read(kmem, &v, sizeof(v)) != sizeof(v))
237	xload_error("cannot read", VAR_NAME);
238
239    if ((p=(struct proc *)malloc(v.v_proc*sizeof(*p))) == NULL)
240	xload_error("cannot allocat space for", PROC_NAME);
241
242    first_buf = (XtPointer) namelist[2].n_value;
243    last_buf  = (char *)first_buf + v.v_buf * sizeof(struct buf);
244}
245
246/* ARGSUSED */
247void GetLoadPoint( w, closure, call_data )	/* SYSV386 version */
248Widget	w;		/* unused */
249XtPointer	closure;	/* unused */
250XtPointer	call_data;	/* pointer to (double) return value */
251{
252    double *loadavg = (double *)call_data;
253    static double avenrun = 0.0;
254    int i, nproc, size;
255
256    (void) lseek(kmem, namelist[0].n_value, 0);
257    (void) read(kmem, &v, sizeof(v));
258
259    size = (struct proc *)v.ve_proc - (struct proc *)namelist[1].n_value;
260
261    (void) lseek(kmem, namelist[1].n_value, 0);
262    (void) read(kmem, p, size * sizeof(struct proc));
263
264    for (nproc = 0, i=0; i<size; i++)
265	  if ((p[i].p_stat == SRUN) ||
266	      (p[i].p_stat == SIDL) ||
267	      (p[i].p_stat == SXBRK) ||
268	      (p[i].p_stat == SSLEEP && (p[i].p_pri < PZERO) &&
269	       (p[i].p_wchan >= (char *)first_buf) && (p[i].p_wchan < (char *)last_buf)))
270	    nproc++;
271
272    /* update the load average using a decay filter */
273    avenrun = DECAY * avenrun + nproc * (1.0 - DECAY);
274    *loadavg = avenrun;
275
276    return;
277}
278#else /* not (SYSV && i386) */
279
280#if defined(linux) || (defined(__FreeBSD_kernel__) && defined(__GLIBC__))
281
282void InitLoadPoint(void)
283{
284      return;
285}
286
287void GetLoadPoint(
288    Widget	w,		/* unused */
289    XtPointer	closure,	/* unused */
290    XtPointer	call_data)      /* pointer to (double) return value */
291{
292      static int fd = -1;
293      int n;
294      char buf[10] = {0, };
295#ifndef X_LOCALE
296      char *dp;
297      static char ldp = 0;
298#endif
299
300
301      if (fd < 0)
302      {
303              if (fd == -2 ||
304                  (fd = open("/proc/loadavg", O_RDONLY)) < 0)
305              {
306                      fd = -2;
307                      *(double *)call_data = 0.0;
308                      return;
309              }
310#ifndef X_LOCALE
311	      ldp = *localeconv()->decimal_point;
312#endif
313      }
314      else
315              lseek(fd, 0, 0);
316
317      if ((n = read(fd, buf, sizeof(buf)-1)) > 0) {
318#ifndef X_LOCALE
319	  if (ldp != '.')
320	      while ((dp = memchr(buf,'.',sizeof(buf)-1)) != NULL) {
321		  *(char *)dp = ldp;
322	      }
323
324#endif
325	  if (sscanf(buf, "%lf", (double *)call_data) == 1)
326	      return;
327      }
328
329
330      *(double *)call_data = 0.0;     /* temporary hiccup */
331
332      return;
333}
334
335#else /* linux */
336
337#ifdef __GNU__
338
339#include <mach.h>
340
341static processor_set_t default_set;
342
343void InitLoadPoint(void)
344{
345  if (processor_set_default (mach_host_self (), &default_set) != KERN_SUCCESS)
346    xload_error("cannot get processor_set_default", "");
347}
348
349/* ARGSUSED */
350void GetLoadPoint(
351    Widget	w,		/* unused */
352    XtPointer	closure,	/* unused */
353    XtPointer	call_data)	/* pointer to (double) return value */
354{
355  host_t host;
356  struct processor_set_basic_info info;
357  unsigned info_count;
358
359  info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
360  if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
361			  (processor_set_info_t) &info, &info_count)
362      != KERN_SUCCESS)
363    {
364      InitLoadPoint();
365      info.load_average = 0;
366    }
367
368  *(double *)call_data = info.load_average * 1000 / LOAD_SCALE;
369
370  return;
371}
372
373#else /* __GNU__ */
374
375#ifdef __APPLE__
376
377#include <mach/mach.h>
378
379static mach_port_t host_priv_port;
380
381void InitLoadPoint(void)
382{
383    host_priv_port = mach_host_self();
384}
385
386/* ARGSUSED */
387void GetLoadPoint(
388    Widget	w,		/* unused */
389    XtPointer	closure,	/* unused */
390    XtPointer	call_data)	/* pointer to (double) return value */
391{
392    double *loadavg = (double *)call_data;
393
394    struct host_load_info load_data;
395    int host_count;
396    kern_return_t kr;
397
398    host_count = sizeof(load_data)/sizeof(integer_t);
399    kr = host_statistics(host_priv_port, HOST_LOAD_INFO,
400                        (host_info_t)&load_data, &host_count);
401    if (kr != KERN_SUCCESS)
402        xload_error("cannot get host statistics", "");
403    *loadavg = (double)load_data.avenrun[0]/LOAD_SCALE;
404    return;
405}
406
407#else /* __APPLE__ */
408
409#ifdef LOADSTUB
410
411void InitLoadPoint()
412{
413}
414
415/* ARGSUSED */
416void GetLoadPoint( w, closure, call_data )
417     Widget	w;		/* unused */
418     XtPointer	closure;	/* unused */
419     XtPointer	call_data;	/* pointer to (double) return value */
420{
421	*(double *)call_data = 1.0;
422}
423
424#else /* not LOADSTUB */
425
426#ifdef __osf__
427
428void InitLoadPoint()
429{
430}
431
432/*ARGSUSED*/
433void GetLoadPoint( w, closure, call_data )
434     Widget   w;              /* unused */
435     XtPointer  closure;        /* unused */
436     XtPointer  call_data;      /* pointer to (double) return value */
437{
438    double *loadavg = (double *)call_data;
439    struct tbl_loadavg load_data;
440
441    if (table(TBL_LOADAVG, 0, (char *)&load_data, 1, sizeof(load_data)) < 0)
442	xload_error("error reading load average", "");
443    *loadavg = (load_data.tl_lscale == 0) ?
444	load_data.tl_avenrun.d[WHICH_AVG] :
445	load_data.tl_avenrun.l[WHICH_AVG] / (double)load_data.tl_lscale;
446}
447
448#else /* not __osf__ */
449
450#ifdef __QNXNTO__
451#include <time.h>
452#include <sys/neutrino.h>
453static _Uint64t          nto_idle = 0, nto_idle_last = 0;
454static  int       nto_idle_id;
455static  struct timespec nto_now, nto_last;
456
457void
458InitLoadPoint(void)
459{
460  nto_idle_id = ClockId(1, 1); /* Idle thread */
461  ClockTime(nto_idle_id, NULL, &nto_idle_last);
462  clock_gettime( CLOCK_REALTIME, &nto_last);
463}
464
465/* ARGSUSED */
466void
467GetLoadPoint(			/* QNX NTO version */
468    Widget	w,		/* unused */
469    XtPointer	closure,	/* unused */
470    XtPointer	call_data)	/* pointer to (double) return value */
471{
472    double *loadavg = (double *)call_data;
473    double timediff;
474    double temp = 0.0;
475
476    ClockTime(nto_idle_id, NULL, &nto_idle);
477    clock_gettime( CLOCK_REALTIME, &nto_now);
478    timediff = 1000000000.0 * (nto_now.tv_sec - nto_last.tv_sec)
479               + (nto_now.tv_nsec - nto_last.tv_nsec);
480    temp = 1.0 - (nto_idle-nto_idle_last)/timediff;
481    *loadavg = temp >= 0 ? temp : 0;
482    nto_idle_last = nto_idle;
483    nto_last = nto_now;
484}
485#else /* not __QNXNTO__ */
486
487#ifdef __bsdi__
488#include <kvm.h>
489
490static struct nlist nl[] = {
491  { "_averunnable" },
492#define X_AVERUNNABLE 0
493  { "_fscale" },
494#define X_FSCALE      1
495  { "" },
496};
497static kvm_t *kd;
498static int fscale;
499
500void InitLoadPoint(void)
501{
502  fixpt_t averunnable[3];  /* unused really */
503
504  if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, NULL)) == NULL)
505    xload_error("can't open kvm files", "");
506
507  if (kvm_nlist(kd, nl) != 0)
508    xload_error("can't read name list", "");
509
510  if (kvm_read(kd, (off_t)nl[X_AVERUNNABLE].n_value, (char *)averunnable,
511	       sizeof(averunnable)) != sizeof(averunnable))
512    xload_error("couldn't obtain _averunnable variable", "");
513
514  if (kvm_read(kd, (off_t)nl[X_FSCALE].n_value, (char *)&fscale,
515	       sizeof(fscale)) != sizeof(fscale))
516    xload_error("couldn't obtain _fscale variable", "");
517
518  return;
519}
520
521void GetLoadPoint(
522     Widget	w,		/* unused */
523     XtPointer	closure,	/* unused */
524    XtPointer	call_data)	/* ptr to (double) return value */
525{
526  double *loadavg = (double *)call_data;
527  fixpt_t t;
528
529  if (kvm_read(kd, (off_t)nl[X_AVERUNNABLE].n_value, (char *)&t,
530	       sizeof(t)) != sizeof(t))
531    xload_error("couldn't obtain load average", "");
532
533  *loadavg = (double)t/fscale;
534
535  return;
536}
537
538#else /* not __bsdi__ */
539#if defined(HAVE_GETLOADAVG)
540#include <stdlib.h>
541#ifdef HAVE_SYS_LOADAVG_H
542#include <sys/loadavg.h>	/* Solaris definition of getloadavg */
543#endif
544
545void InitLoadPoint()
546{
547}
548
549void GetLoadPoint(w, closure, call_data)
550     Widget w;          /* unused */
551     XtPointer closure;   /* unused */
552     XtPointer call_data; /* ptr to (double) return value */
553{
554  double *loadavg = (double *)call_data;
555
556  if (getloadavg(loadavg, 1) < 0)
557    xload_error("couldn't obtain load average", "");
558}
559
560#else /* not HAVE_GETLOADAVG */
561
562#ifndef KMEM_FILE
563#define KMEM_FILE "/dev/kmem"
564#endif
565
566#ifndef KERNEL_FILE
567
568#ifdef alliant
569#define KERNEL_FILE "/vmunix"
570#endif /* alliant */
571
572#ifdef CRAY
573#define KERNEL_FILE "/unicos"
574#endif /* CRAY */
575
576#ifdef hpux
577#define KERNEL_FILE "/hp-ux"
578#endif /* hpux */
579
580
581#ifdef umips
582# ifdef SYSTYPE_SYSV
583# define KERNEL_FILE "/unix"
584# else
585# define KERNEL_FILE "/vmunix"
586# endif /* SYSTYPE_SYSV */
587#endif /* umips */
588
589#ifdef sequent
590#define KERNEL_FILE "/dynix"
591#endif /* sequent */
592
593#ifdef hcx
594#define KERNEL_FILE "/unix"
595#endif /* hcx */
596
597#ifdef MOTOROLA
598#if defined(SYSV) && defined(m68k)
599#define KERNEL_FILE "/sysV68"
600#endif
601#if defined(SYSV) && defined(m88k)
602#define KERNEL_FILE "/unix"
603#endif
604#ifdef SVR4
605#define KERNEL_FILE "/unix"
606#endif
607#endif /* MOTOROLA */
608
609#ifdef sgi
610#if (OSMAJORVERSION > 4)
611#define KERNEL_FILE "/unix"
612#endif
613#endif
614
615/*
616 * provide default for everyone else
617 */
618#ifndef KERNEL_FILE
619#ifdef SVR4
620#define KERNEL_FILE "/stand/unix"
621#else
622#ifdef SYSV
623#define KERNEL_FILE "/unix"
624#else
625/* If a BSD system, check in <paths.h> */
626#   ifdef BSD
627#    include <paths.h>
628#    ifdef _PATH_UNIX
629#     define KERNEL_FILE _PATH_UNIX
630#    else
631#     ifdef _PATH_KERNEL
632#      define KERNEL_FILE _PATH_KERNEL
633#     else
634#      define KERNEL_FILE "/vmunix"
635#     endif
636#    endif
637#   else /* BSD */
638#    define KERNEL_FILE "/vmunix"
639#   endif /* BSD */
640#endif /* SYSV */
641#endif /* SVR4 */
642#endif /* KERNEL_FILE */
643#endif /* KERNEL_FILE */
644
645
646#ifndef KERNEL_LOAD_VARIABLE
647#    if defined(BSD) && (BSD >= 199103)
648#        define KERNEL_LOAD_VARIABLE "_averunnable"
649#    endif /* BSD >= 199103 */
650
651#    ifdef alliant
652#        define KERNEL_LOAD_VARIABLE "_Loadavg"
653#    endif /* alliant */
654
655#    ifdef CRAY
656#        if defined(CRAY2) && OSMAJORVERSION == 4
657#            define KERNEL_LOAD_VARIABLE "avenrun"
658#        else
659#            define KERNEL_LOAD_VARIABLE "sysinfo"
660#            define SYSINFO
661#        endif /* defined(CRAY2) && OSMAJORVERSION == 4 */
662#    endif /* CRAY */
663
664#    ifdef hpux
665#        ifdef __hp9000s800
666#            define KERNEL_LOAD_VARIABLE "avenrun"
667#        endif /* hp9000s800 */
668#    endif /* hpux */
669
670#    ifdef umips
671#        ifdef SYSTYPE_SYSV
672#            define KERNEL_LOAD_VARIABLE "avenrun"
673#        else
674#            define KERNEL_LOAD_VARIABLE "_avenrun"
675#        endif /* SYSTYPE_SYSV */
676#    endif /* umips */
677
678#    ifdef sgi
679#	 define KERNEL_LOAD_VARIABLE "avenrun"
680#    endif /* sgi */
681
682#    ifdef AIXV3
683#        define KERNEL_LOAD_VARIABLE "sysinfo"
684#    endif /* AIXV3 */
685
686#    ifdef MOTOROLA
687#        if defined(SYSV) && defined(m68k)
688#            define KERNEL_LOAD_VARIABLE "sysinfo"
689#        endif
690#        if defined(SYSV) && defined(m88k)
691#            define KERNEL_LOAD_VARIABLE "_sysinfo"
692#        endif
693#        ifdef SVR4
694#            define KERNEL_LOAD_VARIABLE "avenrun"
695#        endif
696#    endif /* MOTOROLA */
697
698#endif /* KERNEL_LOAD_VARIABLE */
699
700/*
701 * provide default for everyone else
702 */
703
704#ifndef KERNEL_LOAD_VARIABLE
705#    ifdef USG
706#        define KERNEL_LOAD_VARIABLE "sysinfo"
707#        define SYSINFO
708#    else
709#    ifdef SVR4
710#        define KERNEL_LOAD_VARIABLE "avenrun"
711#    else
712#        define KERNEL_LOAD_VARIABLE "_avenrun"
713#    endif
714#    endif
715#endif /* KERNEL_LOAD_VARIABLE */
716
717static struct nlist namelist[] = {	    /* namelist for vmunix grubbing */
718#define LOADAV 0
719    {KERNEL_LOAD_VARIABLE},
720    {0}
721};
722
723static int kmem;
724static long loadavg_seek;
725
726void InitLoadPoint()
727{
728#if !defined(SVR4) && !defined(sgi) && !defined(MOTOROLA) && !defined(AIXV5) && !(BSD >= 199103) && !defined(__APPLE__)
729    extern void nlist();
730#endif
731
732#ifdef AIXV3
733    knlist( namelist, 1, sizeof(struct nlist));
734#else
735    nlist( KERNEL_FILE, namelist);
736#endif
737    /*
738     * Some systems appear to set only one of these to Zero if the entry could
739     * not be found, I hope no_one returns Zero as a good value, or bad things
740     * will happen to you.  (I have a hard time believing the value will
741     * ever really be zero anyway).   CDP 5/17/89.
742     */
743#ifdef hcx
744    if (namelist[LOADAV].n_type == 0 &&
745#else
746    if (namelist[LOADAV].n_type == 0 ||
747#endif /* hcx */
748	namelist[LOADAV].n_value == 0) {
749	xload_error("cannot get name list from", KERNEL_FILE);
750	exit(-1);
751    }
752    loadavg_seek = namelist[LOADAV].n_value;
753#if defined(umips) && defined(SYSTYPE_SYSV)
754    loadavg_seek &= 0x7fffffff;
755#endif /* umips && SYSTYPE_SYSV */
756#if (defined(CRAY) && defined(SYSINFO))
757    loadavg_seek += ((char *) (((struct sysinfo *)NULL)->avenrun)) -
758	((char *) NULL);
759#endif /* CRAY && SYSINFO */
760    kmem = open(KMEM_FILE, O_RDONLY);
761    if (kmem < 0) xload_error("cannot open", KMEM_FILE);
762}
763
764/* ARGSUSED */
765void GetLoadPoint( w, closure, call_data )
766     Widget	w;		/* unused */
767     XtPointer	closure;	/* unused */
768     XtPointer	call_data;	/* pointer to (double) return value */
769{
770  	double *loadavg = (double *)call_data;
771
772	(void) lseek(kmem, loadavg_seek, 0);
773
774#if defined (UTEK) || defined(sequent) || defined(alliant) || defined(SVR4) || defined(sgi) || defined(hcx) || (BSD >= 199103)
775	{
776		long temp;
777		(void) read(kmem, (char *)&temp, sizeof(long));
778		*loadavg = (double)temp/FSCALE;
779	}
780#else /* else not UTEK or sequent or alliant or SVR4 or sgi or hcx */
781#  if defined(umips) || (defined(ultrix) && defined(mips))
782	{
783		fix temp;
784		(void) read(kmem, (char *)&temp, sizeof(fix));
785		*loadavg = FIX_TO_DBL(temp);
786	}
787#  else /* not umips or ultrix risc */
788#    ifdef AIXV3
789        {
790          struct sysinfo sysinfo_now;
791          struct sysinfo sysinfo_last;
792          static firsttime = TRUE;
793          static double runavg = 0.0, swpavg = 0.0;
794
795          (void) lseek(kmem, loadavg_seek, 0);
796          (void) read(kmem, (char *)&sysinfo_last, sizeof(struct sysinfo));
797          if (firsttime)
798            {
799              *loadavg = 0.0;
800              firsttime = FALSE;
801            }
802          else
803            {
804              sleep(1);
805              (void) lseek(kmem, loadavg_seek, 0);
806              (void) read(kmem, (char *)&sysinfo_now, sizeof(struct sysinfo));
807              runavg *= 0.8; swpavg *= 0.8;
808              if (sysinfo_now.runocc != sysinfo_last.runocc)
809                runavg += 0.2*((sysinfo_now.runque - sysinfo_last.runque - 1)
810                          /(double)(sysinfo_now.runocc - sysinfo_last.runocc));
811              if (sysinfo_now.swpocc != sysinfo_last.swpocc)
812                swpavg += 0.2*((sysinfo_now.swpque - sysinfo_last.swpque)
813                          /(double)(sysinfo_now.swpocc - sysinfo_last.swpocc));
814              *loadavg = runavg + swpavg;
815              sysinfo_last = sysinfo_now;
816            }
817          /* otherwise we leave load alone. */
818        }
819#    else /* not AIXV3 */
820#      if defined(MOTOROLA) && defined(SYSV)
821	{
822        static int init = 0;
823        static kmem;
824        static long loadavg_seek;
825
826#define CEXP    0.25            /* Constant used for load averaging */
827
828        struct sysinfo sysinfod;
829        static double oldloadavg;
830        static double cexp = CEXP;
831        static long sv_rq, sv_oc;   /* save old values */
832        double rq, oc;              /* amount values have changed */
833
834        if (!init)
835        {
836            if (nlist(KERNEL_FILE,namelist) == -1)
837            {
838                perror("xload: nlist()");
839                xload_error("cannot get name list from", KERNEL_FILE);
840            }
841            loadavg_seek = namelist[0].n_value;
842
843            kmem = open(KMEM_FILE, O_RDONLY);
844            if (kmem < 0)
845            {
846                perror("xload: open()");
847                xload_error("cannot open", KMEM_FILE);
848            }
849        }
850
851        lseek(kmem, loadavg_seek, 0);
852        if (read(kmem, &sysinfod, (int) sizeof (struct sysinfo)) == -1)
853        {
854             perror("xload: read() SYSINFONL");
855             xload_error("read failed from", KMEM_FILE);
856        }
857
858        if (!init)
859        {
860            init = 1;
861            sv_rq = sysinfod.runque;
862            sv_oc = sysinfod.runocc;
863            oldloadavg = *loadavg = 0.0;
864            return;
865        }
866        /*
867         * calculate the amount the values have
868         * changed since last update
869         */
870        rq = (double) sysinfod.runque - sv_rq;
871        oc = (double) sysinfod.runocc - sv_oc;
872
873        /*
874         * save old values for next time
875         */
876        sv_rq = sysinfod.runque;
877        sv_oc = sysinfod.runocc;
878
879        if (oc == 0.0)          /* avoid divide by zero  */
880        {
881                *loadavg = (1.0 - cexp) * oldloadavg;
882
883        }
884        else
885        {
886                *loadavg = ((1.0 - cexp) * oldloadavg) + ((rq / oc) * cexp);
887        }
888        oldloadavg = *loadavg;
889	}
890#      else /* not MOTOROLA */
891#     if defined(sony) && OSMAJORVERSION == 4
892#      ifdef mips
893	{
894		fix temp;
895		(void) read(kmem, (char *)&temp, sizeof(fix));
896		*loadavg = FIX_TO_DBL(temp);
897	}
898#      else /* not mips */
899	{
900		long temp;
901		(void) read(kmem, (char *)&temp, sizeof(long));
902		*loadavg = (double)temp/FSCALE;
903	}
904#      endif /* mips */
905#     else /* not sony NEWSOS4 */
906	(void) read(kmem, (char *)loadavg, sizeof(double));
907#      endif /* sony NEWOS4 */
908#     endif /* MOTOROLA else */
909#    endif /* AIXV3 else */
910#  endif /* umips else */
911#endif /* SVR4 or ... else */
912	return;
913}
914#endif /* HAVE_GETLOADAVG else */
915#endif /* __bsdi__ else */
916#endif /* __QNXNTO__ else */
917#endif /* __osf__ else */
918#endif /* LOADSTUB else */
919#endif /* __APPLE__ else */
920#endif /* __GNU__ else */
921#endif /* linux else */
922#endif /* SYSV && i386 else */
923
924static void xload_error(const char *str1, const char *str2)
925{
926    (void) fprintf(stderr,"xload: %s %s\n", str1, str2);
927#ifdef __bsdi__
928    if (kd)
929	kvm_close(kd);
930#endif
931    exit(-1);
932}
933
934#endif /* END of __CYGWIN__ */
935