Skip to content

Commit e14679c

Browse files
pdoxbenjaminp
pdox
authored andcommitted
closes bpo-31596: Add an interface for pthread_getcpuclockid(3) (#3756)
1 parent 55fd066 commit e14679c

File tree

7 files changed

+84
-0
lines changed

7 files changed

+84
-0
lines changed

Doc/library/time.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,22 @@ The module defines the following functions and data items:
162162
:func:`perf_counter` or :func:`process_time` instead, depending on your
163163
requirements, to have a well defined behaviour.
164164

165+
.. function:: pthread_getcpuclockid(thread_id)
166+
167+
Return the *clk_id* of the thread-specific CPU-time clock for the specified *thread_id*.
168+
169+
Use :func:`threading.get_ident` or the :attr:`~threading.Thread.ident`
170+
attribute of :class:`threading.Thread` objects to get a suitable value
171+
for *thread_id*.
172+
173+
.. warning::
174+
Passing an invalid or expired *thread_id* may result in
175+
undefined behavior, such as segmentation fault.
176+
177+
Availability: Unix (see the man page for :manpage:`pthread_getcpuclockid(3)` for
178+
further information)
179+
180+
.. versionadded:: 3.7
165181

166182
.. function:: clock_getres(clk_id)
167183

Lib/test/test_time.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import sys
88
import sysconfig
99
import time
10+
import threading
1011
import unittest
1112
try:
1213
import _testcapi
@@ -80,6 +81,25 @@ def test_clock_monotonic(self):
8081
b = time.clock_gettime(time.CLOCK_MONOTONIC)
8182
self.assertLessEqual(a, b)
8283

84+
@unittest.skipUnless(hasattr(time, 'pthread_getcpuclockid'),
85+
'need time.pthread_getcpuclockid()')
86+
@unittest.skipUnless(hasattr(time, 'clock_gettime'),
87+
'need time.clock_gettime()')
88+
@unittest.skipUnless(hasattr(time, 'CLOCK_THREAD_CPUTIME_ID'),
89+
'need time.CLOCK_THREAD_CPUTIME_ID')
90+
def test_pthread_getcpuclockid(self):
91+
clk_id = time.pthread_getcpuclockid(threading.get_ident())
92+
self.assertTrue(type(clk_id) is int)
93+
self.assertNotEqual(clk_id, time.CLOCK_THREAD_CPUTIME_ID)
94+
# This should suffice to show that both calls are measuring the same clock.
95+
t1 = time.clock_gettime(clk_id)
96+
t2 = time.clock_gettime(time.CLOCK_THREAD_CPUTIME_ID)
97+
t3 = time.clock_gettime(clk_id)
98+
t4 = time.clock_gettime(time.CLOCK_THREAD_CPUTIME_ID)
99+
self.assertLessEqual(t1, t2)
100+
self.assertLessEqual(t2, t3)
101+
self.assertLessEqual(t3, t4)
102+
83103
@unittest.skipUnless(hasattr(time, 'clock_getres'),
84104
'need time.clock_getres()')
85105
def test_clock_getres(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added pthread_getcpuclockid() to the time module

Modules/timemodule.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
#include <io.h>
2121
#endif
2222

23+
#if defined(HAVE_PTHREAD_H)
24+
# include <pthread.h>
25+
#endif
26+
2327
#if defined(__WATCOMC__) && !defined(__QNX__)
2428
#include <i86.h>
2529
#else
@@ -221,6 +225,31 @@ PyDoc_STRVAR(clock_getres_doc,
221225
Return the resolution (precision) of the specified clock clk_id.");
222226
#endif /* HAVE_CLOCK_GETRES */
223227

228+
#ifdef HAVE_PTHREAD_GETCPUCLOCKID
229+
static PyObject *
230+
time_pthread_getcpuclockid(PyObject *self, PyObject *args)
231+
{
232+
unsigned long thread_id;
233+
int err;
234+
clockid_t clk_id;
235+
if (!PyArg_ParseTuple(args, "k:pthread_getcpuclockid", &thread_id)) {
236+
return NULL;
237+
}
238+
err = pthread_getcpuclockid((pthread_t)thread_id, &clk_id);
239+
if (err) {
240+
errno = err;
241+
PyErr_SetFromErrno(PyExc_OSError);
242+
return NULL;
243+
}
244+
return PyLong_FromLong(clk_id);
245+
}
246+
247+
PyDoc_STRVAR(pthread_getcpuclockid_doc,
248+
"pthread_getcpuclockid(thread_id) -> int\n\
249+
\n\
250+
Return the clk_id of a thread's CPU time clock.");
251+
#endif /* HAVE_PTHREAD_GETCPUCLOCKID */
252+
224253
static PyObject *
225254
time_sleep(PyObject *self, PyObject *obj)
226255
{
@@ -1287,6 +1316,9 @@ static PyMethodDef time_methods[] = {
12871316
#endif
12881317
#ifdef HAVE_CLOCK_GETRES
12891318
{"clock_getres", time_clock_getres, METH_VARARGS, clock_getres_doc},
1319+
#endif
1320+
#ifdef HAVE_PTHREAD_GETCPUCLOCKID
1321+
{"pthread_getcpuclockid", time_pthread_getcpuclockid, METH_VARARGS, pthread_getcpuclockid_doc},
12901322
#endif
12911323
{"sleep", time_sleep, METH_O, sleep_doc},
12921324
{"gmtime", time_gmtime, METH_VARARGS, gmtime_doc},

configure

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10480,6 +10480,17 @@ if test "x$ac_cv_func_pthread_atfork" = xyes; then :
1048010480
#define HAVE_PTHREAD_ATFORK 1
1048110481
_ACEOF
1048210482

10483+
fi
10484+
done
10485+
10486+
for ac_func in pthread_getcpuclockid
10487+
do :
10488+
ac_fn_c_check_func "$LINENO" "pthread_getcpuclockid" "ac_cv_func_pthread_getcpuclockid"
10489+
if test "x$ac_cv_func_pthread_getcpuclockid" = xyes; then :
10490+
cat >>confdefs.h <<_ACEOF
10491+
#define HAVE_PTHREAD_GETCPUCLOCKID 1
10492+
_ACEOF
10493+
1048310494
fi
1048410495
done
1048510496

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3025,6 +3025,7 @@ if test "$posix_threads" = "yes"; then
30253025
;;
30263026
esac])
30273027
AC_CHECK_FUNCS(pthread_atfork)
3028+
AC_CHECK_FUNCS(pthread_getcpuclockid)
30283029
fi
30293030

30303031

pyconfig.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,9 @@
694694
/* Defined for Solaris 2.6 bug in pthread header. */
695695
#undef HAVE_PTHREAD_DESTRUCTOR
696696

697+
/* Define to 1 if you have the `pthread_getcpuclockid' function. */
698+
#undef HAVE_PTHREAD_GETCPUCLOCKID
699+
697700
/* Define to 1 if you have the <pthread.h> header file. */
698701
#undef HAVE_PTHREAD_H
699702

0 commit comments

Comments
 (0)