Mercurial > ~astiob > upreckon > hgweb
comparison upreckon/_unixmodule.cpp @ 253:d06e57b182a9
Embraced clock_gettime and mach_absolute_time in _unix
Also made _unix wall clock time reports more precise;
this was necessitated by the main changes.
author | Oleg Oshmyan <chortos@inbox.lv> |
---|---|
date | Fri, 14 Mar 2014 15:25:06 +0000 |
parents | 65b5c9390010 |
children | 393b4689ac2f |
comparison
equal
deleted
inserted
replaced
252:756dacca888a | 253:d06e57b182a9 |
---|---|
1 // Copyright (c) 2011 Chortos-2 <chortos@inbox.lv> | 1 // Copyright (c) 2011-2014 Chortos-2 <chortos@inbox.lv> |
2 | 2 |
3 #include <Python.h> | 3 #include <Python.h> |
4 #include <structmember.h> | 4 #include <structmember.h> |
5 | 5 |
6 #ifdef HAVE_SYS_TYPES_H | 6 #ifdef HAVE_SYS_TYPES_H |
10 #ifdef HAVE_FCNTL_H | 10 #ifdef HAVE_FCNTL_H |
11 #include <fcntl.h> | 11 #include <fcntl.h> |
12 #endif | 12 #endif |
13 | 13 |
14 #include <limits.h> | 14 #include <limits.h> |
15 | |
16 #ifdef __APPLE__ | |
17 #include <mach/mach_time.h> | |
18 #endif | |
15 | 19 |
16 #ifdef HAVE_SIGNAL_H | 20 #ifdef HAVE_SIGNAL_H |
17 #include <signal.h> | 21 #include <signal.h> |
18 #endif | 22 #endif |
19 | 23 |
32 #include <sys/wait.h> | 36 #include <sys/wait.h> |
33 #endif | 37 #endif |
34 | 38 |
35 #ifdef HAVE_TERMIOS_H | 39 #ifdef HAVE_TERMIOS_H |
36 #include <termios.h> | 40 #include <termios.h> |
41 #endif | |
42 | |
43 #ifdef HAVE_CLOCK_GETTIME | |
44 #include <time.h> | |
37 #endif | 45 #endif |
38 | 46 |
39 #if !(defined __cplusplus) && !(defined bool) | 47 #if !(defined __cplusplus) && !(defined bool) |
40 #ifdef HAVE_C99_BOOL | 48 #ifdef HAVE_C99_BOOL |
41 #define bool _Bool | 49 #define bool _Bool |
72 #endif | 80 #endif |
73 | 81 |
74 #ifndef Py_PYTIME_H | 82 #ifndef Py_PYTIME_H |
75 typedef struct timeval _PyTime_timeval; | 83 typedef struct timeval _PyTime_timeval; |
76 #ifndef GETTIMEOFDAY_NO_TZ | 84 #ifndef GETTIMEOFDAY_NO_TZ |
77 #define _PyTime_gettimeofday(tvp) gettimeofday((tvp), NULL) | 85 #define _PyTime_gettimeofday(tvp) gettimeofday(tvp, NULL) |
78 #else | 86 #else |
79 #define _PyTime_gettimeofday(tvp) gettimeofday((tvp)) | 87 #define _PyTime_gettimeofday(tvp) gettimeofday(tvp) |
80 #endif | 88 #endif |
81 #endif | 89 #endif |
90 | |
91 static inline void timerget(_PyTime_timeval *tvp) | |
92 { | |
93 #if defined HAVE_CLOCK_GETTIME && (defined CLOCK_MONOTONIC_RAW || defined CLOCK_HIGHRES || defined CLOCK_MONOTONIC) | |
94 struct timespec ts; | |
95 #ifdef CLOCK_MONOTONIC_RAW | |
96 clock_gettime(CLOCK_MONOTONIC_RAW, &ts); | |
97 #elif defined CLOCK_HIGHRES | |
98 clock_gettime(CLOCK_HIGHRES, &ts); | |
99 #else | |
100 clock_gettime(CLOCK_MONOTONIC, &ts); | |
101 #endif | |
102 tvp->tv_sec = ts.tv_sec; | |
103 tvp->tv_usec = ts.tv_nsec / 1000; | |
104 #elif defined __APPLE__ | |
105 static mach_timebase_info_data_t base; | |
106 if (!base.numer) | |
107 { | |
108 mach_timebase_info(&base); | |
109 base.denom *= 1000; | |
110 } | |
111 uint64_t t = mach_absolute_time() * base.numer / base.denom; | |
112 tvp->tv_sec = t / 1000000; | |
113 tvp->tv_usec = t % 1000000; | |
114 #else | |
115 _PyTime_gettimeofday(tvp); | |
116 #endif | |
117 } | |
82 | 118 |
83 #if PY_MAJOR_VERSION >= 3 | 119 #if PY_MAJOR_VERSION >= 3 |
84 #define PyInt_AsLong PyLong_AsLong | 120 #define PyInt_AsLong PyLong_AsLong |
85 #define PyInt_FromLong PyLong_FromLong | 121 #define PyInt_FromLong PyLong_FromLong |
86 #define PyNumber_Int PyNumber_Long | 122 #define PyNumber_Int PyNumber_Long |
477 #ifdef __APPLE__ | 513 #ifdef __APPLE__ |
478 if (posix_spawnp != NULL) | 514 if (posix_spawnp != NULL) |
479 { | 515 { |
480 #endif | 516 #endif |
481 spawn_errno = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ); | 517 spawn_errno = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ); |
482 _PyTime_gettimeofday(&tvstart); | 518 timerget(&tvstart); |
483 | 519 |
484 if (spawn_errno) | 520 if (spawn_errno) |
485 { | 521 { |
486 TESTEE_REPORT_STATUS(TESTEE_SPAWN_FAILED); | 522 TESTEE_REPORT_STATUS(TESTEE_SPAWN_FAILED); |
487 write(c2ppipe[1], &spawn_errno, sizeof spawn_errno); | 523 write(c2ppipe[1], &spawn_errno, sizeof spawn_errno); |
510 write(c2ppipe[1], &spawn_errno, sizeof spawn_errno); | 546 write(c2ppipe[1], &spawn_errno, sizeof spawn_errno); |
511 _exit(127); | 547 _exit(127); |
512 } | 548 } |
513 else | 549 else |
514 { | 550 { |
515 _PyTime_gettimeofday(&tvstart); | 551 timerget(&tvstart); |
516 } | 552 } |
517 } | 553 } |
518 #endif | 554 #endif |
519 TESTEE_REPORT_STATUS(TESTEE_SPAWNED); | 555 TESTEE_REPORT_STATUS(TESTEE_SPAWNED); |
520 write(c2ppipe[1], &tvstart, sizeof tvstart); | 556 write(c2ppipe[1], &tvstart, sizeof tvstart); |
527 while (waitpid(pid, &status, 0) != pid); | 563 while (waitpid(pid, &status, 0) != pid); |
528 #else | 564 #else |
529 while (wait(&status) != pid); | 565 while (wait(&status) != pid); |
530 #endif | 566 #endif |
531 | 567 |
532 _PyTime_gettimeofday(&tvend); | 568 timerget(&tvend); |
533 #if defined HAVE_SYS_RESOURCE_H && !(defined HAVE_WAIT4 || defined HAVE_WAIT3) | 569 #if defined HAVE_SYS_RESOURCE_H && !(defined HAVE_WAIT4 || defined HAVE_WAIT3) |
534 getrusage(RUSAGE_CHILDREN, &rusage); | 570 getrusage(RUSAGE_CHILDREN, &rusage); |
535 #endif | 571 #endif |
536 | 572 |
537 stats = zero_stats; | 573 stats = zero_stats; |
671 static char is_int(unsigned long long); | 707 static char is_int(unsigned long long); |
672 #endif | 708 #endif |
673 static two_chars is_int(...); | 709 static two_chars is_int(...); |
674 #endif | 710 #endif |
675 | 711 |
676 static inline bool timeval_to_attr(_PyTime_timeval *ptv, PyObject *obj, const char *attr) | 712 static inline PyObject *timeval_to_obj(const _PyTime_timeval *ptv) |
677 { | 713 { |
678 PyObject *value; | |
679 #ifdef __cplusplus | 714 #ifdef __cplusplus |
680 // If tv_sec has an integral type and !tv_usec, try to create a Python int | 715 // If tv_sec has an integral type and !tv_usec, try to create a Python int |
681 if (sizeof is_int(ptv->tv_sec) == sizeof(char) && !ptv->tv_usec) | 716 if (sizeof is_int(ptv->tv_sec) == sizeof(char) && !ptv->tv_usec) |
682 { | 717 { |
683 if (ptv->tv_sec <= LONG_MAX) | 718 if (ptv->tv_sec <= LONG_MAX) |
684 { | 719 { |
685 value = PyInt_FromLong(ptv->tv_sec); | 720 return PyInt_FromLong(ptv->tv_sec); |
686 } | 721 } |
687 // FIXME: signed/unsigned comparisons ruin everything | 722 // FIXME: signed/unsigned comparisons ruin everything |
688 #ifdef HAVE_LONG_LONG | 723 #ifdef HAVE_LONG_LONG |
689 else// if (ptv->tv_sec <= ULLONG_MAX) | 724 else// if (ptv->tv_sec <= ULLONG_MAX) |
690 { | 725 { |
691 value = PyLong_FromUnsignedLongLong(ptv->tv_sec); | 726 return PyLong_FromUnsignedLongLong(ptv->tv_sec); |
692 } | 727 } |
693 #else | 728 #else |
694 // else if (ptv->tv_sec <= ULONG_MAX) | 729 // else if (ptv->tv_sec <= ULONG_MAX) |
695 // { | 730 // { |
696 // value = PyLong_FromUnsignedLong(ptv->tv_sec); | 731 // return PyLong_FromUnsignedLong(ptv->tv_sec); |
697 // } | 732 // } |
698 //#endif | 733 //#endif |
699 else | 734 else |
700 { | 735 { |
701 value = PyFloat_FromDouble(ptv->tv_sec); | 736 return PyFloat_FromDouble(ptv->tv_sec); |
702 } | 737 } |
703 // | 738 // |
704 #endif | 739 #endif |
705 // | 740 // |
706 } | 741 } |
707 else | 742 else |
708 #endif | 743 #endif |
709 { | 744 { |
710 // TODO: use decimal.Decimal or fractions.Fraction | 745 // TODO: use decimal.Decimal or fractions.Fraction |
711 value = PyFloat_FromDouble(ptv->tv_sec + ptv->tv_usec * 0.000001); | 746 return PyFloat_FromDouble(ptv->tv_sec + ptv->tv_usec * 0.000001); |
712 } | 747 } |
748 } | |
749 | |
750 static inline bool timeval_to_attr(const _PyTime_timeval *ptv, PyObject *obj, const char *attr) | |
751 { | |
752 PyObject *value = timeval_to_obj(ptv); | |
713 if (value == NULL) | 753 if (value == NULL) |
714 { | 754 { |
715 return false; | 755 return false; |
716 } | 756 } |
717 if (PyObject_SetAttrString(obj, attr, value) == -1) | 757 if (PyObject_SetAttrString(obj, attr, value) == -1) |
722 return true; | 762 return true; |
723 } | 763 } |
724 | 764 |
725 /* | 765 /* |
726 TODO/FIXME: | 766 TODO/FIXME: |
727 * Replace timeval->timespec and select->pselect if pselect is available | |
728 (preferably only if pselect is not a wrapper around select). | |
729 * File descriptors might be >= FD_SETSIZE? | 767 * File descriptors might be >= FD_SETSIZE? |
730 */ | 768 */ |
731 static PyObject *_unix_call(PyObject *self, PyObject *args, PyObject *kwds) | 769 static PyObject *_unix_call(PyObject *self, PyObject *args, PyObject *kwds) |
732 { | 770 { |
733 PyObject *testcase = NULL, *obj; | 771 PyObject *testcase = NULL, *obj; |
737 _PyTime_timeval maxwalltime, maxcputime, timeout, time_start; | 775 _PyTime_timeval maxwalltime, maxcputime, timeout, time_start; |
738 Py_ssize_t maxmemory, r; | 776 Py_ssize_t maxmemory, r; |
739 size_t stats_read = 0; | 777 size_t stats_read = 0; |
740 fd_set readfds; | 778 fd_set readfds; |
741 char c; | 779 char c; |
742 bool have_maxwalltime; | 780 bool have_maxwalltime, wall_time_exceeded; |
743 | 781 |
744 if (kwds != NULL) | 782 if (kwds != NULL) |
745 { | 783 { |
746 testcase = PyDict_GetItemString(kwds, "case"); | 784 testcase = PyDict_GetItemString(kwds, "case"); |
747 } | 785 } |
997 #endif | 1035 #endif |
998 FD_SET(c2ppipe[0], &readfds); | 1036 FD_SET(c2ppipe[0], &readfds); |
999 | 1037 |
1000 if (have_maxwalltime) | 1038 if (have_maxwalltime) |
1001 { | 1039 { |
1002 _PyTime_gettimeofday(&now); | 1040 timerget(&now); |
1003 if (timercmp(&time_end, &now, <)) | 1041 if (timercmp(&time_end, &now, <)) |
1004 { | 1042 { |
1005 timerclear(&timeout); | 1043 timerclear(&timeout); |
1006 } | 1044 } |
1007 else | 1045 else |
1014 if (!s && timercmp(&time_end, &now, <)) | 1052 if (!s && timercmp(&time_end, &now, <)) |
1015 { | 1053 { |
1016 close(c2ppipe[0]); | 1054 close(c2ppipe[0]); |
1017 TERM_TESTEE; | 1055 TERM_TESTEE; |
1018 Py_BLOCK_THREADS | 1056 Py_BLOCK_THREADS |
1057 timeval_to_attr(&now, testcase, "time_stopped"); | |
1019 Py_DECREF(testcase); | 1058 Py_DECREF(testcase); |
1020 PyErr_SetObject(WallTimeLimitExceeded, NULL); | 1059 PyErr_SetObject(WallTimeLimitExceeded, NULL); |
1021 return NULL; | 1060 return NULL; |
1022 } | 1061 } |
1023 } | 1062 } |
1195 Py_DECREF(testcase); | 1234 Py_DECREF(testcase); |
1196 PyErr_SetString(PyExc_EnvironmentError, "unexpectedly early end of output from worker"); | 1235 PyErr_SetString(PyExc_EnvironmentError, "unexpectedly early end of output from worker"); |
1197 return NULL; | 1236 return NULL; |
1198 } | 1237 } |
1199 | 1238 |
1200 if (timerisset(&maxwalltime) && timercmp(&stats.walltime, &maxwalltime, >)) | |
1201 { | |
1202 Py_DECREF(testcase); | |
1203 PyErr_SetObject(WallTimeLimitExceeded, NULL); | |
1204 return NULL; | |
1205 } | |
1206 | |
1207 obj = PyInt_FromLong(0); | 1239 obj = PyInt_FromLong(0); |
1208 if (obj == NULL) | 1240 if (obj == NULL) |
1209 { | 1241 { |
1210 Py_DECREF(testcase); | 1242 Py_DECREF(testcase); |
1211 return NULL; | 1243 return NULL; |
1215 Py_DECREF(testcase); | 1247 Py_DECREF(testcase); |
1216 return NULL; | 1248 return NULL; |
1217 } | 1249 } |
1218 Py_DECREF(obj); | 1250 Py_DECREF(obj); |
1219 | 1251 |
1252 wall_time_exceeded = timerisset(&maxwalltime) && timercmp(&stats.walltime, &maxwalltime, >); | |
1220 #if defined HAVE_SYS_RESOURCE_H || defined HAVE_WAIT4 || defined HAVE_WAIT3 | 1253 #if defined HAVE_SYS_RESOURCE_H || defined HAVE_WAIT4 || defined HAVE_WAIT3 |
1221 if (timerisset(&maxcputime) || !timerisset(&maxwalltime)) | 1254 if (!wall_time_exceeded && (timerisset(&maxcputime) || !timerisset(&maxwalltime))) |
1222 { | 1255 { |
1223 PyObject *cputls; | 1256 PyObject *cputls; |
1224 if (!timeval_to_attr(&stats.cputime, testcase, "time_stopped")) | 1257 if (!timeval_to_attr(&stats.cputime, testcase, "time_stopped")) |
1225 { | 1258 { |
1226 Py_DECREF(testcase); | 1259 Py_DECREF(testcase); |
1249 #endif | 1282 #endif |
1250 { | 1283 { |
1251 if (!timeval_to_attr(&stats.walltime, testcase, "time_stopped")) | 1284 if (!timeval_to_attr(&stats.walltime, testcase, "time_stopped")) |
1252 { | 1285 { |
1253 Py_DECREF(testcase); | 1286 Py_DECREF(testcase); |
1287 return NULL; | |
1288 } | |
1289 if (wall_time_exceeded) | |
1290 { | |
1291 Py_DECREF(testcase); | |
1292 PyErr_SetObject(WallTimeLimitExceeded, NULL); | |
1254 return NULL; | 1293 return NULL; |
1255 } | 1294 } |
1256 } | 1295 } |
1257 | 1296 |
1258 #if defined HAVE_SYS_RESOURCE_H || defined HAVE_WAIT4 || defined HAVE_WAIT3 | 1297 #if defined HAVE_SYS_RESOURCE_H || defined HAVE_WAIT4 || defined HAVE_WAIT3 |
1274 Py_DECREF(Popen_placeholder); | 1313 Py_DECREF(Popen_placeholder); |
1275 Py_DECREF(testcase); | 1314 Py_DECREF(testcase); |
1276 Py_RETURN_NONE; | 1315 Py_RETURN_NONE; |
1277 } | 1316 } |
1278 | 1317 |
1318 static PyObject *_unix_clock(PyObject *self) | |
1319 { | |
1320 _PyTime_timeval tv; | |
1321 timerget(&tv); | |
1322 return timeval_to_obj(&tv); | |
1323 } | |
1324 | |
1279 static PyObject *_unix_pause(PyObject *self) | 1325 static PyObject *_unix_pause(PyObject *self) |
1280 { | 1326 { |
1281 #ifdef HAVE_TERMIOS_H | 1327 #ifdef HAVE_TERMIOS_H |
1282 if (catch_escape) | 1328 if (catch_escape) |
1283 { | 1329 { |
1298 } | 1344 } |
1299 | 1345 |
1300 static PyMethodDef _unixMethods[] = | 1346 static PyMethodDef _unixMethods[] = |
1301 { | 1347 { |
1302 { "call", (PyCFunction) _unix_call, METH_VARARGS | METH_KEYWORDS, "Call a process." }, | 1348 { "call", (PyCFunction) _unix_call, METH_VARARGS | METH_KEYWORDS, "Call a process." }, |
1349 { "clock", (PyCFunction) _unix_clock, METH_NOARGS, "Return the current time in seconds since an unspecified reference point." }, | |
1303 { "pause", (PyCFunction) _unix_pause, METH_NOARGS, "Block until a key is pressed." }, | 1350 { "pause", (PyCFunction) _unix_pause, METH_NOARGS, "Block until a key is pressed." }, |
1304 { NULL } | 1351 { NULL } |
1305 }; | 1352 }; |
1306 | 1353 |
1307 #ifdef USE_WAKEUP_FD | 1354 #ifdef USE_WAKEUP_FD |