⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sysinfo.c

📁 Linux下进程监控相关源代码
💻 C
字号:
/***********************************************************************\*   Copyright (C) 1992-1998 by Michael K. Johnson, johnsonm@redhat.com **                                                                      **      This file is placed under the conditions of the GNU Library     **      General Public License, version 2, or any later version.        **      See file COPYING for information on distribution conditions.    *\***********************************************************************//* File for parsing top-level /proc entities. */#include "proc/sysinfo.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <fcntl.h>#include "proc/version.h"#define BAD_OPEN_MESSAGE					\"Error: /proc must be mounted\n"				\"  To mount /proc at boot you need an /etc/fstab line like:\n"	\"      /proc   /proc   proc    defaults\n"			\"  In the meantime, mount /proc /proc -t proc\n"#define STAT_FILE    "/proc/stat"static int stat_fd = -1;#define UPTIME_FILE  "/proc/uptime"static int uptime_fd = -1;#define LOADAVG_FILE "/proc/loadavg"static int loadavg_fd = -1;#define MEMINFO_FILE "/proc/meminfo"static int meminfo_fd = -1;static char buf[1024];/* This macro opens filename only if necessary and seeks to 0 so * that successive calls to the functions are more efficient. * It also reads the current contents of the file into the global buf. */#define FILE_TO_BUF(filename, fd) do{				\    static int n;						\    if (fd == -1 && (fd = open(filename, O_RDONLY)) == -1) {	\	fprintf(stderr, BAD_OPEN_MESSAGE);			\	close(fd);						\	_exit(1);						\    }								\    lseek(fd, 0L, SEEK_SET);					\    if ((n = read(fd, buf, sizeof buf - 1)) < 0) {		\	perror(filename);					\	close(fd);						\	fd = -1;						\	return 0;						\    }								\    buf[n] = '\0';						\}while(0)#define SET_IF_DESIRED(x,y)  if(x) *(x) = (y)	/* evals 'x' twice *//***********************************************************************/int uptime(double *uptime_secs, double *idle_secs) {    double up=0, idle=0;    FILE_TO_BUF(UPTIME_FILE,uptime_fd);    if (sscanf(buf, "%lf %lf", &up, &idle) < 2) {	fprintf(stderr, "bad data in " UPTIME_FILE "\n");	return 0;    }    SET_IF_DESIRED(uptime_secs, up);    SET_IF_DESIRED(idle_secs, idle);    return up;	/* assume never be zero seconds in practice */}/*********************************************************************** * Some values in /proc are expressed in units of 1/HZ seconds, where HZ * is the kernel clock tick rate. One of these units is called a jiffy. * The HZ value used in the kernel may vary according to hacker desire. * According to Linus Torvalds, this is not true. He considers the values * in /proc as being in architecture-dependant units that have no relation * to the kernel clock tick rate. Examination of the kernel source code * reveals that opinion as wishful thinking. * * In any case, we need the HZ constant as used in /proc. (the real HZ value * may differ, but we don't care) There are several ways we could get HZ: * * 1. Include the kernel header file. If it changes, recompile this library. * 2. Use the sysconf() function. When HZ changes, recompile the C library! * 3. Ask the kernel. This is obviously correct... * * Linus Torvalds won't let us ask the kernel, because he thinks we should * not know the HZ value. Oh well, we don't have to listen to him. * Someone smuggled out the HZ value. :-) * * This code should work fine, even if Linus fixes the kernel to match his * stated behavior. The code only fails in case of a partial conversion. * * (Albert Cahalan, I think, wrote the rant above.) * * Unfortunately, this code does not always succeed.  Anyone who can do * better is welcome to do so... */unsigned long Hertz;static int init_Hertz_value(void) __attribute__((constructor));static int init_Hertz_value(void){  unsigned long user_j, nice_j, sys_j, other_j;  /* jiffies (clock ticks) */  double up_1, up_2, seconds;  unsigned long jiffies, h;  int i = 0;  do{    FILE_TO_BUF(UPTIME_FILE,uptime_fd);  sscanf(buf, "%lf", &up_1);    /* uptime(&up_1, NULL); */    FILE_TO_BUF(STAT_FILE,stat_fd);    /* If we are SMP, then the first line is the sum of jiffies by all CPUs */    /* In that case, skip it and use the jiffies of the first CPU instead. */    /* On a single-CPU machine, the 2nd sscanf should harmlessly fail. */    sscanf(buf, "cpu %lu %lu %lu %lu\n%n",	   &user_j, &nice_j, &sys_j, &other_j, &i);    sscanf(buf+i, "cpu0 %lu %lu %lu %lu", &user_j, &nice_j, &sys_j, &other_j);    FILE_TO_BUF(UPTIME_FILE,uptime_fd);  sscanf(buf, "%lf", &up_2);    /* uptime(&up_2, NULL); */  } while((long)( (up_2-up_1)*1000.0/up_1 )); /* want under 0.1% error */  jiffies = user_j + nice_j + sys_j + other_j;  seconds = (up_1 + up_2) / 2;  h = (unsigned long)( (double)jiffies/seconds );  switch(h){  case   48 ...   52 :  Hertz =   50; break;  case   58 ...   62 :  Hertz =   60; break;  case   95 ...  105 :  Hertz =  100; break; /* normal Linux */  case  124 ...  132 :  Hertz =  128; break;  case  195 ...  204 :  Hertz =  200; break; /* normal << 1 */  case  253 ...  260 :  Hertz =  256; break;  case  393 ...  408 :  Hertz =  400; break; /* normal << 2 */  case  790 ...  808 :  Hertz =  800; break; /* normal << 3 */  case  990 ... 1010 :  Hertz = 1000; break;  case 1015 ... 1035 :  Hertz = 1024; break; /* Alpha */  default:#ifdef HZ    Hertz = (unsigned long)HZ;    /* <asm/param.h> */#else    Hertz = (sizeof(long)==sizeof(int)) ? 100UL : 1024UL;#endif#if 0 /* This ends up causing more harm than good.  :-( */    fprintf(stderr, "Unknown HZ value! (%ld) Assume %ld.\n", h, Hertz);#endif  }  return 0; /* useless, but FILE_TO_BUF has a return in it */}/***********************************************************************/#define JT unsigned longint four_cpu_numbers(JT *uret, JT *nret, JT *sret, JT *iret) {    static JT u, n, s, i;    JT user_j, nice_j, sys_j, idle_j;    FILE_TO_BUF(STAT_FILE,stat_fd);    sscanf(buf, "cpu %lu %lu %lu %lu", &user_j, &nice_j, &sys_j, &idle_j);    SET_IF_DESIRED(uret, user_j-u);    SET_IF_DESIRED(nret, nice_j-n);    SET_IF_DESIRED(sret,  sys_j-s);    SET_IF_DESIRED(iret, idle_j-i);    u=user_j;    n=nice_j;    s=sys_j;    i=idle_j;    return 0;}#undef JT/***********************************************************************/int loadavg(double *av1, double *av5, double *av15) {    double avg_1=0, avg_5=0, avg_15=0;        FILE_TO_BUF(LOADAVG_FILE,loadavg_fd);    if (sscanf(buf, "%lf %lf %lf", &avg_1, &avg_5, &avg_15) < 3) {	fprintf(stderr, "bad data in " LOADAVG_FILE "\n");	exit(1);    }    SET_IF_DESIRED(av1,  avg_1);    SET_IF_DESIRED(av5,  avg_5);    SET_IF_DESIRED(av15, avg_15);    return 1;}/************************************************************************ * The following /proc/meminfo parsing routine assumes the following format: * [ <label> ... ]				# header lines * [ <label> ] <num> [ <num> ... ]		# table rows * [ repeats of above line ] *  * Any lines with fewer <num>s than <label>s get trailing <num>s set to zero. * The return value is a NULL terminated unsigned** which is the table of * numbers without labels.  Convenient enumeration constants for the major and * minor dimensions are available in the header file.  Note that this version * requires that labels do not contain digits.  It is readily extensible to * labels which do not *begin* with digits, though. */#define MAX_ROW 3	/* these are a little liberal for flexibility */#define MAX_COL 7unsigned long long **meminfo(void){    static unsigned long long *row[MAX_ROW + 1];		/* row pointers */    static unsigned long long num[MAX_ROW * MAX_COL];	/* number storage */    char *p;    char fieldbuf[12];		/* bigger than any field name or size in kb */    int i, j, k, l;        FILE_TO_BUF(MEMINFO_FILE,meminfo_fd);    if (!row[0])				/* init ptrs 1st time through */	for (i=0; i < MAX_ROW; i++)		/* std column major order: */	    row[i] = num + MAX_COL*i;		/* A[i][j] = A + COLS*i + j */    p = buf;    for (i=0; i < MAX_ROW; i++)			/* zero unassigned fields */	for (j=0; j < MAX_COL; j++)	    row[i][j] = 0;    if (linux_version_code < LINUX_VERSION(2,0,0)) {    	for (i=0; i < MAX_ROW && *p; i++) {                /* loop over rows */		while(*p && !isdigit(*p)) p++;          /* skip chars until a digit */		for (j=0; j < MAX_COL && *p; j++) {     /* scanf column-by-column */		    l = sscanf(p, "%u%n", row[i] + j, &k);		    p += k;                             /* step over used buffer */		    if (*p == '\n' || l < 1)            /* end of line/buffer */			break;		}	}    }    else {	    while(*p) {	    	sscanf(p,"%11s%n",fieldbuf,&k);	    	if(!strcmp(fieldbuf,"MemTotal:")) {	    		p+=k;	    		sscanf(p," %Ld",&(row[meminfo_main][meminfo_total]));	    		row[meminfo_main][meminfo_total]<<=10;	    		while(*p++ != '\n');	    	}	    	else if(!strcmp(fieldbuf,"MemFree:")) {	    		p+=k;	    		sscanf(p," %Ld",&(row[meminfo_main][meminfo_free]));	    		row[meminfo_main][meminfo_free]<<=10;	    		while(*p++ != '\n');	    	}	    	else if(!strcmp(fieldbuf,"MemShared:")) {	    		p+=k;	    		sscanf(p," %Ld",&(row[meminfo_main][meminfo_shared]));	    		row[meminfo_main][meminfo_shared]<<=10;	    		while(*p++ != '\n');	    	}	    	else if(!strcmp(fieldbuf,"Buffers:")) {	    		p+=k;	    		sscanf(p," %Ld",&(row[meminfo_main][meminfo_buffers]));	    		row[meminfo_main][meminfo_buffers]<<=10;	    		while(*p++ != '\n');	    	}	    	else if(!strcmp(fieldbuf,"Cached:")) {	    		p+=k;    			sscanf(p," %Ld",&(row[meminfo_main][meminfo_cached]));    			row[meminfo_main][meminfo_cached]<<=10;    			while(*p++ != '\n');    		}    		else if(!strcmp(fieldbuf,"SwapTotal:")) {    			p+=k;    			sscanf(p," %Ld",&(row[meminfo_swap][meminfo_total]));    			row[meminfo_swap][meminfo_total]<<=10;    			while(*p++ != '\n');    		}    		else if(!strcmp(fieldbuf,"SwapFree:")) {    			p+=k;    			sscanf(p," %Ld",&(row[meminfo_swap][meminfo_free]));    			row[meminfo_swap][meminfo_free]<<=10;    			while(*p++ != '\n');    		}    		else    			while(*p++ != '\n'); /* ignore lines we don't understand */    	}		    	row[meminfo_swap][meminfo_used]=row[meminfo_swap][meminfo_total]-row[meminfo_swap][meminfo_free];    	row[meminfo_main][meminfo_used]=row[meminfo_main][meminfo_total]-row[meminfo_main][meminfo_free];    }    return row;					/* NULL return ==> error */}/************************************************************************** * shorthand for read_table("/proc/meminfo")[meminfo_main][meminfo_total] */unsigned read_total_main(void) {    unsigned long long** mem;    return (mem = meminfo()) ? mem[meminfo_main][meminfo_total] : -1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -