diff options
| author | Paul Eggert | 2012-06-22 14:17:42 -0700 |
|---|---|---|
| committer | Paul Eggert | 2012-06-22 14:17:42 -0700 |
| commit | d35af63cd671563fd188c3b0a1ef30067027c7aa (patch) | |
| tree | c9e01847ccf788e23794684da9331c3e0defd0d3 /src/sysdep.c | |
| parent | f143bfe38b43ad0a9d817f05c25e418982dca06f (diff) | |
| download | emacs-d35af63cd671563fd188c3b0a1ef30067027c7aa.tar.gz emacs-d35af63cd671563fd188c3b0a1ef30067027c7aa.zip | |
Support higher-resolution time stamps.
Fixes: debbugs:9000
Diffstat (limited to 'src/sysdep.c')
| -rw-r--r-- | src/sysdep.c | 227 |
1 files changed, 101 insertions, 126 deletions
diff --git a/src/sysdep.c b/src/sysdep.c index 3356582de0c..8d1c3d0ca3c 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -32,6 +32,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 32 | #include <allocator.h> | 32 | #include <allocator.h> |
| 33 | #include <careadlinkat.h> | 33 | #include <careadlinkat.h> |
| 34 | #include <ignore-value.h> | 34 | #include <ignore-value.h> |
| 35 | #include <utimens.h> | ||
| 35 | 36 | ||
| 36 | #include "lisp.h" | 37 | #include "lisp.h" |
| 37 | #include "sysselect.h" | 38 | #include "sysselect.h" |
| @@ -109,20 +110,6 @@ extern char *getwd (char *); | |||
| 109 | 110 | ||
| 110 | #include "syssignal.h" | 111 | #include "syssignal.h" |
| 111 | #include "systime.h" | 112 | #include "systime.h" |
| 112 | #ifdef HAVE_UTIME_H | ||
| 113 | #include <utime.h> | ||
| 114 | #endif | ||
| 115 | |||
| 116 | #ifndef HAVE_UTIMES | ||
| 117 | #ifndef HAVE_STRUCT_UTIMBUF | ||
| 118 | /* We want to use utime rather than utimes, but we couldn't find the | ||
| 119 | structure declaration. We'll use the traditional one. */ | ||
| 120 | struct utimbuf { | ||
| 121 | long actime; | ||
| 122 | long modtime; | ||
| 123 | }; | ||
| 124 | #endif | ||
| 125 | #endif | ||
| 126 | 113 | ||
| 127 | static int emacs_get_tty (int, struct emacs_tty *); | 114 | static int emacs_get_tty (int, struct emacs_tty *); |
| 128 | static int emacs_set_tty (int, struct emacs_tty *, int); | 115 | static int emacs_set_tty (int, struct emacs_tty *, int); |
| @@ -2067,30 +2054,6 @@ perror (void) | |||
| 2067 | #endif /* HPUX and not HAVE_PERROR */ | 2054 | #endif /* HPUX and not HAVE_PERROR */ |
| 2068 | 2055 | ||
| 2069 | /* | 2056 | /* |
| 2070 | * Gettimeofday. Simulate as much as possible. Only accurate | ||
| 2071 | * to nearest second. Emacs doesn't use tzp so ignore it for now. | ||
| 2072 | * Only needed when subprocesses are defined. | ||
| 2073 | */ | ||
| 2074 | |||
| 2075 | #ifndef HAVE_GETTIMEOFDAY | ||
| 2076 | #ifdef HAVE_TIMEVAL | ||
| 2077 | |||
| 2078 | int | ||
| 2079 | gettimeofday (struct timeval *tp, struct timezone *tzp) | ||
| 2080 | { | ||
| 2081 | extern long time (long); | ||
| 2082 | |||
| 2083 | tp->tv_sec = time ((long *)0); | ||
| 2084 | tp->tv_usec = 0; | ||
| 2085 | if (tzp != 0) | ||
| 2086 | tzp->tz_minuteswest = -1; | ||
| 2087 | return 0; | ||
| 2088 | } | ||
| 2089 | |||
| 2090 | #endif | ||
| 2091 | #endif /* !HAVE_GETTIMEOFDAY && HAVE_TIMEVAL */ | ||
| 2092 | |||
| 2093 | /* | ||
| 2094 | * This function will go away as soon as all the stubs fixed. (fnf) | 2057 | * This function will go away as soon as all the stubs fixed. (fnf) |
| 2095 | */ | 2058 | */ |
| 2096 | 2059 | ||
| @@ -2126,20 +2089,43 @@ closedir (DIR *dirp /* stream from opendir */) | |||
| 2126 | #endif /* HAVE_DIRENT_H */ | 2089 | #endif /* HAVE_DIRENT_H */ |
| 2127 | 2090 | ||
| 2128 | 2091 | ||
| 2092 | /* Return a struct timeval that is roughly equivalent to T. | ||
| 2093 | Use the least timeval not less than T. | ||
| 2094 | Return an extremal value if the result would overflow. */ | ||
| 2095 | struct timeval | ||
| 2096 | make_timeval (EMACS_TIME t) | ||
| 2097 | { | ||
| 2098 | struct timeval tv; | ||
| 2099 | tv.tv_sec = t.tv_sec; | ||
| 2100 | tv.tv_usec = t.tv_nsec / 1000; | ||
| 2101 | |||
| 2102 | if (t.tv_nsec % 1000 != 0) | ||
| 2103 | { | ||
| 2104 | if (tv.tv_usec < 999999) | ||
| 2105 | tv.tv_usec++; | ||
| 2106 | else if (tv.tv_sec < TYPE_MAXIMUM (time_t)) | ||
| 2107 | { | ||
| 2108 | tv.tv_sec++; | ||
| 2109 | tv.tv_usec = 0; | ||
| 2110 | } | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | return tv; | ||
| 2114 | } | ||
| 2115 | |||
| 2116 | /* Set the access and modification time stamps of FD (a.k.a. FILE) to be | ||
| 2117 | ATIME and MTIME, respectively. | ||
| 2118 | FD must be either negative -- in which case it is ignored -- | ||
| 2119 | or a file descriptor that is open on FILE. | ||
| 2120 | If FD is nonnegative, then FILE can be NULL. */ | ||
| 2129 | int | 2121 | int |
| 2130 | set_file_times (const char *filename, EMACS_TIME atime, EMACS_TIME mtime) | 2122 | set_file_times (int fd, const char *filename, |
| 2131 | { | 2123 | EMACS_TIME atime, EMACS_TIME mtime) |
| 2132 | #ifdef HAVE_UTIMES | 2124 | { |
| 2133 | struct timeval tv[2]; | 2125 | struct timespec timespec[2]; |
| 2134 | tv[0] = atime; | 2126 | timespec[0] = atime; |
| 2135 | tv[1] = mtime; | 2127 | timespec[1] = mtime; |
| 2136 | return utimes (filename, tv); | 2128 | return fdutimens (fd, filename, timespec); |
| 2137 | #else /* not HAVE_UTIMES */ | ||
| 2138 | struct utimbuf utb; | ||
| 2139 | utb.actime = EMACS_SECS (atime); | ||
| 2140 | utb.modtime = EMACS_SECS (mtime); | ||
| 2141 | return utime (filename, &utb); | ||
| 2142 | #endif /* not HAVE_UTIMES */ | ||
| 2143 | } | 2129 | } |
| 2144 | 2130 | ||
| 2145 | /* mkdir and rmdir functions, for systems which don't have them. */ | 2131 | /* mkdir and rmdir functions, for systems which don't have them. */ |
| @@ -2595,60 +2581,82 @@ list_system_processes (void) | |||
| 2595 | #endif /* !defined (WINDOWSNT) */ | 2581 | #endif /* !defined (WINDOWSNT) */ |
| 2596 | 2582 | ||
| 2597 | #ifdef GNU_LINUX | 2583 | #ifdef GNU_LINUX |
| 2598 | static void | 2584 | static EMACS_TIME |
| 2599 | time_from_jiffies (unsigned long long tval, long hz, | 2585 | time_from_jiffies (unsigned long long tval, long hz) |
| 2600 | time_t *sec, unsigned *usec) | 2586 | { |
| 2601 | { | 2587 | unsigned long long s = tval / hz; |
| 2602 | unsigned long long ullsec; | 2588 | unsigned long long frac = tval % hz; |
| 2603 | 2589 | int ns; | |
| 2604 | *sec = tval / hz; | 2590 | EMACS_TIME t; |
| 2605 | ullsec = *sec; | 2591 | |
| 2606 | tval -= ullsec * hz; | 2592 | if (TYPE_MAXIMUM (time_t) < s) |
| 2607 | /* Careful: if HZ > 1 million, then integer division by it yields zero. */ | 2593 | time_overflow (); |
| 2608 | if (hz <= 1000000) | 2594 | if (LONG_MAX - 1 <= ULLONG_MAX / EMACS_TIME_RESOLUTION |
| 2609 | *usec = tval * 1000000 / hz; | 2595 | || frac <= ULLONG_MAX / EMACS_TIME_RESOLUTION) |
| 2596 | ns = frac * EMACS_TIME_RESOLUTION / hz; | ||
| 2610 | else | 2597 | else |
| 2611 | *usec = tval / (hz / 1000000); | 2598 | { |
| 2599 | /* This is reachable only in the unlikely case that HZ * HZ | ||
| 2600 | exceeds ULLONG_MAX. It calculates an approximation that is | ||
| 2601 | guaranteed to be in range. */ | ||
| 2602 | long hz_per_ns = (hz / EMACS_TIME_RESOLUTION | ||
| 2603 | + (hz % EMACS_TIME_RESOLUTION != 0)); | ||
| 2604 | ns = frac / hz_per_ns; | ||
| 2605 | } | ||
| 2606 | |||
| 2607 | EMACS_SET_SECS_NSECS (t, s, ns); | ||
| 2608 | return t; | ||
| 2612 | } | 2609 | } |
| 2613 | 2610 | ||
| 2614 | static Lisp_Object | 2611 | static Lisp_Object |
| 2615 | ltime_from_jiffies (unsigned long long tval, long hz) | 2612 | ltime_from_jiffies (unsigned long long tval, long hz) |
| 2616 | { | 2613 | { |
| 2617 | time_t sec; | 2614 | EMACS_TIME t = time_from_jiffies (tval, hz); |
| 2618 | unsigned usec; | 2615 | return make_lisp_time (t); |
| 2619 | |||
| 2620 | time_from_jiffies (tval, hz, &sec, &usec); | ||
| 2621 | |||
| 2622 | return list3 (make_number ((sec >> 16) & 0xffff), | ||
| 2623 | make_number (sec & 0xffff), | ||
| 2624 | make_number (usec)); | ||
| 2625 | } | 2616 | } |
| 2626 | 2617 | ||
| 2627 | static void | 2618 | static EMACS_TIME |
| 2628 | get_up_time (time_t *sec, unsigned *usec) | 2619 | get_up_time (void) |
| 2629 | { | 2620 | { |
| 2630 | FILE *fup; | 2621 | FILE *fup; |
| 2622 | EMACS_TIME up; | ||
| 2631 | 2623 | ||
| 2632 | *sec = *usec = 0; | 2624 | EMACS_SET_SECS_NSECS (up, 0, 0); |
| 2633 | 2625 | ||
| 2634 | BLOCK_INPUT; | 2626 | BLOCK_INPUT; |
| 2635 | fup = fopen ("/proc/uptime", "r"); | 2627 | fup = fopen ("/proc/uptime", "r"); |
| 2636 | 2628 | ||
| 2637 | if (fup) | 2629 | if (fup) |
| 2638 | { | 2630 | { |
| 2639 | double uptime, idletime; | 2631 | unsigned long long upsec, upfrac, idlesec, idlefrac; |
| 2632 | int upfrac_start, upfrac_end, idlefrac_start, idlefrac_end; | ||
| 2640 | 2633 | ||
| 2641 | /* The numbers in /proc/uptime use C-locale decimal point, but | 2634 | if (fscanf (fup, "%llu.%n%llu%n %llu.%n%llu%n", |
| 2642 | we already set ourselves to the C locale (see `fixup_locale' | 2635 | &upsec, &upfrac_start, &upfrac, &upfrac_end, |
| 2643 | in emacs.c). */ | 2636 | &idlesec, &idlefrac_start, &idlefrac, &idlefrac_end) |
| 2644 | if (2 <= fscanf (fup, "%lf %lf", &uptime, &idletime)) | 2637 | == 4) |
| 2645 | { | 2638 | { |
| 2646 | *sec = uptime; | 2639 | if (TYPE_MAXIMUM (time_t) < upsec) |
| 2647 | *usec = (uptime - *sec) * 1000000; | 2640 | { |
| 2641 | upsec = TYPE_MAXIMUM (time_t); | ||
| 2642 | upfrac = EMACS_TIME_RESOLUTION - 1; | ||
| 2643 | } | ||
| 2644 | else | ||
| 2645 | { | ||
| 2646 | int upfraclen = upfrac_end - upfrac_start; | ||
| 2647 | for (; upfraclen < LOG10_EMACS_TIME_RESOLUTION; upfraclen++) | ||
| 2648 | upfrac *= 10; | ||
| 2649 | for (; LOG10_EMACS_TIME_RESOLUTION < upfraclen; upfraclen--) | ||
| 2650 | upfrac /= 10; | ||
| 2651 | upfrac = min (upfrac, EMACS_TIME_RESOLUTION - 1); | ||
| 2652 | } | ||
| 2653 | EMACS_SET_SECS_NSECS (up, upsec, upfrac); | ||
| 2648 | } | 2654 | } |
| 2649 | fclose (fup); | 2655 | fclose (fup); |
| 2650 | } | 2656 | } |
| 2651 | UNBLOCK_INPUT; | 2657 | UNBLOCK_INPUT; |
| 2658 | |||
| 2659 | return up; | ||
| 2652 | } | 2660 | } |
| 2653 | 2661 | ||
| 2654 | #define MAJOR(d) (((unsigned)(d) >> 8) & 0xfff) | 2662 | #define MAJOR(d) (((unsigned)(d) >> 8) & 0xfff) |
| @@ -2748,9 +2756,7 @@ system_process_attributes (Lisp_Object pid) | |||
| 2748 | unsigned long long u_time, s_time, cutime, cstime, start; | 2756 | unsigned long long u_time, s_time, cutime, cstime, start; |
| 2749 | long priority, niceness, rss; | 2757 | long priority, niceness, rss; |
| 2750 | unsigned long minflt, majflt, cminflt, cmajflt, vsize; | 2758 | unsigned long minflt, majflt, cminflt, cmajflt, vsize; |
| 2751 | time_t sec; | 2759 | EMACS_TIME tnow, tstart, tboot, telapsed, us_time; |
| 2752 | unsigned usec; | ||
| 2753 | EMACS_TIME tnow, tstart, tboot, telapsed; | ||
| 2754 | double pcpu, pmem; | 2760 | double pcpu, pmem; |
| 2755 | Lisp_Object attrs = Qnil; | 2761 | Lisp_Object attrs = Qnil; |
| 2756 | Lisp_Object cmd_str, decoded_cmd, tem; | 2762 | Lisp_Object cmd_str, decoded_cmd, tem; |
| @@ -2873,35 +2879,18 @@ system_process_attributes (Lisp_Object pid) | |||
| 2873 | attrs = Fcons (Fcons (Qnice, make_number (niceness)), attrs); | 2879 | attrs = Fcons (Fcons (Qnice, make_number (niceness)), attrs); |
| 2874 | attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (thcount_eint)), attrs); | 2880 | attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (thcount_eint)), attrs); |
| 2875 | EMACS_GET_TIME (tnow); | 2881 | EMACS_GET_TIME (tnow); |
| 2876 | get_up_time (&sec, &usec); | 2882 | telapsed = get_up_time (); |
| 2877 | EMACS_SET_SECS (telapsed, sec); | ||
| 2878 | EMACS_SET_USECS (telapsed, usec); | ||
| 2879 | EMACS_SUB_TIME (tboot, tnow, telapsed); | 2883 | EMACS_SUB_TIME (tboot, tnow, telapsed); |
| 2880 | time_from_jiffies (start, clocks_per_sec, &sec, &usec); | 2884 | tstart = time_from_jiffies (start, clocks_per_sec); |
| 2881 | EMACS_SET_SECS (tstart, sec); | ||
| 2882 | EMACS_SET_USECS (tstart, usec); | ||
| 2883 | EMACS_ADD_TIME (tstart, tboot, tstart); | 2885 | EMACS_ADD_TIME (tstart, tboot, tstart); |
| 2884 | attrs = Fcons (Fcons (Qstart, | 2886 | attrs = Fcons (Fcons (Qstart, make_lisp_time (tstart)), attrs); |
| 2885 | list3 (make_number | ||
| 2886 | ((EMACS_SECS (tstart) >> 16) & 0xffff), | ||
| 2887 | make_number | ||
| 2888 | (EMACS_SECS (tstart) & 0xffff), | ||
| 2889 | make_number | ||
| 2890 | (EMACS_USECS (tstart)))), | ||
| 2891 | attrs); | ||
| 2892 | attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (vsize/1024)), attrs); | 2887 | attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (vsize/1024)), attrs); |
| 2893 | attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (4*rss)), attrs); | 2888 | attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (4*rss)), attrs); |
| 2894 | EMACS_SUB_TIME (telapsed, tnow, tstart); | 2889 | EMACS_SUB_TIME (telapsed, tnow, tstart); |
| 2895 | attrs = Fcons (Fcons (Qetime, | 2890 | attrs = Fcons (Fcons (Qetime, make_lisp_time (telapsed)), attrs); |
| 2896 | list3 (make_number | 2891 | us_time = time_from_jiffies (u_time + s_time, clocks_per_sec); |
| 2897 | ((EMACS_SECS (telapsed) >> 16) & 0xffff), | 2892 | pcpu = (EMACS_TIME_TO_DOUBLE (us_time) |
| 2898 | make_number | 2893 | / EMACS_TIME_TO_DOUBLE (telapsed)); |
| 2899 | (EMACS_SECS (telapsed) & 0xffff), | ||
| 2900 | make_number | ||
| 2901 | (EMACS_USECS (telapsed)))), | ||
| 2902 | attrs); | ||
| 2903 | time_from_jiffies (u_time + s_time, clocks_per_sec, &sec, &usec); | ||
| 2904 | pcpu = (sec + usec / 1000000.0) / (EMACS_SECS (telapsed) + EMACS_USECS (telapsed) / 1000000.0); | ||
| 2905 | if (pcpu > 1.0) | 2894 | if (pcpu > 1.0) |
| 2906 | pcpu = 1.0; | 2895 | pcpu = 1.0; |
| 2907 | attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs); | 2896 | attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs); |
| @@ -3082,27 +3071,13 @@ system_process_attributes (Lisp_Object pid) | |||
| 3082 | Qcstime | 3071 | Qcstime |
| 3083 | Are they available? */ | 3072 | Are they available? */ |
| 3084 | 3073 | ||
| 3085 | attrs = Fcons (Fcons (Qtime, | 3074 | attrs = Fcons (Fcons (Qtime, make_lisp_time (pinfo.pr_time)), attrs); |
| 3086 | list3 (make_number (pinfo.pr_time.tv_sec >> 16), | 3075 | attrs = Fcons (Fcons (Qctime, make_lisp_time (pinfo.pr_ctime)), attrs); |
| 3087 | make_number (pinfo.pr_time.tv_sec & 0xffff), | ||
| 3088 | make_number (pinfo.pr_time.tv_nsec))), | ||
| 3089 | attrs); | ||
| 3090 | |||
| 3091 | attrs = Fcons (Fcons (Qctime, | ||
| 3092 | list3 (make_number (pinfo.pr_ctime.tv_sec >> 16), | ||
| 3093 | make_number (pinfo.pr_ctime.tv_sec & 0xffff), | ||
| 3094 | make_number (pinfo.pr_ctime.tv_nsec))), | ||
| 3095 | attrs); | ||
| 3096 | |||
| 3097 | attrs = Fcons (Fcons (Qpri, make_number (pinfo.pr_lwp.pr_pri)), attrs); | 3076 | attrs = Fcons (Fcons (Qpri, make_number (pinfo.pr_lwp.pr_pri)), attrs); |
| 3098 | attrs = Fcons (Fcons (Qnice, make_number (pinfo.pr_lwp.pr_nice)), attrs); | 3077 | attrs = Fcons (Fcons (Qnice, make_number (pinfo.pr_lwp.pr_nice)), attrs); |
| 3099 | attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (pinfo.pr_nlwp)), attrs); | 3078 | attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (pinfo.pr_nlwp)), attrs); |
| 3100 | 3079 | ||
| 3101 | attrs = Fcons (Fcons (Qstart, | 3080 | attrs = Fcons (Fcons (Qstart, make_lisp_time (pinfo.pr_start)), attrs); |
| 3102 | list3 (make_number (pinfo.pr_start.tv_sec >> 16), | ||
| 3103 | make_number (pinfo.pr_start.tv_sec & 0xffff), | ||
| 3104 | make_number (pinfo.pr_start.tv_nsec))), | ||
| 3105 | attrs); | ||
| 3106 | attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (pinfo.pr_size)), attrs); | 3081 | attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (pinfo.pr_size)), attrs); |
| 3107 | attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (pinfo.pr_rssize)), attrs); | 3082 | attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (pinfo.pr_rssize)), attrs); |
| 3108 | 3083 | ||