Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -121,7 +121,7 @@ public void postInitialize(Python3Core core) {
}

@TruffleBoundary
private static void dumpTraceback(PythonLanguage language, PrintWriter writer) {
private static synchronized void dumpTraceback(PythonLanguage language, PrintWriter writer) {
writer.println();
writer.println(Thread.currentThread());
if (PythonOptions.isPExceptionWithJavaStacktrace(language)) {
Expand Down Expand Up @@ -262,7 +262,9 @@ private static void doDumpLater(Node inliningTarget, PythonModule module, long t
do {
sleepInterruptibly(inliningTarget, timeoutNs);
long timeoutS = timeoutNs / 1_000_000_000;
newRawFdPrintWriter(fd).printf("Timeout (%d:%02d:%02d)!%n", timeoutS / 3600, timeoutS / 60, timeoutS);
PrintWriter timeoutWriter = newRawFdPrintWriter(fd);
timeoutWriter.printf("Timeout (%d:%02d:%02d)!%n", timeoutS / 3600, timeoutS / 60, timeoutS);
timeoutWriter.flush();
try {
DumpTracebackNode.dump(context.getLanguage(), context, fd, fileObj, true);
if (exit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ public void setContextVarsContext(PContextVarsContext contextVarsContext) {
this.contextVarsContext = contextVarsContext;
}

public void dispose(PythonContext context, boolean canRunGuestCode) {
public void dispose(PythonContext context, boolean canRunGuestCode, boolean clearNativeThreadLocalVarPointer) {
// This method may be called twice on the same object.

/*
Expand Down Expand Up @@ -498,10 +498,10 @@ public void dispose(PythonContext context, boolean canRunGuestCode) {
* precaution, we just skip this if we cannot run guest code, because it may invoke
* LLVM.
*/
if (nativeThreadLocalVarPointer != null && canRunGuestCode) {
if (nativeThreadLocalVarPointer != null && canRunGuestCode && clearNativeThreadLocalVarPointer) {
CStructAccess.WritePointerNode.writeUncached(nativeThreadLocalVarPointer, 0, context.getNativeNull());
nativeThreadLocalVarPointer = null;
}
nativeThreadLocalVarPointer = null;
}

public Object getTraceFun() {
Expand Down Expand Up @@ -2097,8 +2097,9 @@ public void runShutdownHooks() {
*/
@TruffleBoundary
private void disposeThreadStates() {
for (PythonThreadState ts : threadStateMapping.values()) {
ts.dispose(this, true);
Thread currentThread = Thread.currentThread();
for (Map.Entry<Thread, PythonThreadState> entry : threadStateMapping.entrySet()) {
entry.getValue().dispose(this, true, entry.getKey() == currentThread);
}
threadStateMapping.clear();
}
Expand Down Expand Up @@ -2581,7 +2582,7 @@ public synchronized void disposeThread(Thread thread, boolean canRunGuestCode) {
}
ts.shutdown();
threadStateMapping.remove(thread);
ts.dispose(this, canRunGuestCode);
ts.dispose(this, canRunGuestCode, thread == Thread.currentThread());
releaseSentinelLock(ts.sentinelLock);
getSharedMultiprocessingData().removeChildContextThread(PThread.getThreadId(thread));
}
Expand Down
1 change: 1 addition & 0 deletions graalpython/lib-python/3/test/conftest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ partial_splits_individual_tests = true
selector = [
'test_multiprocessing_spawn',
'test_multiprocessing_main_handling',
'test_tarfile',
]


Expand Down
14 changes: 14 additions & 0 deletions graalpython/lib-python/3/test/test_weakref.py
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,7 @@ def cb(self, ignore):

del alist[:]
gc.collect()
gc_collect() # <- GraalPy change
self.assertEqual(alist, [])

def test_gc_during_ref_creation(self):
Expand All @@ -798,6 +799,7 @@ def check_gc_during_creation(self, makeref):
thresholds = gc.get_threshold()
gc.set_threshold(1, 1, 1)
gc.collect()
gc_collect() # <- GraalPy change
class A:
pass

Expand Down Expand Up @@ -902,6 +904,7 @@ def test_ordering(self):
# Same when dead.
del x, y
gc.collect()
gc_collect() # <- GraalPy change
for op in ops:
self.assertRaises(TypeError, op, a, b)

Expand All @@ -914,6 +917,7 @@ def test_hashing(self):
self.assertEqual(hash(a), hash(42))
del x, y
gc.collect()
gc_collect() # <- GraalPy change
# Dead weakrefs:
# - retain their hash is they were hashed when alive;
# - otherwise, cannot be hashed.
Expand Down Expand Up @@ -1192,6 +1196,7 @@ def _ne(a, b):
_eq(a, ALWAYS_EQ)
del x, y, z
gc.collect()
gc_collect() # <- GraalPy change
# Dead WeakMethods compare by identity
refs = a, b, c, d, e, f
for q in refs:
Expand Down Expand Up @@ -1236,9 +1241,11 @@ def check_len_cycles(self, dict_type, cons):
pass
del items
gc.collect()
gc_collect() # <- GraalPy change
n1 = len(dct)
del it
gc.collect()
gc_collect() # <- GraalPy change
n2 = len(dct)
# one item may be kept alive inside the iterator
self.assertIn(n1, (0, 1))
Expand All @@ -1257,6 +1264,7 @@ def check_len_race(self, dict_type, cons):
for th in range(1, 100):
N = 20
gc.collect(0)
gc_collect() # <- GraalPy change
gc.set_threshold(th, th, th)
items = [RefCycle() for i in range(N)]
dct = dict_type(cons(o) for o in items)
Expand Down Expand Up @@ -1428,6 +1436,7 @@ def check_weak_destroy_while_iterating(self, dict, objects, iter_name):
# Destroy an object
del objects[-1]
gc.collect() # just in case
gc_collect() # <- GraalPy change
# We have removed either the first consumed object, or another one
self.assertIn(len(list(it)), [len(objects), len(objects) - 1])
del it
Expand Down Expand Up @@ -1508,10 +1517,12 @@ def testcontext():
# Schedule a key/value for removal and recreate it
v = objects.pop().arg
gc.collect() # just in case
gc_collect() # <- GraalPy change
yield Object(v), v
finally:
it = None # should commit all removals
gc.collect()
gc_collect() # <- GraalPy change
self.check_weak_destroy_and_mutate_while_iterating(dict, testcontext)
# Issue #21173: len() fragile when keys are both implicitly and
# explicitly removed.
Expand All @@ -1535,10 +1546,12 @@ def testcontext():
# Schedule a key/value for removal and recreate it
k = objects.pop().arg
gc.collect() # just in case
gc_collect() # <- GraalPy change
yield k, Object(k)
finally:
it = None # should commit all removals
gc.collect()
gc_collect() # <- GraalPy change
self.check_weak_destroy_and_mutate_while_iterating(dict, testcontext)
dict, objects = self.make_weak_valued_dict()
self.check_weak_del_and_len_while_iterating(dict, testcontext)
Expand Down Expand Up @@ -1907,6 +1920,7 @@ def pop_and_collect(lst):
lst.pop(i)
if gc_ctr % 10000 == 0:
gc.collect() # just in case
gc_collect() # <- GraalPy change

self.assertIn(type_, (weakref.WeakKeyDictionary, weakref.WeakValueDictionary))

Expand Down
Loading