From 06e111a6efbbe275e8f7c364ff8e5955d1ab75f0 Mon Sep 17 00:00:00 2001 From: Dan Nicolaescu Date: Fri, 19 Dec 2008 19:50:35 +0000 Subject: [PATCH] Reorganize implementation of Flist_system_processes and Fsystem_process_attributes. No functional changes. * process.c: Don't #include pwd.h, grp.h and limits.h. (Flist_system_processes): Just call list_system_processes. (Fsystem_process_attributes): Just call system_process_attributes. (procfs_list_system_processes, time_from_jiffies) (ltime_from_jiffies, get_up_time, procfs_ttyname, MAJOR, MINOR) (procfs_get_total_memory, procfs_system_process_attributes): Move ... * sysdep.c: ... here. Include pwd.h, grp.h and limits.h. (list_system_processes): Rename from procfs_list_system_processes. Enclose in #ifdef HAVE_PROCFS. Provide a do nothing implementation. (system_process_attributes): Rename from procfs_list_system_processes. (ltime_from_jiffies, get_up_time, procfs_ttyname, MAJOR, MINOR) (procfs_get_total_memory): Enclose in #ifdef GNU_LINUX. * w32.c (list_system_processes): Rename from w32_list_system_processes. (system_process_attributes): Rename from w32_system_process_attributes. * s/gnu-linux.h (LISTPROC, PROCATTR): Remove. * process.h (w32_list_system_processes) (w32_system_process_attributes): Remove. (list_system_processes, system_process_attributes): New prototypes. * config.nt (LISTPROC, PROCATTR): Remove. --- admin/CPP-DEFINES | 2 - nt/ChangeLog | 4 + nt/config.nt | 4 - src/ChangeLog | 32 ++++ src/process.c | 439 +-------------------------------------------- src/process.h | 6 +- src/s/gnu-linux.h | 4 +- src/sysdep.c | 444 ++++++++++++++++++++++++++++++++++++++++++++++ src/w32.c | 4 +- 9 files changed, 488 insertions(+), 451 deletions(-) diff --git a/admin/CPP-DEFINES b/admin/CPP-DEFINES index de82ddf421..b2e5bdb314 100644 --- a/admin/CPP-DEFINES +++ b/admin/CPP-DEFINES @@ -40,8 +40,6 @@ FRAME_WINDOW_P A GUI frame (like X, w32, etc.) ** Support for accessing other processes on the system ** HAVE_PROCFS The /proc filesystem is supported. -LISTPROC A function that returns a list of PIDs of system processes. -PROCATTR A function that returns attributes of a process. ** Compile-time options ** diff --git a/nt/ChangeLog b/nt/ChangeLog index d259c0ce04..0739de0dd0 100644 --- a/nt/ChangeLog +++ b/nt/ChangeLog @@ -1,3 +1,7 @@ +2008-12-19 Dan Nicolaescu + + * config.nt (LISTPROC, PROCATTR): Remove. + 2008-08-09 Eli Zaretskii * config.nt (LISTPROC, PROCATTR): New macros. diff --git a/nt/config.nt b/nt/config.nt index dd37960d48..dea980ece1 100644 --- a/nt/config.nt +++ b/nt/config.nt @@ -464,10 +464,6 @@ void w32_abort (void) NO_RETURN; #endif #endif -/* Support for listing processes and their attributes. */ -#define LISTPROC w32_list_system_processes -#define PROCATTR w32_system_process_attributes - /* Prevent accidental use of features unavailable in older Windows versions we still support. */ #define _WIN32_WINNT 0x0400 diff --git a/src/ChangeLog b/src/ChangeLog index 53654f413f..4bc6d54c1a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,35 @@ +2008-12-19 Dan Nicolaescu + + Reorganize implementation of Flist_system_processes and + Fsystem_process_attributes. No functional changes. + * process.c: Don't #include pwd.h, grp.h and limits.h. + (Flist_system_processes): Just call list_system_processes. + (Fsystem_process_attributes): Just call system_process_attributes. + (procfs_list_system_processes, time_from_jiffies) + (ltime_from_jiffies, get_up_time, procfs_ttyname, MAJOR, MINOR) + (procfs_get_total_memory, procfs_system_process_attributes): Move ... + + * sysdep.c: ... here. Include pwd.h, grp.h and limits.h. + (list_system_processes): Rename from + procfs_list_system_processes. Enclose in #ifdef HAVE_PROCFS. + Provide a do nothing implementation. + (system_process_attributes): Rename from + procfs_list_system_processes. + (ltime_from_jiffies, get_up_time, procfs_ttyname, MAJOR, MINOR) + (procfs_get_total_memory): Enclose in #ifdef GNU_LINUX. + + * w32.c (list_system_processes): Rename from + w32_list_system_processes. + (system_process_attributes): Rename from + w32_system_process_attributes. + + * s/gnu-linux.h (LISTPROC, PROCATTR): Remove. + + * process.h (w32_list_system_processes) + (w32_system_process_attributes): Remove. + (list_system_processes, system_process_attributes): New + prototypes. + 2008-12-19 Kenichi Handa * xfont.c (xfont_decode_coding_xlfd): New function. diff --git a/src/process.c b/src/process.c index 0f3373b5db..4172ffe1f5 100644 --- a/src/process.c +++ b/src/process.c @@ -33,8 +33,6 @@ along with GNU Emacs. If not, see . */ #ifdef subprocesses #include -#include -#include #include #include #include /* some typedefs are used in sys/file.h */ @@ -44,11 +42,6 @@ along with GNU Emacs. If not, see . */ #include #endif -#ifdef HAVE_PWD_H -#include -#include -#endif - #ifdef HAVE_UNISTD_H #include #endif @@ -104,10 +97,6 @@ along with GNU Emacs. If not, see . */ #include #endif -#ifdef HAVE_LIMITS_H -#include -#endif /* HAVE_LIMITS_H */ - #include "lisp.h" #include "systime.h" #include "systty.h" @@ -7073,422 +7062,6 @@ keyboard_bit_set (mask) /* Enumeration of and access to system processes a-la ps(1). */ -#if HAVE_PROCFS - -/* Process enumeration and access via /proc. */ - -static Lisp_Object -procfs_list_system_processes () -{ - Lisp_Object procdir, match, proclist, next; - struct gcpro gcpro1, gcpro2; - register Lisp_Object tail; - - GCPRO2 (procdir, match); - /* For every process on the system, there's a directory in the - "/proc" pseudo-directory whose name is the numeric ID of that - process. */ - procdir = build_string ("/proc"); - match = build_string ("[0-9]+"); - proclist = directory_files_internal (procdir, Qnil, match, Qt, 0, Qnil); - - /* `proclist' gives process IDs as strings. Destructively convert - each string into a number. */ - for (tail = proclist; CONSP (tail); tail = next) - { - next = XCDR (tail); - XSETCAR (tail, Fstring_to_number (XCAR (tail), Qnil)); - } - UNGCPRO; - - /* directory_files_internal returns the files in reverse order; undo - that. */ - proclist = Fnreverse (proclist); - return proclist; -} - -static void -time_from_jiffies (unsigned long long tval, long hz, - time_t *sec, unsigned *usec) -{ - unsigned long long ullsec; - - *sec = tval / hz; - ullsec = *sec; - tval -= ullsec * hz; - /* Careful: if HZ > 1 million, then integer division by it yields zero. */ - if (hz <= 1000000) - *usec = tval * 1000000 / hz; - else - *usec = tval / (hz / 1000000); -} - -static Lisp_Object -ltime_from_jiffies (unsigned long long tval, long hz) -{ - time_t sec; - unsigned usec; - - time_from_jiffies (tval, hz, &sec, &usec); - - return list3 (make_number ((sec >> 16) & 0xffff), - make_number (sec & 0xffff), - make_number (usec)); -} - -static void -get_up_time (time_t *sec, unsigned *usec) -{ - FILE *fup; - - *sec = *usec = 0; - - BLOCK_INPUT; - fup = fopen ("/proc/uptime", "r"); - - if (fup) - { - double uptime, idletime; - - /* The numbers in /proc/uptime use C-locale decimal point, but - we already set ourselves to the C locale (see `fixup_locale' - in emacs.c). */ - if (2 <= fscanf (fup, "%lf %lf", &uptime, &idletime)) - { - *sec = uptime; - *usec = (uptime - *sec) * 1000000; - } - fclose (fup); - } - UNBLOCK_INPUT; -} - -#define MAJOR(d) (((unsigned)(d) >> 8) & 0xfff) -#define MINOR(d) (((unsigned)(d) & 0xff) | (((unsigned)(d) & 0xfff00000) >> 12)) - -static Lisp_Object -procfs_ttyname (rdev) -{ - FILE *fdev = NULL; - char name[PATH_MAX]; - - BLOCK_INPUT; - fdev = fopen ("/proc/tty/drivers", "r"); - - if (fdev) - { - unsigned major; - unsigned long minor_beg, minor_end; - char minor[25]; /* 2 32-bit numbers + dash */ - char *endp; - - while (!feof (fdev) && !ferror (fdev)) - { - if (3 <= fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor) - && major == MAJOR (rdev)) - { - minor_beg = strtoul (minor, &endp, 0); - if (*endp == '\0') - minor_end = minor_beg; - else if (*endp == '-') - minor_end = strtoul (endp + 1, &endp, 0); - else - continue; - - if (MINOR (rdev) >= minor_beg && MINOR (rdev) <= minor_end) - { - sprintf (name + strlen (name), "%lu", MINOR (rdev)); - break; - } - } - } - fclose (fdev); - } - UNBLOCK_INPUT; - return build_string (name); -} - -static unsigned long -procfs_get_total_memory (void) -{ - FILE *fmem = NULL; - unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */ - - BLOCK_INPUT; - fmem = fopen ("/proc/meminfo", "r"); - - if (fmem) - { - unsigned long entry_value; - char entry_name[20]; /* the longest I saw is 13+1 */ - - while (!feof (fmem) && !ferror (fmem)) - { - if (2 <= fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value) - && strcmp (entry_name, "MemTotal:") == 0) - { - retval = entry_value; - break; - } - } - fclose (fmem); - } - UNBLOCK_INPUT; - return retval; -} - -static Lisp_Object -procfs_system_process_attributes (pid) - Lisp_Object pid; -{ - char procfn[PATH_MAX], fn[PATH_MAX]; - struct stat st; - struct passwd *pw; - struct group *gr; - long clocks_per_sec; - char *procfn_end; - char procbuf[1025], *p, *q; - int fd; - ssize_t nread; - const char *cmd = NULL; - char *cmdline = NULL; - size_t cmdsize = 0, cmdline_size; - unsigned char c; - int proc_id, ppid, uid, gid, pgrp, sess, tty, tpgid, thcount; - unsigned long long utime, stime, cutime, cstime, start; - long priority, nice, rss; - unsigned long minflt, majflt, cminflt, cmajflt, vsize; - time_t sec; - unsigned usec; - EMACS_TIME tnow, tstart, tboot, telapsed,ttotal; - double pcpu, pmem; - Lisp_Object attrs = Qnil; - Lisp_Object cmd_str, decoded_cmd, tem; - struct gcpro gcpro1, gcpro2; - EMACS_INT uid_eint, gid_eint; - - CHECK_NUMBER_OR_FLOAT (pid); - proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid); - sprintf (procfn, "/proc/%lu", proc_id); - if (stat (procfn, &st) < 0) - return attrs; - - GCPRO2 (attrs, decoded_cmd); - - /* euid egid */ - uid = st.st_uid; - /* Use of EMACS_INT stops GCC whining about limited range of data type. */ - uid_eint = uid; - attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid_eint)), attrs); - BLOCK_INPUT; - pw = getpwuid (uid); - UNBLOCK_INPUT; - if (pw) - attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs); - - gid = st.st_gid; - gid_eint = gid; - attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid_eint)), attrs); - BLOCK_INPUT; - gr = getgrgid (gid); - UNBLOCK_INPUT; - if (gr) - attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs); - - strcpy (fn, procfn); - procfn_end = fn + strlen (fn); - strcpy (procfn_end, "/stat"); - fd = emacs_open (fn, O_RDONLY, 0); - if (fd >= 0 && (nread = emacs_read (fd, procbuf, sizeof(procbuf) - 1)) > 0) - { - procbuf[nread] = '\0'; - p = procbuf; - - p = strchr (p, '('); - if (p != NULL) - { - q = strrchr (p + 1, ')'); - /* comm */ - if (q != NULL) - { - cmd = p + 1; - cmdsize = q - cmd; - } - } - else - q = NULL; - if (cmd == NULL) - { - cmd = "???"; - cmdsize = 3; - } - /* Command name is encoded in locale-coding-system; decode it. */ - cmd_str = make_unibyte_string (cmd, cmdsize); - decoded_cmd = code_convert_string_norecord (cmd_str, - Vlocale_coding_system, 0); - attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs); - - if (q) - { - EMACS_INT ppid_eint, pgrp_eint, sess_eint, tpgid_eint, thcount_eint; - p = q + 2; - /* state ppid pgrp sess tty tpgid . minflt cminflt majflt cmajflt utime stime cutime cstime priority nice thcount . start vsize rss */ - sscanf (p, "%c %d %d %d %d %d %*u %lu %lu %lu %lu %Lu %Lu %Lu %Lu %ld %ld %d %*d %Lu %lu %ld", - &c, &ppid, &pgrp, &sess, &tty, &tpgid, - &minflt, &cminflt, &majflt, &cmajflt, - &utime, &stime, &cutime, &cstime, - &priority, &nice, &thcount, &start, &vsize, &rss); - { - char state_str[2]; - - state_str[0] = c; - state_str[1] = '\0'; - tem = build_string (state_str); - attrs = Fcons (Fcons (Qstate, tem), attrs); - } - /* Stops GCC whining about limited range of data type. */ - ppid_eint = ppid; - pgrp_eint = pgrp; - sess_eint = sess; - tpgid_eint = tpgid; - thcount_eint = thcount; - attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (ppid_eint)), attrs); - attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pgrp_eint)), attrs); - attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (sess_eint)), attrs); - attrs = Fcons (Fcons (Qttname, procfs_ttyname (tty)), attrs); - attrs = Fcons (Fcons (Qtpgid, make_fixnum_or_float (tpgid_eint)), attrs); - attrs = Fcons (Fcons (Qminflt, make_fixnum_or_float (minflt)), attrs); - attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (majflt)), attrs); - attrs = Fcons (Fcons (Qcminflt, make_fixnum_or_float (cminflt)), attrs); - attrs = Fcons (Fcons (Qcmajflt, make_fixnum_or_float (cmajflt)), attrs); - clocks_per_sec = sysconf (_SC_CLK_TCK); - if (clocks_per_sec < 0) - clocks_per_sec = 100; - attrs = Fcons (Fcons (Qutime, - ltime_from_jiffies (utime, clocks_per_sec)), - attrs); - attrs = Fcons (Fcons (Qstime, - ltime_from_jiffies (stime, clocks_per_sec)), - attrs); - attrs = Fcons (Fcons (Qcutime, - ltime_from_jiffies (cutime, clocks_per_sec)), - attrs); - attrs = Fcons (Fcons (Qcstime, - ltime_from_jiffies (cstime, clocks_per_sec)), - attrs); - attrs = Fcons (Fcons (Qpri, make_number (priority)), attrs); - attrs = Fcons (Fcons (Qnice, make_number (nice)), attrs); - attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (thcount_eint)), attrs); - EMACS_GET_TIME (tnow); - get_up_time (&sec, &usec); - EMACS_SET_SECS (telapsed, sec); - EMACS_SET_USECS (telapsed, usec); - EMACS_SUB_TIME (tboot, tnow, telapsed); - time_from_jiffies (start, clocks_per_sec, &sec, &usec); - EMACS_SET_SECS (tstart, sec); - EMACS_SET_USECS (tstart, usec); - EMACS_ADD_TIME (tstart, tboot, tstart); - attrs = Fcons (Fcons (Qstart, - list3 (make_number - ((EMACS_SECS (tstart) >> 16) & 0xffff), - make_number - (EMACS_SECS (tstart) & 0xffff), - make_number - (EMACS_USECS (tstart)))), - attrs); - attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (vsize/1024)), attrs); - attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (4*rss)), attrs); - EMACS_SUB_TIME (telapsed, tnow, tstart); - attrs = Fcons (Fcons (Qetime, - list3 (make_number - ((EMACS_SECS (telapsed) >> 16) & 0xffff), - make_number - (EMACS_SECS (telapsed) & 0xffff), - make_number - (EMACS_USECS (telapsed)))), - attrs); - time_from_jiffies (utime + stime, clocks_per_sec, &sec, &usec); - pcpu = (sec + usec / 1000000.0) / (EMACS_SECS (telapsed) + EMACS_USECS (telapsed) / 1000000.0); - if (pcpu > 1.0) - pcpu = 1.0; - attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs); - pmem = 4.0 * 100 * rss / procfs_get_total_memory (); - if (pmem > 100) - pmem = 100; - attrs = Fcons (Fcons (Qpmem, make_float (pmem)), attrs); - } - } - if (fd >= 0) - emacs_close (fd); - - /* args */ - strcpy (procfn_end, "/cmdline"); - fd = emacs_open (fn, O_RDONLY, 0); - if (fd >= 0) - { - for (cmdline_size = 0; emacs_read (fd, &c, 1) == 1; cmdline_size++) - { - if (isspace (c) || c == '\\') - cmdline_size++; /* for later quoting, see below */ - } - if (cmdline_size) - { - cmdline = xmalloc (cmdline_size + 1); - lseek (fd, 0L, SEEK_SET); - cmdline[0] = '\0'; - if ((nread = read (fd, cmdline, cmdline_size)) >= 0) - cmdline[nread++] = '\0'; - else - { - /* Assigning zero to `nread' makes us skip the following - two loops, assign zero to cmdline_size, and enter the - following `if' clause that handles unknown command - lines. */ - nread = 0; - } - /* We don't want trailing null characters. */ - for (p = cmdline + nread - 1; p > cmdline && !*p; p--) - nread--; - for (p = cmdline; p < cmdline + nread; p++) - { - /* Escape-quote whitespace and backslashes. */ - if (isspace (*p) || *p == '\\') - { - memmove (p + 1, p, nread - (p - cmdline)); - nread++; - *p++ = '\\'; - } - else if (*p == '\0') - *p = ' '; - } - cmdline_size = nread; - } - if (!cmdline_size) - { - if (!cmd) - cmd = "???"; - if (!cmdsize) - cmdsize = strlen (cmd); - cmdline_size = cmdsize + 2; - cmdline = xmalloc (cmdline_size + 1); - strcpy (cmdline, "["); - strcat (strncat (cmdline, cmd, cmdsize), "]"); - } - emacs_close (fd); - /* Command line is encoded in locale-coding-system; decode it. */ - cmd_str = make_unibyte_string (cmdline, cmdline_size); - decoded_cmd = code_convert_string_norecord (cmd_str, - Vlocale_coding_system, 0); - xfree (cmdline); - attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs); - } - - UNGCPRO; - return attrs; -} - -#endif /* !HAVE_PROCFS */ - DEFUN ("list-system-processes", Flist_system_processes, Slist_system_processes, 0, 0, 0, doc: /* Return a list of numerical process IDs of all running processes. @@ -7498,11 +7071,7 @@ See `system-process-attributes' for getting attributes of a process given its ID. */) () { -#ifdef LISTPROC - return LISTPROC (); -#else - return Qnil; -#endif + return list_system_processes (); } DEFUN ("system-process-attributes", Fsystem_process_attributes, @@ -7558,11 +7127,7 @@ integer or floating point values. Lisp_Object pid; { -#ifdef PROCATTR - return PROCATTR (pid); -#else - return Qnil; -#endif + return system_process_attributes (pid); } void diff --git a/src/process.h b/src/process.h index 9606f5da9d..73674b7358 100644 --- a/src/process.h +++ b/src/process.h @@ -161,13 +161,13 @@ extern int synch_process_retcode; when exiting. */ extern int inhibit_sentinels; -extern Lisp_Object w32_list_system_processes P_ ((void)); -extern Lisp_Object w32_system_process_attributes P_ ((Lisp_Object)); - extern Lisp_Object Qeuid, Qegid, Qcomm, Qstate, Qppid, Qpgrp, Qsess, Qttname; extern Lisp_Object Qminflt, Qmajflt, Qcminflt, Qcmajflt, Qutime, Qstime; extern Lisp_Object Qcutime, Qpri, Qnice, Qthcount, Qstart, Qvsize, Qrss, Qargs; extern Lisp_Object Quser, Qgroup, Qetime, Qpcpu, Qpmem, Qtpgid, Qcstime; +extern Lisp_Object list_system_processes (void); +extern Lisp_Object system_process_attributes (Lisp_Object); + /* arch-tag: dffedfc4-d7bc-4b58-a26f-c16155449c72 (do not change this comment) */ diff --git a/src/s/gnu-linux.h b/src/s/gnu-linux.h index 2e28b81f7d..7437db5d8e 100644 --- a/src/s/gnu-linux.h +++ b/src/s/gnu-linux.h @@ -105,10 +105,8 @@ along with GNU Emacs. If not, see . */ #define BSTRING -/* These are used in Flist_system_processes and Fsystem_process_attributes. */ +/* This is used in list_system_processes. */ #define HAVE_PROCFS 1 -#define LISTPROC procfs_list_system_processes -#define PROCATTR procfs_system_process_attributes /* define MAIL_USE_FLOCK if the mailer uses flock to interlock access to /usr/spool/mail/$USER. diff --git a/src/sysdep.c b/src/sysdep.c index 0a2e2ed161..7f53ea2f78 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -25,6 +25,13 @@ along with GNU Emacs. If not, see . */ #include #include #include +#ifdef HAVE_PWD_H +#include +#include +#endif /* HAVE_PWD_H */ +#ifdef HAVE_LIMITS_H +#include +#endif /* HAVE_LIMITS_H */ #ifdef HAVE_UNISTD_H #include #endif @@ -3171,6 +3178,443 @@ serial_configure (struct Lisp_Process *p, } #endif /* TERMIOS */ + +/* System depended enumeration of and access to system processes a-la ps(1). */ + +#ifdef HAVE_PROCFS + +/* Process enumeration and access via /proc. */ + +Lisp_Object +list_system_processes () +{ + Lisp_Object procdir, match, proclist, next; + struct gcpro gcpro1, gcpro2; + register Lisp_Object tail; + + GCPRO2 (procdir, match); + /* For every process on the system, there's a directory in the + "/proc" pseudo-directory whose name is the numeric ID of that + process. */ + procdir = build_string ("/proc"); + match = build_string ("[0-9]+"); + proclist = directory_files_internal (procdir, Qnil, match, Qt, 0, Qnil); + + /* `proclist' gives process IDs as strings. Destructively convert + each string into a number. */ + for (tail = proclist; CONSP (tail); tail = next) + { + next = XCDR (tail); + XSETCAR (tail, Fstring_to_number (XCAR (tail), Qnil)); + } + UNGCPRO; + + /* directory_files_internal returns the files in reverse order; undo + that. */ + proclist = Fnreverse (proclist); + return proclist; +} + +#elif !defined (WINDOWSNT) + +Lisp_Object +list_system_processes () +{ + return Qnil; +} +#endif /* !defined (WINDOWSNT)*/ + +#ifdef GNU_LINUX +static void +time_from_jiffies (unsigned long long tval, long hz, + time_t *sec, unsigned *usec) +{ + unsigned long long ullsec; + + *sec = tval / hz; + ullsec = *sec; + tval -= ullsec * hz; + /* Careful: if HZ > 1 million, then integer division by it yields zero. */ + if (hz <= 1000000) + *usec = tval * 1000000 / hz; + else + *usec = tval / (hz / 1000000); +} + +static Lisp_Object +ltime_from_jiffies (unsigned long long tval, long hz) +{ + time_t sec; + unsigned usec; + + time_from_jiffies (tval, hz, &sec, &usec); + + return list3 (make_number ((sec >> 16) & 0xffff), + make_number (sec & 0xffff), + make_number (usec)); +} + +static void +get_up_time (time_t *sec, unsigned *usec) +{ + FILE *fup; + + *sec = *usec = 0; + + BLOCK_INPUT; + fup = fopen ("/proc/uptime", "r"); + + if (fup) + { + double uptime, idletime; + + /* The numbers in /proc/uptime use C-locale decimal point, but + we already set ourselves to the C locale (see `fixup_locale' + in emacs.c). */ + if (2 <= fscanf (fup, "%lf %lf", &uptime, &idletime)) + { + *sec = uptime; + *usec = (uptime - *sec) * 1000000; + } + fclose (fup); + } + UNBLOCK_INPUT; +} + +#define MAJOR(d) (((unsigned)(d) >> 8) & 0xfff) +#define MINOR(d) (((unsigned)(d) & 0xff) | (((unsigned)(d) & 0xfff00000) >> 12)) + +static Lisp_Object +procfs_ttyname (rdev) +{ + FILE *fdev = NULL; + char name[PATH_MAX]; + + BLOCK_INPUT; + fdev = fopen ("/proc/tty/drivers", "r"); + + if (fdev) + { + unsigned major; + unsigned long minor_beg, minor_end; + char minor[25]; /* 2 32-bit numbers + dash */ + char *endp; + + while (!feof (fdev) && !ferror (fdev)) + { + if (3 <= fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor) + && major == MAJOR (rdev)) + { + minor_beg = strtoul (minor, &endp, 0); + if (*endp == '\0') + minor_end = minor_beg; + else if (*endp == '-') + minor_end = strtoul (endp + 1, &endp, 0); + else + continue; + + if (MINOR (rdev) >= minor_beg && MINOR (rdev) <= minor_end) + { + sprintf (name + strlen (name), "%lu", MINOR (rdev)); + break; + } + } + } + fclose (fdev); + } + UNBLOCK_INPUT; + return build_string (name); +} + +static unsigned long +procfs_get_total_memory (void) +{ + FILE *fmem = NULL; + unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */ + + BLOCK_INPUT; + fmem = fopen ("/proc/meminfo", "r"); + + if (fmem) + { + unsigned long entry_value; + char entry_name[20]; /* the longest I saw is 13+1 */ + + while (!feof (fmem) && !ferror (fmem)) + { + if (2 <= fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value) + && strcmp (entry_name, "MemTotal:") == 0) + { + retval = entry_value; + break; + } + } + fclose (fmem); + } + UNBLOCK_INPUT; + return retval; +} + +Lisp_Object +system_process_attributes (pid) + Lisp_Object pid; +{ + char procfn[PATH_MAX], fn[PATH_MAX]; + struct stat st; + struct passwd *pw; + struct group *gr; + long clocks_per_sec; + char *procfn_end; + char procbuf[1025], *p, *q; + int fd; + ssize_t nread; + const char *cmd = NULL; + char *cmdline = NULL; + size_t cmdsize = 0, cmdline_size; + unsigned char c; + int proc_id, ppid, uid, gid, pgrp, sess, tty, tpgid, thcount; + unsigned long long utime, stime, cutime, cstime, start; + long priority, nice, rss; + unsigned long minflt, majflt, cminflt, cmajflt, vsize; + time_t sec; + unsigned usec; + EMACS_TIME tnow, tstart, tboot, telapsed,ttotal; + double pcpu, pmem; + Lisp_Object attrs = Qnil; + Lisp_Object cmd_str, decoded_cmd, tem; + struct gcpro gcpro1, gcpro2; + EMACS_INT uid_eint, gid_eint; + + CHECK_NUMBER_OR_FLOAT (pid); + proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid); + sprintf (procfn, "/proc/%lu", proc_id); + if (stat (procfn, &st) < 0) + return attrs; + + GCPRO2 (attrs, decoded_cmd); + + /* euid egid */ + uid = st.st_uid; + /* Use of EMACS_INT stops GCC whining about limited range of data type. */ + uid_eint = uid; + attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid_eint)), attrs); + BLOCK_INPUT; + pw = getpwuid (uid); + UNBLOCK_INPUT; + if (pw) + attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs); + + gid = st.st_gid; + gid_eint = gid; + attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid_eint)), attrs); + BLOCK_INPUT; + gr = getgrgid (gid); + UNBLOCK_INPUT; + if (gr) + attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs); + + strcpy (fn, procfn); + procfn_end = fn + strlen (fn); + strcpy (procfn_end, "/stat"); + fd = emacs_open (fn, O_RDONLY, 0); + if (fd >= 0 && (nread = emacs_read (fd, procbuf, sizeof(procbuf) - 1)) > 0) + { + procbuf[nread] = '\0'; + p = procbuf; + + p = strchr (p, '('); + if (p != NULL) + { + q = strrchr (p + 1, ')'); + /* comm */ + if (q != NULL) + { + cmd = p + 1; + cmdsize = q - cmd; + } + } + else + q = NULL; + if (cmd == NULL) + { + cmd = "???"; + cmdsize = 3; + } + /* Command name is encoded in locale-coding-system; decode it. */ + cmd_str = make_unibyte_string (cmd, cmdsize); + decoded_cmd = code_convert_string_norecord (cmd_str, + Vlocale_coding_system, 0); + attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs); + + if (q) + { + EMACS_INT ppid_eint, pgrp_eint, sess_eint, tpgid_eint, thcount_eint; + p = q + 2; + /* state ppid pgrp sess tty tpgid . minflt cminflt majflt cmajflt utime stime cutime cstime priority nice thcount . start vsize rss */ + sscanf (p, "%c %d %d %d %d %d %*u %lu %lu %lu %lu %Lu %Lu %Lu %Lu %ld %ld %d %*d %Lu %lu %ld", + &c, &ppid, &pgrp, &sess, &tty, &tpgid, + &minflt, &cminflt, &majflt, &cmajflt, + &utime, &stime, &cutime, &cstime, + &priority, &nice, &thcount, &start, &vsize, &rss); + { + char state_str[2]; + + state_str[0] = c; + state_str[1] = '\0'; + tem = build_string (state_str); + attrs = Fcons (Fcons (Qstate, tem), attrs); + } + /* Stops GCC whining about limited range of data type. */ + ppid_eint = ppid; + pgrp_eint = pgrp; + sess_eint = sess; + tpgid_eint = tpgid; + thcount_eint = thcount; + attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (ppid_eint)), attrs); + attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pgrp_eint)), attrs); + attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (sess_eint)), attrs); + attrs = Fcons (Fcons (Qttname, procfs_ttyname (tty)), attrs); + attrs = Fcons (Fcons (Qtpgid, make_fixnum_or_float (tpgid_eint)), attrs); + attrs = Fcons (Fcons (Qminflt, make_fixnum_or_float (minflt)), attrs); + attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (majflt)), attrs); + attrs = Fcons (Fcons (Qcminflt, make_fixnum_or_float (cminflt)), attrs); + attrs = Fcons (Fcons (Qcmajflt, make_fixnum_or_float (cmajflt)), attrs); + clocks_per_sec = sysconf (_SC_CLK_TCK); + if (clocks_per_sec < 0) + clocks_per_sec = 100; + attrs = Fcons (Fcons (Qutime, + ltime_from_jiffies (utime, clocks_per_sec)), + attrs); + attrs = Fcons (Fcons (Qstime, + ltime_from_jiffies (stime, clocks_per_sec)), + attrs); + attrs = Fcons (Fcons (Qcutime, + ltime_from_jiffies (cutime, clocks_per_sec)), + attrs); + attrs = Fcons (Fcons (Qcstime, + ltime_from_jiffies (cstime, clocks_per_sec)), + attrs); + attrs = Fcons (Fcons (Qpri, make_number (priority)), attrs); + attrs = Fcons (Fcons (Qnice, make_number (nice)), attrs); + attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (thcount_eint)), attrs); + EMACS_GET_TIME (tnow); + get_up_time (&sec, &usec); + EMACS_SET_SECS (telapsed, sec); + EMACS_SET_USECS (telapsed, usec); + EMACS_SUB_TIME (tboot, tnow, telapsed); + time_from_jiffies (start, clocks_per_sec, &sec, &usec); + EMACS_SET_SECS (tstart, sec); + EMACS_SET_USECS (tstart, usec); + EMACS_ADD_TIME (tstart, tboot, tstart); + attrs = Fcons (Fcons (Qstart, + list3 (make_number + ((EMACS_SECS (tstart) >> 16) & 0xffff), + make_number + (EMACS_SECS (tstart) & 0xffff), + make_number + (EMACS_USECS (tstart)))), + attrs); + attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (vsize/1024)), attrs); + attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (4*rss)), attrs); + EMACS_SUB_TIME (telapsed, tnow, tstart); + attrs = Fcons (Fcons (Qetime, + list3 (make_number + ((EMACS_SECS (telapsed) >> 16) & 0xffff), + make_number + (EMACS_SECS (telapsed) & 0xffff), + make_number + (EMACS_USECS (telapsed)))), + attrs); + time_from_jiffies (utime + stime, clocks_per_sec, &sec, &usec); + pcpu = (sec + usec / 1000000.0) / (EMACS_SECS (telapsed) + EMACS_USECS (telapsed) / 1000000.0); + if (pcpu > 1.0) + pcpu = 1.0; + attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs); + pmem = 4.0 * 100 * rss / procfs_get_total_memory (); + if (pmem > 100) + pmem = 100; + attrs = Fcons (Fcons (Qpmem, make_float (pmem)), attrs); + } + } + if (fd >= 0) + emacs_close (fd); + + /* args */ + strcpy (procfn_end, "/cmdline"); + fd = emacs_open (fn, O_RDONLY, 0); + if (fd >= 0) + { + for (cmdline_size = 0; emacs_read (fd, &c, 1) == 1; cmdline_size++) + { + if (isspace (c) || c == '\\') + cmdline_size++; /* for later quoting, see below */ + } + if (cmdline_size) + { + cmdline = xmalloc (cmdline_size + 1); + lseek (fd, 0L, SEEK_SET); + cmdline[0] = '\0'; + if ((nread = read (fd, cmdline, cmdline_size)) >= 0) + cmdline[nread++] = '\0'; + else + { + /* Assigning zero to `nread' makes us skip the following + two loops, assign zero to cmdline_size, and enter the + following `if' clause that handles unknown command + lines. */ + nread = 0; + } + /* We don't want trailing null characters. */ + for (p = cmdline + nread - 1; p > cmdline && !*p; p--) + nread--; + for (p = cmdline; p < cmdline + nread; p++) + { + /* Escape-quote whitespace and backslashes. */ + if (isspace (*p) || *p == '\\') + { + memmove (p + 1, p, nread - (p - cmdline)); + nread++; + *p++ = '\\'; + } + else if (*p == '\0') + *p = ' '; + } + cmdline_size = nread; + } + if (!cmdline_size) + { + if (!cmd) + cmd = "???"; + if (!cmdsize) + cmdsize = strlen (cmd); + cmdline_size = cmdsize + 2; + cmdline = xmalloc (cmdline_size + 1); + strcpy (cmdline, "["); + strcat (strncat (cmdline, cmd, cmdsize), "]"); + } + emacs_close (fd); + /* Command line is encoded in locale-coding-system; decode it. */ + cmd_str = make_unibyte_string (cmdline, cmdline_size); + decoded_cmd = code_convert_string_norecord (cmd_str, + Vlocale_coding_system, 0); + xfree (cmdline); + attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs); + } + + UNGCPRO; + return attrs; +} + +#elif !defined (WINDOWSNT) + +Lisp_Object +system_process_attributes (Lisp_Object pid) +{ + return Qnil +} + +#endif /* !defined (WINDOWSNT) */ + /* arch-tag: edb43589-4e09-4544-b325-978b5b121dcf (do not change this comment) */ diff --git a/src/w32.c b/src/w32.c index c6660c0d3d..5d70cbc48c 100644 --- a/src/w32.c +++ b/src/w32.c @@ -3671,7 +3671,7 @@ BOOL WINAPI global_memory_status_ex ( } Lisp_Object -w32_list_system_processes () +list_system_processes () { struct gcpro gcpro1; Lisp_Object proclist = Qnil; @@ -3823,7 +3823,7 @@ process_times (h_proc, ctime, etime, stime, utime, pcpu) } Lisp_Object -w32_system_process_attributes (pid) +system_process_attributes (pid) Lisp_Object pid; { struct gcpro gcpro1, gcpro2, gcpro3; -- 2.20.1