Skip to content

Commit

Permalink
closes bpo-31596: Add an interface for pthread_getcpuclockid(3) (#3756)
Browse files Browse the repository at this point in the history
  • Loading branch information
pdox authored and benjaminp committed Oct 5, 2017
1 parent 55fd066 commit e14679c
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 0 deletions.
16 changes: 16 additions & 0 deletions Doc/library/time.rst
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,22 @@ The module defines the following functions and data items:
:func:`perf_counter` or :func:`process_time` instead, depending on your
requirements, to have a well defined behaviour.

.. function:: pthread_getcpuclockid(thread_id)

Return the *clk_id* of the thread-specific CPU-time clock for the specified *thread_id*.

Use :func:`threading.get_ident` or the :attr:`~threading.Thread.ident`
attribute of :class:`threading.Thread` objects to get a suitable value
for *thread_id*.

.. warning::
Passing an invalid or expired *thread_id* may result in
undefined behavior, such as segmentation fault.

Availability: Unix (see the man page for :manpage:`pthread_getcpuclockid(3)` for
further information)

.. versionadded:: 3.7

.. function:: clock_getres(clk_id)

Expand Down
20 changes: 20 additions & 0 deletions Lib/test/test_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import sys
import sysconfig
import time
import threading
import unittest
try:
import _testcapi
Expand Down Expand Up @@ -80,6 +81,25 @@ def test_clock_monotonic(self):
b = time.clock_gettime(time.CLOCK_MONOTONIC)
self.assertLessEqual(a, b)

@unittest.skipUnless(hasattr(time, 'pthread_getcpuclockid'),
'need time.pthread_getcpuclockid()')
@unittest.skipUnless(hasattr(time, 'clock_gettime'),
'need time.clock_gettime()')
@unittest.skipUnless(hasattr(time, 'CLOCK_THREAD_CPUTIME_ID'),
'need time.CLOCK_THREAD_CPUTIME_ID')
def test_pthread_getcpuclockid(self):
clk_id = time.pthread_getcpuclockid(threading.get_ident())
self.assertTrue(type(clk_id) is int)
self.assertNotEqual(clk_id, time.CLOCK_THREAD_CPUTIME_ID)
# This should suffice to show that both calls are measuring the same clock.
t1 = time.clock_gettime(clk_id)
t2 = time.clock_gettime(time.CLOCK_THREAD_CPUTIME_ID)
t3 = time.clock_gettime(clk_id)
t4 = time.clock_gettime(time.CLOCK_THREAD_CPUTIME_ID)
self.assertLessEqual(t1, t2)
self.assertLessEqual(t2, t3)
self.assertLessEqual(t3, t4)

@unittest.skipUnless(hasattr(time, 'clock_getres'),
'need time.clock_getres()')
def test_clock_getres(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added pthread_getcpuclockid() to the time module
32 changes: 32 additions & 0 deletions Modules/timemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
#include <io.h>
#endif

#if defined(HAVE_PTHREAD_H)
# include <pthread.h>
#endif

#if defined(__WATCOMC__) && !defined(__QNX__)
#include <i86.h>
#else
Expand Down Expand Up @@ -221,6 +225,31 @@ PyDoc_STRVAR(clock_getres_doc,
Return the resolution (precision) of the specified clock clk_id.");
#endif /* HAVE_CLOCK_GETRES */

#ifdef HAVE_PTHREAD_GETCPUCLOCKID
static PyObject *
time_pthread_getcpuclockid(PyObject *self, PyObject *args)
{
unsigned long thread_id;
int err;
clockid_t clk_id;
if (!PyArg_ParseTuple(args, "k:pthread_getcpuclockid", &thread_id)) {
return NULL;
}
err = pthread_getcpuclockid((pthread_t)thread_id, &clk_id);
if (err) {
errno = err;
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
}
return PyLong_FromLong(clk_id);
}

PyDoc_STRVAR(pthread_getcpuclockid_doc,
"pthread_getcpuclockid(thread_id) -> int\n\
\n\
Return the clk_id of a thread's CPU time clock.");
#endif /* HAVE_PTHREAD_GETCPUCLOCKID */

static PyObject *
time_sleep(PyObject *self, PyObject *obj)
{
Expand Down Expand Up @@ -1287,6 +1316,9 @@ static PyMethodDef time_methods[] = {
#endif
#ifdef HAVE_CLOCK_GETRES
{"clock_getres", time_clock_getres, METH_VARARGS, clock_getres_doc},
#endif
#ifdef HAVE_PTHREAD_GETCPUCLOCKID
{"pthread_getcpuclockid", time_pthread_getcpuclockid, METH_VARARGS, pthread_getcpuclockid_doc},
#endif
{"sleep", time_sleep, METH_O, sleep_doc},
{"gmtime", time_gmtime, METH_VARARGS, gmtime_doc},
Expand Down
11 changes: 11 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -10480,6 +10480,17 @@ if test "x$ac_cv_func_pthread_atfork" = xyes; then :
#define HAVE_PTHREAD_ATFORK 1
_ACEOF

fi
done

for ac_func in pthread_getcpuclockid
do :
ac_fn_c_check_func "$LINENO" "pthread_getcpuclockid" "ac_cv_func_pthread_getcpuclockid"
if test "x$ac_cv_func_pthread_getcpuclockid" = xyes; then :
cat >>confdefs.h <<_ACEOF
#define HAVE_PTHREAD_GETCPUCLOCKID 1
_ACEOF

fi
done

Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -3025,6 +3025,7 @@ if test "$posix_threads" = "yes"; then
;;
esac])
AC_CHECK_FUNCS(pthread_atfork)
AC_CHECK_FUNCS(pthread_getcpuclockid)
fi


Expand Down
3 changes: 3 additions & 0 deletions pyconfig.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,9 @@
/* Defined for Solaris 2.6 bug in pthread header. */
#undef HAVE_PTHREAD_DESTRUCTOR

/* Define to 1 if you have the `pthread_getcpuclockid' function. */
#undef HAVE_PTHREAD_GETCPUCLOCKID

/* Define to 1 if you have the <pthread.h> header file. */
#undef HAVE_PTHREAD_H

Expand Down

0 comments on commit e14679c

Please sign in to comment.