Skip to content

Commit 0638f68

Browse files
committed
Add a new test and fix some assertion failures.
1 parent ba57d76 commit 0638f68

2 files changed

Lines changed: 32 additions & 9 deletions

File tree

Lib/test/test_interpreters/test_api.py

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2362,14 +2362,17 @@ def test_set___main___attrs(self):
23622362

23632363

23642364
class TestSharedObjectProxy(TestBase):
2365-
def unshareable(self, file=os.devnull):
2365+
def unshareable(self, file=None):
23662366
class Unshareable:
23672367
def __init__(self):
2368-
# This prevents the object from being pickleable
2369-
self.file = open(file, "w+")
2368+
self.file = file
2369+
# Prevents the object from being pickleable
2370+
self._dummy = open(os.devnull)
23702371

23712372
def __del__(self):
2372-
self.file.close()
2373+
self._dummy.close()
2374+
if self.file:
2375+
self.file.write("done")
23732376

23742377
def foo(self):
23752378
return 42
@@ -2401,6 +2404,23 @@ def get_interp(obj):
24012404
finally:
24022405
interp.close()
24032406

2407+
def test_object_collected_after_proxy_closes(self):
2408+
import io
2409+
2410+
buffer = io.StringIO()
2411+
interp = interpreters.create()
2412+
try:
2413+
def write_to_proxy(obj):
2414+
obj.file.write("hello")
2415+
2416+
with interpreters.share(self.unshareable(buffer)) as proxy:
2417+
self.assertFalse(is_pickleable(proxy))
2418+
self.assertIsNone(interp.call(write_to_proxy, proxy))
2419+
2420+
self.assertEqual(buffer.getvalue(), "hellodone")
2421+
finally:
2422+
interp.close()
2423+
24042424

24052425

24062426
if __name__ == '__main__':

Modules/_interpretersmodule.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,7 @@ _sharedobjectproxy_freelist_push(PyObject *mod, SharedObjectProxy *self)
849849
{
850850
module_state *state = get_module_state(mod);
851851
assert(state != NULL);
852+
assert(self->previous == NULL);
852853

853854
// XXX Make an FT wrapper?
854855
#ifdef Py_GIL_DISABLED
@@ -872,11 +873,10 @@ _sharedobjectproxy_freelist_pop(PyObject *mod)
872873
#else
873874
PyObject *top = state->available_proxies;
874875
#endif
875-
FT_ATOMIC_STORE_PTR_RELAXED(state->available_proxies,
876-
top == NULL
877-
? NULL
878-
: (PyObject *)SharedObjectProxy_CAST(top)->next);
879-
876+
if (top != NULL) {
877+
FT_ATOMIC_STORE_PTR_RELAXED(state->available_proxies, (PyObject *)SharedObjectProxy_CAST(top)->next);
878+
SharedObjectProxy_CAST(top)->next = NULL;
879+
}
880880
return (SharedObjectProxy *)top;
881881
}
882882

@@ -897,6 +897,9 @@ _sharedobjectproxy_detach(PyObject *mod, SharedObjectProxy *self)
897897
return -1;
898898
}
899899

900+
// In the freelist, we don't use a doubly linked list.
901+
self->context_id = -1;
902+
self->previous = NULL;
900903
_sharedobjectproxy_freelist_push(mod, self);
901904
return 0;
902905
}

0 commit comments

Comments
 (0)