📄 getloadavg.c
字号:
static processor_set_t default_set;static int getloadavg_initialized;# endif /* NeXT */# ifdef UMAXstatic unsigned int cpus = 0;static unsigned int samples;# endif /* UMAX */# ifdef DGUXstatic struct dg_sys_info_load_info load_info; /* what-a-mouthful! */# endif /* DGUX */# ifdef LOAD_AVE_TYPE/* File descriptor open to /dev/kmem or VMS load ave driver. */static int channel;/* Nonzero iff channel is valid. */static int getloadavg_initialized;/* Offset in kmem to seek to read load average, or 0 means invalid. */static long offset;# if !defined(VMS) && !defined(sgi) && !defined(__linux__)static struct nlist nl[2];# endif /* Not VMS or sgi */# ifdef SUNOS_5static kvm_t *kd;# endif /* SUNOS_5 */# endif /* LOAD_AVE_TYPE *//* Put the 1 minute, 5 minute and 15 minute load averages into the first NELEM elements of LOADAVG. Return the number written (never more than 3, but may be less than NELEM), or -1 if an error occurred. */int getloadavg(double loadavg[], int nelem){ int elem = 0; /* Return value. */# ifdef NO_GET_LOAD_AVG# define LDAV_DONE /* Set errno to zero to indicate that there was no particular error; this function just can't work at all on this system. */ errno = 0; elem = -1;# endif # if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT) /* Use libkstat because we don't have to be root. */# define LDAV_DONE kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *kn; if ((kc = kstat_open()) == 0) { return -1; } if ((ksp = kstat_lookup(kc, "unix", 0, "system_misc")) == 0) { out_kstat: kstat_close(kc); return -1; } if (kstat_read(kc, ksp, 0) == -1) { goto out_kstat; } if ((kn = kstat_data_lookup(ksp, "avenrun_1min")) == 0) { /* Return -1 if no load average information is available. */ nelem = 0; elem = -1; } else if (nelem >= 1) { loadavg[elem++] = (double) kn->value.ul / FSCALE; } if (nelem >= 2) { kn = kstat_data_lookup(ksp, "avenrun_5min"); if (kn != 0) { loadavg[elem++] = (double) kn->value.ul / FSCALE; if (nelem >= 3) { kn = kstat_data_lookup(ksp, "avenrun_15min"); if (kn != 0) { loadavg[elem++] = (double) kn->value.ul / FSCALE; } } } } kstat_close(kc);# endif /* HAVE_LIBKSTAT */# if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC) /* Use pstat_getdynamic() because we don't have to be root. */# define LDAV_DONE# undef LOAD_AVE_TYPE struct pst_dynamic dyn_info; if (pstat_getdynamic(&dyn_info, sizeof dyn_info, 0, 0) < 0) { return -1; } if (nelem > 0) { loadavg[elem++] = dyn_info.psd_avg_1_min; } if (nelem > 1) { loadavg[elem++] = dyn_info.psd_avg_5_min; } if (nelem > 2) { loadavg[elem++] = dyn_info.psd_avg_15_min; }# endif /* hpux && HAVE_PSTAT_GETDYNAMIC */# if !defined (LDAV_DONE) && defined (__linux__)# define LDAV_DONE# undef LOAD_AVE_TYPE # ifndef LINUX_LDAV_FILE# define LINUX_LDAV_FILE "/proc/loadavg"# endif char ldavgbuf[40]; double load_ave[3]; int fd; ssize_t count; if ((fd = open(LINUX_LDAV_FILE, O_RDONLY | O_NOFOLLOW)) == -1) { return -1; } count = read(fd, ldavgbuf, (size_t) 40U); (void) close(fd); if (count <= (ssize_t) 0) { return -1; } count = sscanf(ldavgbuf, "%lf %lf %lf", &load_ave[0], &load_ave[1], &load_ave[2]); if (count < 1) { return -1; } for (elem = 0; elem < nelem && elem < count; elem++) { loadavg[elem] = load_ave[elem]; } return elem;# endif /* __linux__ */# if !defined (LDAV_DONE) && defined (__NetBSD__)# define LDAV_DONE# undef LOAD_AVE_TYPE# ifndef NETBSD_LDAV_FILE# define NETBSD_LDAV_FILE "/kern/loadavg"# endif FILE *fp; unsigned long int load_ave[3], scale; int count; if ((fp = fopen(NETBSD_LDAV_FILE, "r")) == NULL) { return -1; } count = fscanf(fp, "%lu %lu %lu %lu\n", &load_ave[0], &load_ave[1], &load_ave[2], &scale); (void) fclose(fp); if (count != 4) { return -1; } for (elem = 0; elem < nelem; elem++) { loadavg[elem] = (double) load_ave[elem] / (double) scale; } return elem;# endif /* __NetBSD__ */# if !defined (LDAV_DONE) && defined (NeXT)# define LDAV_DONE /* The NeXT code was adapted from iscreen 3.2. */ host_t host; struct processor_set_basic_info info; unsigned info_count; /* We only know how to get the 1-minute average for this system, so even if the caller asks for more than 1, we only return 1. */ if (!getloadavg_initialized) { if (processor_set_default(host_self(), &default_set) == KERN_SUCCESS) { getloadavg_initialized = 1; } } if (getloadavg_initialized) { info_count = PROCESSOR_SET_BASIC_INFO_COUNT; if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, &host, (processor_set_info_t) &info, &info_count) != KERN_SUCCESS) { getloadavg_initialized = 0; } else { if (nelem > 0) { loadavg[elem++] = (double) info.load_average / LOAD_SCALE; } } } if (!getloadavg_initialized) { return -1; }# endif /* NeXT */# if !defined (LDAV_DONE) && defined (UMAX)# define LDAV_DONE /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not have a /dev/kmem. Information about the workings of the running kernel can be gathered with inq_stats system calls. We only know how to get the 1-minute average for this system. */ struct proc_summary proc_sum_data; struct stat_descr proc_info; double load; register unsigned int i, j; if (cpus == 0) { register unsigned int c, i; struct cpu_config conf; struct stat_descr desc; desc.sd_next = 0; desc.sd_subsys = SUBSYS_CPU; desc.sd_type = CPUTYPE_CONFIG; desc.sd_addr = (char *) &conf; desc.sd_size = sizeof conf; if (inq_stats(1, &desc)) { return -1; } c = 0; for (i = 0; i < conf.config_maxclass; ++i) { struct class_stats stats; bzero((char *) &stats, sizeof stats); desc.sd_type = CPUTYPE_CLASS; desc.sd_objid = i; desc.sd_addr = (char *) &stats; desc.sd_size = sizeof stats; if (inq_stats(1, &desc)) { return -1; } c += stats.class_numcpus; } cpus = c; samples = cpus < 2 ? 3 : (2 * cpus / 3); } proc_info.sd_next = 0; proc_info.sd_subsys = SUBSYS_PROC; proc_info.sd_type = PROCTYPE_SUMMARY; proc_info.sd_addr = (char *) &proc_sum_data; proc_info.sd_size = sizeof (struct proc_summary); proc_info.sd_sizeused = 0; if (inq_stats(1, &proc_info) != 0) { return -1; } load = proc_sum_data.ps_nrunnable; j = 0; for (i = samples - 1; i > 0; --i) { load += proc_sum_data.ps_nrun[j]; if (j++ == PS_NRUNSIZE) { j = 0; } } if (nelem > 0) { loadavg[elem++] = load / samples / cpus; }# endif /* UMAX */# if !defined (LDAV_DONE) && defined (DGUX)# define LDAV_DONE /* This call can return -1 for an error, but with good args it's not supposed to fail. The first argument is for no apparent reason of type `long int *'. */ dg_sys_info((long int *) &load_info, DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0); if (nelem > 0) { loadavg[elem++] = load_info.one_minute; } if (nelem > 1) { loadavg[elem++] = load_info.five_minute; } if (nelem > 2) { loadavg[elem++] = load_info.fifteen_minute; }# endif /* DGUX */# if !defined (LDAV_DONE) && defined (apollo)# define LDAV_DONE /* * Apollo code from lisch@mentorg.com (Ray Lischner). * * This system call is not documented. The load average is obtained as * three long integers, for the load average over the past minute, * five minutes, and fifteen minutes. Each value is a scaled integer, * with 16 bits of integer part and 16 bits of fraction part. * * I'm not sure which operating system first supported this system call, * but I know that SR10.2 supports it. */ extern void proc1_$get_loadav(); unsigned long load_ave[3]; proc1_$get_loadav(load_ave); if (nelem > 0) { loadavg[elem++] = load_ave[0] / 65536.0; } if (nelem > 1) { loadavg[elem++] = load_ave[1] / 65536.0; } if (nelem > 2) { loadavg[elem++] = load_ave[2] / 65536.0; }# endif /* apollo */# if !defined (LDAV_DONE) && defined (OSF_MIPS)# define LDAV_DONE struct tbl_loadavg load_ave; table(TBL_LOADAVG, 0, &load_ave, 1, sizeof load_ave); loadavg[elem++] = (load_ave.tl_lscale == 0 ? load_ave.tl_avenrun.d[0] : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));# endif /* OSF_MIPS */# if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32))# define LDAV_DONE /* A faithful emulation is going to have to be saved for a rainy day. */ for ( ; elem < nelem; elem++) { loadavg[elem] = 0.0; }# endif /* __MSDOS__ || WINDOWS32 */# if !defined (LDAV_DONE) && defined (OSF_ALPHA)# define LDAV_DONE struct tbl_loadavg load_ave; table(TBL_LOADAVG, 0, &load_ave, 1, sizeof load_ave); for (elem = 0; elem < nelem; elem++) { loadavg[elem] = (load_ave.tl_lscale == 0 ? load_ave.tl_avenrun.d[elem] : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale)); }# endif /* OSF_ALPHA */# if !defined (LDAV_DONE) && defined (VMS) /* VMS specific code -- read from the Load Ave driver. */ LOAD_AVE_TYPE load_ave[3];# ifdef eunice struct { int dsc$w_length; char *dsc$a_pointer; } descriptor;# endif /* Attempt to open the channel. */# ifdef eunice descriptor.dsc$w_length = 18; descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE";# else $DESCRIPTOR(descriptor, "LAV0:");# endif if (sys$assign(&descriptor, &channel, 0, 0) & 1) { return -1; } /* Read the load average vector. */ if (!(sys$qiow(0, channel, IO$_READVBLK, 0, 0, 0, load_ave, 12, 0, 0, 0, 0) & 1)) { sys$dassgn(channel); return -1; } sys$dassgn(channel); # endif /* VMS */# if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS) /* UNIX-specific code -- read the average from /dev/kmem. */# define LDAV_PRIVILEGED /* This code requires special installation. */ LOAD_AVE_TYPE load_ave[3]; /* Get the address of LDAV_SYMBOL. */ if (offset == 0L) {# ifndef sgi# ifndef NLIST_STRUCT strncpy(nl[0].n_name, LDAV_SYMBOL, sizeof (nl[0].n_name) - (size_t) 1U); (nl[0].n_name)[sizeof (nl[0].n_name) - (size_t) 1U] = 0; *(nl[1].n_name) = 0;# else /* NLIST_STRUCT */# ifdef NLIST_NAME_UNION nl[0].n_un.n_name = LDAV_SYMBOL; nl[1].n_un.n_name = 0;# else /* not NLIST_NAME_UNION */ nl[0].n_name = LDAV_SYMBOL; nl[1].n_name = 0;# endif /* not NLIST_NAME_UNION */# endif /* NLIST_STRUCT */ # ifndef SUNOS_5 if (# if !(defined (_AIX) && !defined (ps2)) nlist(KERNEL_FILE, nl)# else /* _AIX */ knlist(nl, 1, sizeof nl[0])# endif >= 0) { /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */# ifdef FIXUP_KERNEL_SYMBOL_ADDR FIXUP_KERNEL_SYMBOL_ADDR(nl);# endif offset = nl[0].n_value; }# endif /* !SUNOS_5 */# else /* sgi */ int ldav_off; ldav_off = sysmp(MP_KERNADDR, MPKA_AVENRUN); if (ldav_off != -1) { offset = (long) ldav_off & 0x7fffffff; }# endif /* sgi */ }# ifndef SUNOS_5 if ((channel = open("/dev/kmem", 0)) == -1) { return -1; } /* Set the channel to close on exec, so it does not litter any child's descriptor table. */# ifdef FD_SETFD# ifndef FD_CLOEXEC# define FD_CLOEXEC 1# endif (void) fcntl(channel, F_SETFD, FD_CLOEXEC);# endif# else /* SUNOS_5 */ /* We pass 0 for the kernel, corefile, and swapfile names to use the currently running kernel. */ if ((kd = kvm_open(0, 0, 0, O_RDONLY, 0)) == 0) { return -1; } /* nlist the currently running kernel. */ kvm_nlist(kd, nl); offset = nl[0].n_value;# endif /* SUNOS_5 */ /* No offset => don't read */ if (offset == 0L) {# ifndef SUNOS_5 (void) close(channel);# else kvm_close(kd);# endif return -1; } /* Try to read the load. */# ifndef SUNOS_5 if (lseek(channel, offset, SEEK_SET) == -1L || read(channel, (char *) load_ave, sizeof load_ave) != sizeof load_ave) { close(channel); return -1; }# else /* SUNOS_5 */ if (kvm_read(kd, offset, (char *) load_ave, sizeof load_ave) != sizeof load_ave) { kvm_close(kd); return -1; }# endif /* SUNOS_5 */# endif /* LOAD_AVE_TYPE and not VMS */# if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS. */ if (nelem > 0) { loadavg[elem++] = LDAV_CVT(load_ave[0]); } if (nelem > 1) { loadavg[elem++] = LDAV_CVT(load_ave[1]); } if (nelem > 2) { loadavg[elem++] = LDAV_CVT(load_ave[2]); }# define LDAV_DONE# endif /* !LDAV_DONE && LOAD_AVE_TYPE */# ifdef LDAV_DONE return elem;# else /* Set errno to zero to indicate that there was no particular error; this function just can't work at all on this system. */ errno = 0; return -1;# endif}#endif /* ! HAVE_GETLOADAVG */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -