Skip to content

Commit d3ad082

Browse files
committed
Address review comments: use _Py_LOCK_DONT_DETACH, atomic OR/AND, _PyOnceFlag
1 parent fd936f3 commit d3ad082

File tree

4 files changed

+31
-17
lines changed

4 files changed

+31
-17
lines changed

Include/internal/pycore_dict_state.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11-
#include "pycore_lock.h" // PyMutex
12-
1311
#define DICT_MAX_WATCHERS 8
1412
#define DICT_WATCHED_MUTATION_BITS 4
1513

1614
struct _Py_dict_state {
1715
uint32_t next_keys_version;
18-
PyDict_WatchCallback watchers[DICT_MAX_WATCHERS];
1916
PyMutex watcher_mutex; // Protects the watchers array (free-threaded builds)
17+
_PyOnceFlag watcher_setup_once; // One-time optimizer watcher setup
18+
PyDict_WatchCallback watchers[DICT_MAX_WATCHERS];
2019
};
2120

2221
#define _dict_state_INIT \

Include/internal/pycore_pyatomic_ft_wrappers.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,12 @@ extern "C" {
129129
(void)_Py_atomic_add_ssize(&value, new_value)
130130
#define FT_ATOMIC_ADD_UINT64(value, new_value) \
131131
(void)_Py_atomic_add_uint64(&value, new_value)
132+
#define FT_ATOMIC_OR_UINT64(value, new_value) \
133+
(void)_Py_atomic_or_uint64(&value, new_value)
134+
#define FT_ATOMIC_AND_UINT64(value, new_value) \
135+
(void)_Py_atomic_and_uint64(&value, new_value)
132136
#define FT_MUTEX_LOCK(lock) PyMutex_Lock(lock)
137+
#define FT_MUTEX_LOCK_FLAGS(lock, flags) PyMutex_LockFlags(lock, flags)
133138
#define FT_MUTEX_UNLOCK(lock) PyMutex_Unlock(lock)
134139

135140
#else
@@ -188,7 +193,10 @@ extern "C" {
188193
#define FT_ATOMIC_STORE_ULLONG_RELAXED(value, new_value) value = new_value
189194
#define FT_ATOMIC_ADD_SSIZE(value, new_value) (void)(value += new_value)
190195
#define FT_ATOMIC_ADD_UINT64(value, new_value) (void)(value += new_value)
196+
#define FT_ATOMIC_OR_UINT64(value, new_value) (void)(value |= new_value)
197+
#define FT_ATOMIC_AND_UINT64(value, new_value) (void)(value &= new_value)
191198
#define FT_MUTEX_LOCK(lock) do {} while (0)
199+
#define FT_MUTEX_LOCK_FLAGS(lock, flags) do {} while (0)
192200
#define FT_MUTEX_UNLOCK(lock) do {} while (0)
193201

194202
#endif

Objects/dictobject.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7866,9 +7866,8 @@ PyDict_Watch(int watcher_id, PyObject* dict)
78667866
if (validate_watcher_id(interp, watcher_id)) {
78677867
return -1;
78687868
}
7869-
Py_BEGIN_CRITICAL_SECTION(dict);
7870-
((PyDictObject*)dict)->_ma_watcher_tag |= (1ULL << watcher_id);
7871-
Py_END_CRITICAL_SECTION();
7869+
FT_ATOMIC_OR_UINT64(((PyDictObject*)dict)->_ma_watcher_tag,
7870+
1ULL << watcher_id);
78727871
return 0;
78737872
}
78747873

@@ -7883,9 +7882,8 @@ PyDict_Unwatch(int watcher_id, PyObject* dict)
78837882
if (validate_watcher_id(interp, watcher_id)) {
78847883
return -1;
78857884
}
7886-
Py_BEGIN_CRITICAL_SECTION(dict);
7887-
((PyDictObject*)dict)->_ma_watcher_tag &= ~(1ULL << watcher_id);
7888-
Py_END_CRITICAL_SECTION();
7885+
FT_ATOMIC_AND_UINT64(((PyDictObject*)dict)->_ma_watcher_tag,
7886+
~(1ULL << watcher_id));
78897887
return 0;
78907888
}
78917889

@@ -7895,7 +7893,8 @@ PyDict_AddWatcher(PyDict_WatchCallback callback)
78957893
int watcher_id = -1;
78967894
PyInterpreterState *interp = _PyInterpreterState_GET();
78977895

7898-
FT_MUTEX_LOCK(&interp->dict_state.watcher_mutex);
7896+
FT_MUTEX_LOCK_FLAGS(&interp->dict_state.watcher_mutex,
7897+
_Py_LOCK_DONT_DETACH);
78997898
/* Some watchers are reserved for CPython, start at the first available one */
79007899
for (int i = FIRST_AVAILABLE_WATCHER; i < DICT_MAX_WATCHERS; i++) {
79017900
if (!interp->dict_state.watchers[i]) {
@@ -7915,7 +7914,8 @@ PyDict_ClearWatcher(int watcher_id)
79157914
{
79167915
int res = 0;
79177916
PyInterpreterState *interp = _PyInterpreterState_GET();
7918-
FT_MUTEX_LOCK(&interp->dict_state.watcher_mutex);
7917+
FT_MUTEX_LOCK_FLAGS(&interp->dict_state.watcher_mutex,
7918+
_Py_LOCK_DONT_DETACH);
79197919
if (validate_watcher_id(interp, watcher_id)) {
79207920
res = -1;
79217921
goto done;

Python/optimizer_analysis.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,17 @@ type_watcher_callback(PyTypeObject* type)
155155
return 0;
156156
}
157157

158+
static int
159+
_setup_optimizer_watchers(void *Py_UNUSED(arg))
160+
{
161+
PyInterpreterState *interp = _PyInterpreterState_GET();
162+
FT_ATOMIC_STORE_PTR_RELEASE(
163+
interp->dict_state.watchers[GLOBALS_WATCHER_ID],
164+
globals_watcher_callback);
165+
interp->type_watchers[TYPE_WATCHER_ID] = type_watcher_callback;
166+
return 0;
167+
}
168+
158169
static PyObject *
159170
convert_global_to_const(_PyUOpInstruction *inst, PyObject *obj, bool pop, bool insert)
160171
{
@@ -469,12 +480,8 @@ optimize_uops(
469480

470481
// Make sure that watchers are set up
471482
PyInterpreterState *interp = _PyInterpreterState_GET();
472-
if (FT_ATOMIC_LOAD_PTR_RELAXED(interp->dict_state.watchers[GLOBALS_WATCHER_ID]) == NULL) {
473-
FT_ATOMIC_STORE_PTR_RELEASE(
474-
interp->dict_state.watchers[GLOBALS_WATCHER_ID],
475-
globals_watcher_callback);
476-
interp->type_watchers[TYPE_WATCHER_ID] = type_watcher_callback;
477-
}
483+
_PyOnceFlag_CallOnce(&interp->dict_state.watcher_setup_once,
484+
_setup_optimizer_watchers, NULL);
478485

479486
_Py_uop_abstractcontext_init(ctx, dependencies);
480487
_Py_UOpsAbstractFrame *frame = _Py_uop_frame_new(ctx, (PyCodeObject *)func->func_code, NULL, 0);

0 commit comments

Comments
 (0)