Skip to content

Commit

Permalink
pythongh-117657: initialize_new_array
Browse files Browse the repository at this point in the history
  • Loading branch information
SonicField committed May 9, 2024
1 parent c68acb1 commit edb7575
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Include/internal/pycore_qsbr.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ _Py_qsbr_register(struct _PyThreadStateImpl *tstate,

// Disassociates a PyThreadState from the QSBR state and frees the QSBR state.
extern void
_Py_qsbr_unregister(struct _PyThreadStateImpl *tstate);
_Py_qsbr_unregister(PyThreadState *tstate);

extern void
_Py_qsbr_fini(PyInterpreterState *interp);
Expand Down
117 changes: 117 additions & 0 deletions Modules/spinner.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#include <Python.h>
#include <time.h>
#include <sched.h>
#include <sys/syscall.h>
#include <unistd.h>

// The set_priority function
static PyObject* set_priority(PyObject* self, PyObject* args) {
int policy, priority;

// Parse the arguments
if (!PyArg_ParseTuple(args, "ii", &policy, &priority)) {
return NULL;
}

// Get the current thread id
pid_t tid = syscall(SYS_gettid);

// Set the scheduling policy and priority
struct sched_param param;
param.sched_priority = priority;
if (sched_setscheduler(tid, policy, &param) != 0) {
return PyErr_SetFromErrno(PyExc_OSError);
}

Py_RETURN_NONE;
}

// The get_priority function
static PyObject* get_priority(PyObject* self, PyObject* args) {
// Get the current thread id
pid_t tid = syscall(SYS_gettid);

// Get the scheduling policy
int policy = sched_getscheduler(tid);
if (policy == -1) {
return PyErr_SetFromErrno(PyExc_OSError);
}

// Get the priority
struct sched_param param;
if (sched_getparam(tid, &param) != 0) {
return PyErr_SetFromErrno(PyExc_OSError);
}

return Py_BuildValue("(ii)", policy, param.sched_priority);
}

// The spin function
static PyObject* spin(PyObject* self, PyObject* args) {
int milliseconds;
double spins;

// Parse the arguments
if (!PyArg_ParseTuple(args, "i", &milliseconds)) {
return NULL;
}

// Save the current state and release the GIL
Py_BEGIN_ALLOW_THREADS

// Get the current time
struct timespec start, now;
clock_gettime(CLOCK_MONOTONIC, &start);

// Calculate the end time
time_t end_sec = start.tv_sec + milliseconds / 1000;
long end_nsec = start.tv_nsec + (milliseconds % 1000) * 1000000;
if (end_nsec >= 1000000000) {
end_sec++;
end_nsec -= 1000000000;
}

// Spitn until the end time
spins = 0;
do {
clock_gettime(CLOCK_MONOTONIC, &now);
++spins;
} while (now.tv_sec < end_sec || (now.tv_sec == end_sec && now.tv_nsec < end_nsec));

// Restore the GIL and the saved state
Py_END_ALLOW_THREADS

return Py_BuildValue("d", spins);
}

// The module's function table
static PyMethodDef SpinnerMethods[] = {
{"set_priority", set_priority, METH_VARARGS, "Set the current thread's priority."},
{"get_priority", get_priority, METH_VARARGS, "Get the current thread's priority."},
{"spin", spin, METH_VARARGS, "Spin the CPU for a specified time."},
// Add other functions here...
{NULL, NULL, 0, NULL}
};

// The module's definition
static struct PyModuleDef spinnermodule = {
PyModuleDef_HEAD_INIT,
"spinner",
"A module that spins the CPU and manages thread priorities.",
-1,
SpinnerMethods
};

// The module's initialization function
PyMODINIT_FUNC PyInit_spinner(void) {
PyObject* m;
m = PyModule_Create(&spinnermodule);
if (m == NULL)
return NULL;
PyModule_AddIntConstant(m, "SCHED_IDLE", SCHED_IDLE);
PyModule_AddIntConstant(m, "SCHED_BATCH", SCHED_BATCH);
PyModule_AddIntConstant(m, "SCHED_OTHER", SCHED_OTHER);
PyModule_AddIntConstant(m, "SCHED_FIFO", SCHED_FIFO);
PyModule_AddIntConstant(m, "SCHED_RR", SCHED_FIFO);
return m;
}
2 changes: 1 addition & 1 deletion Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1785,7 +1785,7 @@ tstate_delete_common(PyThreadState *tstate)
HEAD_UNLOCK(runtime);

#ifdef Py_GIL_DISABLED
_Py_qsbr_unregister((_PyThreadStateImpl *)tstate);
_Py_qsbr_unregister(tstate);
#endif

// XXX Unbind in PyThreadState_Clear(), or earlier
Expand Down
11 changes: 6 additions & 5 deletions Python/qsbr.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,20 +231,21 @@ _Py_qsbr_register(_PyThreadStateImpl *tstate, PyInterpreterState *interp,
}

void
_Py_qsbr_unregister(_PyThreadStateImpl *tstate)
_Py_qsbr_unregister(PyThreadState *tstate)
{
struct _qsbr_shared *shared = tstate->qsbr->shared;
struct _qsbr_shared *shared = &tstate->interp->qsbr;
struct _PyThreadStateImpl *tstate_imp = (_PyThreadStateImpl*) tstate;

PyMutex_Lock(&shared->mutex);
// NOTE: we must load (or reload) the thread state's qbsr inside the mutex
// because the array may have been resized (changing tstate->qsbr) while
// we waited to acquire the mutex.
struct _qsbr_thread_state *qsbr = tstate->qsbr;
struct _qsbr_thread_state *qsbr = tstate_imp->qsbr;

assert(qsbr->seq == 0 && "thread state must be detached");
assert(qsbr->allocated && qsbr->tstate == (PyThreadState *)tstate);
assert(qsbr->allocated && qsbr->tstate == tstate);

tstate->qsbr = NULL;
tstate_imp->qsbr = NULL;
qsbr->tstate = NULL;
qsbr->allocated = false;
qsbr->freelist_next = shared->freelist;
Expand Down
1 change: 0 additions & 1 deletion Tools/tsan/suppressions_free_threading.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ race:_PyParkingLot_Park
race:_PyType_HasFeature
race:assign_version_tag
race:gc_restore_tid
race:initialize_new_array
race:insertdict
race:lookup_tp_dict
race:mi_heap_visit_pages
Expand Down

0 comments on commit edb7575

Please sign in to comment.