[vm] Preserve ThreadLocal value if dart::Thread is reclaimed
dart::Thread object representing Isolate's mutator can be reclaimed when thread is suspended, so we need to preserve thread_locals on Isolate itself. TEST=vm/dart/thread_local_test Fixes https://github.com/dart-lang/sdk/issues/63408 Change-Id: I7502b9bc67a07fb2e82479d3052740516a6a6964 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/504921 Commit-Queue: Slava Egorov <vegorov@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
cbb94bc140
commit
bc16ca4d51
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Tests ThreadLocal.
|
||||
//
|
||||
// VMOptions=--experimental-shared-data
|
||||
|
||||
import 'dart:isolate';
|
||||
import 'dart:_vm' show ThreadLocal;
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
import 'package:expect/async_helper.dart';
|
||||
|
||||
@pragma('vm:shared')
|
||||
final ThreadLocal<String> threadLocal = ThreadLocal<String>();
|
||||
|
||||
void main() async {
|
||||
asyncStart();
|
||||
// Make sure that threadLocal retains its value even if underlying
|
||||
// dart::Thread gets reclaimed and recreated.
|
||||
final results = await List.generate(
|
||||
64,
|
||||
(_) => Isolate.run(() async {
|
||||
threadLocal.value = "ok";
|
||||
await Future.delayed(const Duration(milliseconds: 10));
|
||||
return threadLocal.hasValue ? threadLocal.value : "fail";
|
||||
}),
|
||||
).wait;
|
||||
Expect.listEquals(['ok'], results.toSet().toList());
|
||||
asyncEnd();
|
||||
}
|
||||
@@ -7546,7 +7546,6 @@ class ProgramDeserializationRoots : public DeserializationRoots {
|
||||
|
||||
if (Snapshot::IncludesCode(d->kind())) {
|
||||
d->thread()->InitVMConstants();
|
||||
d->thread()->set_thread_locals(Array::empty_array());
|
||||
}
|
||||
|
||||
auto object_store = isolate_group->object_store();
|
||||
|
||||
+2
-1
@@ -791,7 +791,6 @@ char* Dart::InitializeIsolateGroup(Thread* T,
|
||||
ICData::Init();
|
||||
StubCode::Init();
|
||||
T->InitVMConstants();
|
||||
T->set_thread_locals(Array::empty_array());
|
||||
Symbols::Init(IG);
|
||||
Object::FinishInit(IG);
|
||||
Api::InitHandles();
|
||||
@@ -857,6 +856,8 @@ ErrorPtr Dart::InitializeIsolate(Thread* T,
|
||||
I->field_table()->MarkReadyToUse();
|
||||
}
|
||||
|
||||
T->set_thread_locals(Object::empty_array());
|
||||
|
||||
const auto& error =
|
||||
Error::Handle(Z, I->isolate_object_store()->PreallocateObjects());
|
||||
if (!error.IsNull()) {
|
||||
|
||||
@@ -225,6 +225,7 @@ class ObjectPointerVisitor;
|
||||
#define ISOLATE_OBJECT_STORE_FIELD_LIST(R_, RW) \
|
||||
R_(Array, dart_args_1) \
|
||||
R_(Array, dart_args_2) \
|
||||
RW(Array, thread_locals) \
|
||||
R_(GrowableObjectArray, resume_capabilities) \
|
||||
R_(GrowableObjectArray, exit_listeners) \
|
||||
R_(GrowableObjectArray, error_listeners)
|
||||
|
||||
@@ -279,6 +279,9 @@ void Thread::set_default_tag(const UserTag& tag) {
|
||||
}
|
||||
|
||||
void Thread::set_thread_locals(const Array& thread_locals) {
|
||||
if (isolate_ != nullptr) {
|
||||
isolate_->isolate_object_store()->set_thread_locals(thread_locals);
|
||||
}
|
||||
thread_locals_ = thread_locals.ptr();
|
||||
}
|
||||
|
||||
@@ -436,10 +439,6 @@ void Thread::EnterIsolate(Isolate* isolate) {
|
||||
/*bypass_safepoint=*/false);
|
||||
thread->SetupMutatorState();
|
||||
thread->SetupDartMutatorState(isolate);
|
||||
|
||||
if (Array::empty_array().ptr() != nullptr) {
|
||||
thread->set_thread_locals(Array::empty_array());
|
||||
}
|
||||
}
|
||||
|
||||
isolate->scheduled_mutator_thread_ = thread;
|
||||
@@ -1643,6 +1642,7 @@ void Thread::ResetMutatorState() {
|
||||
|
||||
void Thread::SetupDartMutatorState(Isolate* isolate) {
|
||||
field_table_values_ = isolate->field_table_->table();
|
||||
thread_locals_ = isolate->isolate_object_store()->thread_locals();
|
||||
|
||||
SetupDartMutatorStateDependingOnSnapshot(isolate->group());
|
||||
}
|
||||
@@ -1682,6 +1682,7 @@ void Thread::ResetDartMutatorState() {
|
||||
|
||||
field_table_values_ = nullptr;
|
||||
shared_field_table_values_ = nullptr;
|
||||
thread_locals_ = Array::null();
|
||||
ONLY_IN_PRECOMPILED(global_object_pool_ = ObjectPool::null());
|
||||
ONLY_IN_PRECOMPILED(dispatch_table_array_ = nullptr);
|
||||
}
|
||||
|
||||
@@ -178,6 +178,7 @@ void ThreadRegistry::ReturnToFreelistLocked(Thread* thread) {
|
||||
ASSERT(thread->isolate_group_ == nullptr);
|
||||
ASSERT(thread->field_table_values_ == nullptr);
|
||||
ASSERT(thread->shared_field_table_values_ == nullptr);
|
||||
ASSERT(thread->thread_locals_ == Array::null());
|
||||
ASSERT(threads_lock()->IsOwnedByCurrentThread());
|
||||
// Add thread to the free list.
|
||||
thread->next_ = free_list_;
|
||||
|
||||
Reference in New Issue
Block a user