efficient vim config
[dotfiles/.git] / .local / lib / python2.7 / site-packages / trollius / time_monotonic.py
1 """
2 Backport of time.monotonic() of Python 3.3 (PEP 418) for Python 2.7.
3
4 - time_monotonic(). This clock may or may not be monotonic depending on the
5   operating system.
6 - time_monotonic_resolution: Resolution of time_monotonic() clock in second
7
8 Support Windows, Mac OS X, Linux, FreeBSD, OpenBSD and Solaris, but requires
9 the ctypes module.
10 """
11 import os
12 import sys
13 from .log import logger
14 from .py33_exceptions import get_error_class
15
16 __all__ = ('time_monotonic',)
17
18 # default implementation: system clock (non monotonic!)
19 from time import time as time_monotonic
20 # the worst resolution is 15.6 ms on Windows
21 time_monotonic_resolution = 0.050
22
23 if os.name == "nt":
24     # Windows: use GetTickCount64() or GetTickCount()
25     try:
26         import ctypes
27         from ctypes import windll
28         from ctypes.wintypes import DWORD
29     except ImportError:
30         logger.error("time_monotonic import error", exc_info=True)
31     else:
32         # GetTickCount64() requires Windows Vista, Server 2008 or later
33         if hasattr(windll.kernel32, 'GetTickCount64'):
34             ULONGLONG = ctypes.c_uint64
35
36             GetTickCount64 = windll.kernel32.GetTickCount64
37             GetTickCount64.restype = ULONGLONG
38             GetTickCount64.argtypes = ()
39
40             def time_monotonic():
41                 return GetTickCount64() * 1e-3
42             time_monotonic_resolution = 1e-3
43         else:
44             GetTickCount = windll.kernel32.GetTickCount
45             GetTickCount.restype = DWORD
46             GetTickCount.argtypes = ()
47
48             # Detect GetTickCount() integer overflow (32 bits, roll-over after 49.7
49             # days). It increases an internal epoch (reference time) by 2^32 each
50             # time that an overflow is detected. The epoch is stored in the
51             # process-local state and so the value of time_monotonic() may be
52             # different in two Python processes running for more than 49 days.
53             def time_monotonic():
54                 ticks = GetTickCount()
55                 if ticks < time_monotonic.last:
56                     # Integer overflow detected
57                     time_monotonic.delta += 2**32
58                 time_monotonic.last = ticks
59                 return (ticks + time_monotonic.delta) * 1e-3
60             time_monotonic.last = 0
61             time_monotonic.delta = 0
62             time_monotonic_resolution = 1e-3
63
64 elif sys.platform == 'darwin':
65     # Mac OS X: use mach_absolute_time() and mach_timebase_info()
66     try:
67         import ctypes
68         import ctypes.util
69         libc_name = ctypes.util.find_library('c')
70     except ImportError:
71         logger.error("time_monotonic import error", exc_info=True)
72         libc_name = None
73     if libc_name:
74         libc = ctypes.CDLL(libc_name, use_errno=True)
75
76         mach_absolute_time = libc.mach_absolute_time
77         mach_absolute_time.argtypes = ()
78         mach_absolute_time.restype = ctypes.c_uint64
79
80         class mach_timebase_info_data_t(ctypes.Structure):
81             _fields_ = (
82                 ('numer', ctypes.c_uint32),
83                 ('denom', ctypes.c_uint32),
84             )
85         mach_timebase_info_data_p = ctypes.POINTER(mach_timebase_info_data_t)
86
87         mach_timebase_info = libc.mach_timebase_info
88         mach_timebase_info.argtypes = (mach_timebase_info_data_p,)
89         mach_timebase_info.restype = ctypes.c_int
90
91         def time_monotonic():
92             return mach_absolute_time() * time_monotonic.factor
93
94         timebase = mach_timebase_info_data_t()
95         mach_timebase_info(ctypes.byref(timebase))
96         time_monotonic.factor = float(timebase.numer) / timebase.denom * 1e-9
97         time_monotonic_resolution = time_monotonic.factor
98         del timebase
99
100 elif sys.platform.startswith(("linux", "freebsd", "openbsd", "sunos")):
101     # Linux, FreeBSD, OpenBSD: use clock_gettime(CLOCK_MONOTONIC)
102     # Solaris: use clock_gettime(CLOCK_HIGHRES)
103
104     library = None
105     try:
106         import ctypes
107         import ctypes.util
108     except ImportError:
109         logger.error("time_monotonic import error", exc_info=True)
110         libraries = ()
111     else:
112         if sys.platform.startswith(("freebsd", "openbsd")):
113             libraries = ('c',)
114         elif sys.platform.startswith("linux"):
115             # Linux: in glibc 2.17+, clock_gettime() is provided by the libc,
116             # on older versions, it is provided by librt
117             libraries = ('c', 'rt')
118         else:
119             # Solaris
120             libraries = ('rt',)
121
122     for name in libraries:
123         filename = ctypes.util.find_library(name)
124         if not filename:
125             continue
126         library = ctypes.CDLL(filename, use_errno=True)
127         if not hasattr(library, 'clock_gettime'):
128             library = None
129
130     if library is not None:
131         if sys.platform.startswith("openbsd"):
132             import platform
133             release = platform.release()
134             release = tuple(map(int, release.split('.')))
135             if release >= (5, 5):
136                 time_t = ctypes.c_int64
137             else:
138                 time_t = ctypes.c_int32
139         else:
140             time_t = ctypes.c_long
141         clockid_t = ctypes.c_int
142
143         class timespec(ctypes.Structure):
144             _fields_ = (
145                 ('tv_sec', time_t),
146                 ('tv_nsec', ctypes.c_long),
147             )
148         timespec_p = ctypes.POINTER(timespec)
149
150         clock_gettime = library.clock_gettime
151         clock_gettime.argtypes = (clockid_t, timespec_p)
152         clock_gettime.restype = ctypes.c_int
153
154         def ctypes_oserror():
155             errno = ctypes.get_errno()
156             message = os.strerror(errno)
157             error_class = get_error_class(errno, OSError)
158             return error_class(errno, message)
159
160         def time_monotonic():
161             ts = timespec()
162             err = clock_gettime(time_monotonic.clk_id, ctypes.byref(ts))
163             if err:
164                 raise ctypes_oserror()
165             return ts.tv_sec + ts.tv_nsec * 1e-9
166
167         if sys.platform.startswith("linux"):
168             time_monotonic.clk_id = 1   # CLOCK_MONOTONIC
169         elif sys.platform.startswith("freebsd"):
170             time_monotonic.clk_id = 4   # CLOCK_MONOTONIC
171         elif sys.platform.startswith("openbsd"):
172             time_monotonic.clk_id = 3   # CLOCK_MONOTONIC
173         else:
174             assert sys.platform.startswith("sunos")
175             time_monotonic.clk_id = 4   # CLOCK_HIGHRES
176
177         def get_resolution():
178             _clock_getres = library.clock_getres
179             _clock_getres.argtypes = (clockid_t, timespec_p)
180             _clock_getres.restype = ctypes.c_int
181
182             ts = timespec()
183             err = _clock_getres(time_monotonic.clk_id, ctypes.byref(ts))
184             if err:
185                 raise ctypes_oserror()
186             return ts.tv_sec + ts.tv_nsec * 1e-9
187         time_monotonic_resolution = get_resolution()
188         del get_resolution
189
190 else:
191     logger.error("time_monotonic: unspported platform %r", sys.platform)
192