static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime);
_Py_COMP_DIAG_POP
-#define NUMLOCKS 6
+#define NUMLOCKS 7
#define LOCKS_INIT(runtime) \
{ \
&(runtime)->interpreters.mutex, \
&(runtime)->unicode_state.ids.lock, \
&(runtime)->imports.extensions.mutex, \
&(runtime)->atexit.mutex, \
+ &(runtime)->audit_hooks.mutex, \
}
static int
runtime->open_code_hook = open_code_hook;
runtime->open_code_userdata = open_code_userdata;
- runtime->audit_hook_head = audit_hook_head;
+ runtime->audit_hooks.head = audit_hook_head;
PyPreConfig_InitPythonConfig(&runtime->preconfig);
initialization and interpreter initialization. */
void *open_code_hook = runtime->open_code_hook;
void *open_code_userdata = runtime->open_code_userdata;
- _Py_AuditHookEntry *audit_hook_head = runtime->audit_hook_head;
+ _Py_AuditHookEntry *audit_hook_head = runtime->audit_hooks.head;
// bpo-42882: Preserve next_index value if Py_Initialize()/Py_Finalize()
// is called multiple times.
Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index;
if (!interp) {
return 0;
}
- return (interp->runtime->audit_hook_head
+ return (interp->runtime->audit_hooks.head
|| interp->audit_hooks
|| PyDTrace_AUDIT_ENABLED());
}
goto exit;
}
- /* Call global hooks */
- _Py_AuditHookEntry *e = is->runtime->audit_hook_head;
+ /* Call global hooks
+ *
+ * We don't worry about any races on hooks getting added,
+ * since that would not leave is in an inconsistent state. */
+ _Py_AuditHookEntry *e = is->runtime->audit_hooks.head;
for (; e; e = e->next) {
if (e->hookCFunction(event, eventArgs, e->userData) < 0) {
goto exit;
_PySys_Audit(ts, "cpython._PySys_ClearAuditHooks", NULL);
_PyErr_Clear(ts);
- _Py_AuditHookEntry *e = runtime->audit_hook_head, *n;
- runtime->audit_hook_head = NULL;
+ /* We don't worry about the very unlikely race right here,
+ * since it's entirely benign. Nothing else removes entries
+ * from the list and adding an entry right now would not cause
+ * any trouble. */
+ _Py_AuditHookEntry *e = runtime->audit_hooks.head, *n;
+ runtime->audit_hooks.head = NULL;
while (e) {
n = e->next;
PyMem_RawFree(e);
}
}
+static void
+add_audit_hook_entry_unlocked(_PyRuntimeState *runtime,
+ _Py_AuditHookEntry *entry)
+{
+ if (runtime->audit_hooks.head == NULL) {
+ runtime->audit_hooks.head = entry;
+ }
+ else {
+ _Py_AuditHookEntry *last = runtime->audit_hooks.head;
+ while (last->next) {
+ last = last->next;
+ }
+ last->next = entry;
+ }
+}
+
int
PySys_AddAuditHook(Py_AuditHookFunction hook, void *userData)
{
}
}
- _Py_AuditHookEntry *e = runtime->audit_hook_head;
- if (!e) {
- e = (_Py_AuditHookEntry*)PyMem_RawMalloc(sizeof(_Py_AuditHookEntry));
- runtime->audit_hook_head = e;
- } else {
- while (e->next) {
- e = e->next;
- }
- e = e->next = (_Py_AuditHookEntry*)PyMem_RawMalloc(
+ _Py_AuditHookEntry *e = (_Py_AuditHookEntry*)PyMem_RawMalloc(
sizeof(_Py_AuditHookEntry));
- }
-
if (!e) {
if (tstate != NULL) {
_PyErr_NoMemory(tstate);
}
return -1;
}
-
e->next = NULL;
e->hookCFunction = (Py_AuditHookFunction)hook;
e->userData = userData;
+ if (runtime->audit_hooks.mutex == NULL) {
+ /* The runtime must not be initailized yet. */
+ add_audit_hook_entry_unlocked(runtime, e);
+ }
+ else {
+ PyThread_acquire_lock(runtime->audit_hooks.mutex, WAIT_LOCK);
+ add_audit_hook_entry_unlocked(runtime, e);
+ PyThread_release_lock(runtime->audit_hooks.mutex);
+ }
+
return 0;
}