Flutter Engine
The Flutter Engine
thread_test.cc
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/assert.h"
6#include "vm/heap/safepoint.h"
7#include "vm/isolate.h"
8#include "vm/lockers.h"
9#include "vm/profiler.h"
10#include "vm/stack_frame.h"
11#include "vm/symbols.h"
12#include "vm/thread_pool.h"
13#include "vm/unit_test.h"
14
15namespace dart {
16
18 // This unit test case needs a running isolate.
20 Mutex* mutex = new Mutex();
21 mutex->Lock();
22 EXPECT_EQ(false, mutex->TryLock());
23 mutex->Unlock();
24 EXPECT_EQ(true, mutex->TryLock());
25 mutex->Unlock();
26 {
27 MutexLocker ml(mutex);
28 EXPECT_EQ(false, mutex->TryLock());
29 }
30 // The isolate shutdown and the destruction of the mutex are out-of-order on
31 // purpose.
33 delete mutex;
34}
35
36#if !defined(PRODUCT)
38 // This unit test case needs a running isolate.
40 OSThread* thread = OSThread::Current();
41 // Thread interrupter interferes with this test, disable interrupts.
43 Monitor* monitor = new Monitor();
44 monitor->Enter();
45 monitor->Exit();
46 EXPECT_EQ(true, monitor->TryEnter());
47 monitor->Exit();
48
49 const int kNumAttempts = 5;
50 int attempts = 0;
51 while (attempts < kNumAttempts) {
52 MonitorLocker ml(monitor);
54 int64_t wait_time = 2017;
55 Monitor::WaitResult wait_result = ml.Wait(wait_time);
56 int64_t stop = OS::GetCurrentMonotonicMicros();
57
58 // We expect to be timing out here.
59 EXPECT_EQ(Monitor::kTimedOut, wait_result);
60
61 // Check whether this attempt falls within the expected time limits.
62 int64_t wakeup_time = (stop - start) / kMicrosecondsPerMillisecond;
63 OS::PrintErr("wakeup_time: %" Pd64 "\n", wakeup_time);
64 const int kAcceptableTimeJitter = 20; // Measured in milliseconds.
65 const int kAcceptableWakeupDelay = 150; // Measured in milliseconds.
66 if (((wait_time - kAcceptableTimeJitter) <= wakeup_time) &&
67 (wakeup_time <= (wait_time + kAcceptableWakeupDelay))) {
68 break;
69 }
70
71 // Record the attempt.
72 attempts++;
73 }
74 EXPECT_LT(attempts, kNumAttempts);
75
76 // The isolate shutdown and the destruction of the mutex are out-of-order on
77 // purpose.
79 delete monitor;
80}
81#endif
82
84 public:
86 : ObjectPointerVisitor(isolate_group), obj_(obj), count_(0) {}
87
88 void VisitPointers(ObjectPtr* first, ObjectPtr* last) override {
89 for (ObjectPtr* current = first; current <= last; ++current) {
90 if (*current == obj_->ptr()) {
91 ++count_;
92 }
93 }
94 }
95
96#if defined(DART_COMPRESSED_POINTERS)
97 void VisitCompressedPointers(uword heap_base,
99 CompressedObjectPtr* last) override {
100 for (CompressedObjectPtr* current = first; current <= last; ++current) {
101 if (current->Decompress(heap_base) == obj_->ptr()) {
102 ++count_;
103 }
104 }
105 }
106#endif
107
108 intptr_t count() const { return count_; }
109
110 private:
111 const Object* obj_;
112 intptr_t count_;
113};
114
116 public:
118 Monitor* monitor,
119 bool* done,
120 intptr_t id)
121 : isolate_group_(isolate_group),
122 monitor_(monitor),
123 done_(done),
124 id_(id) {}
125 virtual void Run() {
126 const bool kBypassSafepoint = false;
128 kBypassSafepoint);
129 {
130 Thread* thread = Thread::Current();
131 // Create a zone (which is also a stack resource) and exercise it a bit.
132 StackZone stack_zone(thread);
133 Zone* zone = thread->zone();
134 EXPECT_EQ(zone, stack_zone.GetZone());
135 ZoneGrowableArray<bool>* a0 = new (zone) ZoneGrowableArray<bool>(zone, 1);
136 GrowableArray<bool> a1(zone, 1);
137 for (intptr_t i = 0; i < 100000; ++i) {
138 a0->Add(true);
139 a1.Add(true);
140 }
141 // Check that we can create handles and allocate in old space.
142 String& str = String::Handle(zone, String::New("old", Heap::kOld));
143 EXPECT(str.Equals("old"));
144
145 const intptr_t unique_smi = id_ + 928327281;
146 Smi& smi = Smi::Handle(zone, Smi::New(unique_smi));
147 EXPECT(smi.Value() == unique_smi);
148 {
149 HeapIterationScope iteration(thread);
150 ObjectCounter counter(isolate_group_, &smi);
151 // Ensure that our particular zone is visited.
152 iteration.IterateStackPointers(&counter,
154 EXPECT_EQ(1, counter.count());
155 }
156 char* unique_chars = zone->PrintToString("unique_str_%" Pd, id_);
157 String& unique_str = String::Handle(zone);
158 {
159 // String::New may create additional handles in the topmost scope that
160 // we don't want to count, so wrap this in its own scope.
161 HANDLESCOPE(thread);
162 unique_str = String::New(unique_chars, Heap::kOld);
163 }
164 EXPECT(unique_str.Equals(unique_chars));
165 {
166 HeapIterationScope iteration(thread);
167 ObjectCounter str_counter(isolate_group_, &unique_str);
168 // Ensure that our particular zone is visited.
169 iteration.IterateStackPointers(&str_counter,
171 // We should visit the string object exactly once.
172 EXPECT_EQ(1, str_counter.count());
173 }
174 }
175 Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
176 {
177 MonitorLocker ml(monitor_);
178 *done_ = true;
179 ml.Notify();
180 }
181 }
182
183 private:
184 IsolateGroup* isolate_group_;
185 Monitor* monitor_;
186 bool* done_;
187 intptr_t id_;
188};
189
190ISOLATE_UNIT_TEST_CASE(ManyTasksWithZones) {
191 const int kTaskCount = 100;
192 Monitor sync[kTaskCount];
193 bool done[kTaskCount];
194 auto isolate = thread->isolate();
195 auto isolate_group = thread->isolate_group();
196 for (int i = 0; i < kTaskCount; i++) {
197 done[i] = false;
198 Dart::thread_pool()->Run<TaskWithZoneAllocation>(isolate_group, &sync[i],
199 &done[i], i);
200 }
201 bool in_isolate = true;
202 for (int i = 0; i < kTaskCount; i++) {
203 // Check that main mutator thread can still freely use its own zone.
204 String& bar = String::Handle(String::New("bar"));
205 if (i % 10 == 0) {
206 // Mutator thread is free to independently move in/out/between isolates.
208 in_isolate = false;
209 }
210 MonitorLocker ml(&sync[i]);
211 while (!done[i]) {
212 if (in_isolate) {
213 ml.WaitWithSafepointCheck(thread);
214 } else {
215 ml.Wait();
216 }
217 }
218 EXPECT(done[i]);
219 if (i % 10 == 0) {
220 Thread::EnterIsolate(isolate);
221 in_isolate = true;
222 }
223 EXPECT(bar.Equals("bar"));
224 }
225}
226
227#ifndef PRODUCT
229 public:
231 IsolateGroup* isolate_group,
232 Thread** thread_ptr,
233 Monitor* sync,
234 Monitor* monitor,
235 intptr_t* done_count,
236 bool* wait)
237 : id_(id),
238 isolate_group_(isolate_group),
239 thread_ptr_(thread_ptr),
240 sync_(sync),
241 monitor_(monitor),
242 done_count_(done_count),
243 wait_(wait) {}
244
245 virtual void Run() {
246 const bool kBypassSafepoint = false;
248 kBypassSafepoint);
249 {
250 Thread* thread = Thread::Current();
251 *thread_ptr_ = thread;
252 CreateStackZones(id_);
253 }
254 Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
255 // Notify the main thread that this thread has exited.
256 {
257 MonitorLocker ml(monitor_);
258 *done_count_ += 1;
259 ml.Notify();
260 }
261 }
262
263 private:
264 void CreateStackZones(intptr_t num) {
265 Thread* thread = Thread::Current();
266 *thread_ptr_ = thread;
267
268 StackZone stack_zone(thread);
269 Zone* zone = thread->zone();
270 EXPECT_EQ(zone, stack_zone.GetZone());
271
272 // Create a zone (which is also a stack resource) and exercise it a bit.
273 ZoneGrowableArray<bool>* a0 = new (zone) ZoneGrowableArray<bool>(zone, 1);
274 GrowableArray<bool> a1(zone, 1);
275 for (intptr_t i = 0; i < 1000 * num + id_; ++i) {
276 a0->Add(true);
277 a1.Add(true);
278 }
279
280 num -= 1;
281 if (num != 0) {
282 CreateStackZones(num);
283 return;
284 }
285 {
286 // Let the main thread know we're done with memory ops on this thread.
287 MonitorLocker ml(monitor_);
288 *done_count_ += 1;
289 ml.Notify();
290 }
291 // Wait for the go-ahead from the main thread to exit.
292 {
293 MonitorLocker sync_ml(sync_);
294 while (*wait_) {
295 sync_ml.Wait();
296 }
297 }
298 }
299
300 intptr_t id_;
301 IsolateGroup* isolate_group_;
302 Thread** thread_ptr_;
303 Monitor* sync_;
304 Monitor* monitor_;
305 intptr_t* done_count_;
306 bool* wait_;
307};
308
309ISOLATE_UNIT_TEST_CASE(ManySimpleTasksWithZones) {
310 const int kTaskCount = 10;
311 Monitor monitor;
312 Monitor sync;
313 Thread* threads[kTaskCount];
314 auto isolate_group = thread->isolate_group();
315 intptr_t done_count = 0;
316 bool wait = true;
317
318 EXPECT(!thread->force_growth());
319
320 ForceGrowthScope no_heap_growth_scope(thread);
321
322 for (intptr_t i = 0; i < kTaskCount; i++) {
324 (i + 1), isolate_group, &threads[i], &sync, &monitor, &done_count,
325 &wait);
326 }
327 // Wait until all spawned tasks finish their memory operations.
328 {
329 MonitorLocker ml(&monitor);
330 while (done_count < kTaskCount) {
331 ml.Wait();
332 }
333 // Reset the done counter for use later.
334 done_count = 0;
335 }
336
337 // Unblock the tasks so they can finish.
338 {
339 MonitorLocker sync_ml(&sync);
340 wait = false;
341 sync_ml.NotifyAll();
342 }
343 // Now wait for them all to exit before destroying the isolate.
344 {
345 MonitorLocker ml(&monitor);
346 while (done_count < kTaskCount) {
347 ml.Wait();
348 }
349 }
350}
351#endif
352
354 Isolate* orig = Thread::Current()->isolate();
355 Zone* orig_zone = Thread::Current()->zone();
356 char* orig_str = orig_zone->PrintToString("foo");
358 // Create and enter a new isolate.
360 Zone* zone0 = Thread::Current()->zone();
361 EXPECT(zone0 != orig_zone);
363 // Create and enter yet another isolate.
365 {
366 // Create a stack resource this time, and exercise it.
368 StackZone stack_zone(Thread::Current());
369 Zone* zone1 = Thread::Current()->zone();
370 EXPECT(zone1 != zone0);
371 EXPECT(zone1 != orig_zone);
372 }
374 Dart_EnterIsolate(reinterpret_cast<Dart_Isolate>(orig));
375 // Original zone should be preserved.
376 EXPECT_EQ(orig_zone, Thread::Current()->zone());
377 EXPECT_STREQ("foo", orig_str);
378}
379
380// A helper thread that repeatedly reads ICData
382 public:
383 static constexpr intptr_t kTaskCount = 1;
384
386 const Array& ic_datas,
387 Monitor* monitor,
388 intptr_t* exited,
389 std::atomic<bool>* done)
390 : isolate_group_(isolate_group),
391 ic_datas_(ic_datas),
392 len_(ic_datas.Length()),
393 monitor_(monitor),
394 exited_(exited),
395 done_(done) {}
396
397 virtual void Run() {
398 const bool kBypassSafepoint = false;
400 kBypassSafepoint);
401
402 Thread* thread = Thread::Current();
403
404 {
405 StackZone stack_zone(thread);
406
407 ICData& ic_data = ICData::Handle();
408 Array& arr = Array::Handle();
409 while (true) {
410 for (intptr_t cnt = 0; cnt < 0x1000; cnt++) {
411 for (intptr_t i = 0; i < len_; i++) {
412 ic_data ^= ic_datas_.AtAcquire(i);
413 arr = ic_data.entries();
414 intptr_t num_checks = arr.Length() / 3;
415 if (num_checks < 0 || num_checks > 5) {
416 OS::PrintErr("Failure: %" Pd " checks!\n", num_checks);
417 abort();
418 }
419 }
420 }
421
422 if (done_->load(std::memory_order_acquire)) {
423 break;
424 }
425
426 TransitionVMToBlocked blocked(thread);
427 }
428 }
429
430 Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
431 {
432 MonitorLocker ml(monitor_);
433 ++*exited_;
434 ml.Notify();
435 }
436 }
437
438 private:
439 IsolateGroup* isolate_group_;
440 const Array& ic_datas_;
441 const intptr_t len_;
442 Monitor* monitor_;
443 intptr_t* exited_; // # tasks that are no longer running.
444 std::atomic<bool>* done_; // Signal that helper threads can stop working.
445};
446
447static Function* CreateFunction(const char* name) {
448 const String& class_name =
450 const Script& script = Script::Handle();
451 const Library& lib = Library::Handle(Library::New(class_name));
452 const Class& owner_class = Class::Handle(
453 Class::New(lib, class_name, script, TokenPosition::kNoSource));
454 const String& function_name =
458 signature, function_name, UntaggedFunction::kRegularFunction, true, false,
459 false, false, false, owner_class, TokenPosition::kNoSource));
460 return &function;
461}
462
463// Test that checks that other threads only see a fully initialized ICData
464// whenever ICData is updated.
466 auto isolate_group = thread->isolate_group();
467 USE(isolate_group);
468 Monitor monitor;
469 intptr_t exited = 0;
470 std::atomic<bool> done = {false};
471
472 const intptr_t kNumICData = 0x10;
473
474 const Array& ic_datas = Array::Handle(Array::New(kNumICData));
475 ICData& ic_data = ICData::Handle();
476 Function& owner = *CreateFunction("DummyFunction");
477 String& name = String::Handle(Symbols::New(thread, "foo"));
478 const Array& args_desc =
479 Array::Handle(ArgumentsDescriptor::NewBoxed(0, 0, Object::empty_array()));
480 for (intptr_t i = 0; i < kNumICData; i++) {
481 ic_data = ICData::New(owner, name, args_desc, /*deopt_id=*/0,
482 /*num_args_tested=*/1, ICData::kInstance,
483 Object::null_abstract_type());
484 ic_datas.SetAtRelease(i, ic_data);
485 }
486
487 for (int i = 0; i < ICDataTestTask::kTaskCount; i++) {
488 Dart::thread_pool()->Run<ICDataTestTask>(isolate_group, ic_datas, &monitor,
489 &exited, &done);
490 }
491
492 for (int i = 0; i < 0x10000; i++) {
493 for (intptr_t i = 0; i < kNumICData; i++) {
494 ic_data ^= ic_datas.At(i);
495 if (ic_data.NumberOfChecks() < 4) {
496 ic_data.AddReceiverCheck(kInstanceCid + ic_data.NumberOfChecks(), owner,
497 1);
498 } else {
499 ic_data = ICData::New(owner, name, args_desc, /*deopt_id=*/0,
500 /*num_args_tested=*/1, ICData::kInstance,
501 Object::null_abstract_type());
502 ic_datas.SetAtRelease(i, ic_data);
503 }
504 }
505 }
506 // Ensure we looped long enough to allow all helpers to succeed and exit.
507 {
508 done.store(true, std::memory_order_release);
509 MonitorLocker ml(&monitor);
510 while (exited != ICDataTestTask::kTaskCount) {
511 ml.Wait();
512 }
513 EXPECT_EQ(ICDataTestTask::kTaskCount, exited);
514 }
515}
516
517// A helper thread that alternatingly cooperates and organizes
518// safepoint rendezvous. At rendezvous, it explicitly visits the
519// stacks looking for a specific marker (Smi) to verify that the expected
520// number threads are actually visited. The task is "done" when it has
521// successfully made all other tasks and the main thread rendezvous (may
522// not happen in the first rendezvous, since tasks are still starting up).
524 public:
525 static constexpr intptr_t kTaskCount = 5;
526
528 Monitor* monitor,
529 intptr_t* expected_count,
530 intptr_t* total_done,
531 intptr_t* exited)
532 : isolate_(isolate),
533 monitor_(monitor),
534 expected_count_(expected_count),
535 total_done_(total_done),
536 exited_(exited),
537 local_done_(false) {}
538
539 virtual void Run() {
540 const bool kBypassSafepoint = false;
542 kBypassSafepoint);
543 {
544 MonitorLocker ml(monitor_);
545 ++*expected_count_;
546 }
547 Thread* thread = Thread::Current();
548 for (int i = reinterpret_cast<intptr_t>(thread);; ++i) {
549 StackZone stack_zone(thread);
550 Zone* zone = thread->zone();
551 const intptr_t kUniqueSmi = 928327281;
552 Smi& smi = Smi::Handle(zone, Smi::New(kUniqueSmi));
553 if ((i % 100) != 0) {
554 // Usually, we just cooperate.
555 TransitionVMToBlocked transition(thread);
556 } else {
557 // But occasionally, organize a rendezvous.
558 HeapIterationScope iteration(thread); // Establishes a safepoint.
559 ASSERT(thread->OwnsSafepoint());
560 ObjectCounter counter(isolate_->group(), &smi);
561 iteration.IterateStackPointers(&counter,
563 {
564 MonitorLocker ml(monitor_);
565 EXPECT_EQ(*expected_count_, counter.count());
566 }
567 UserTag& tag = UserTag::Handle(zone, isolate_->current_tag());
568 if (tag.ptr() != isolate_->default_tag()) {
569 String& label = String::Handle(zone, tag.label());
570 EXPECT(label.Equals("foo"));
571 MonitorLocker ml(monitor_);
572 if (*expected_count_ == kTaskCount && !local_done_) {
573 // Success for the first time! Remember that we are done, and
574 // update the total count.
575 local_done_ = true;
576 ++*total_done_;
577 }
578 }
579 }
580 // Check whether everyone is done.
581 {
582 MonitorLocker ml(monitor_);
583 if (*total_done_ == kTaskCount) {
584 // Another task might be at SafepointThreads when resuming. Ensure its
585 // expectation reflects reality, since we pop our handles here.
586 --*expected_count_;
587 break;
588 }
589 }
590 }
591 Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
592 {
593 MonitorLocker ml(monitor_);
594 ++*exited_;
595 ml.Notify();
596 }
597 }
598
599 private:
600 Isolate* isolate_;
601 Monitor* monitor_;
602 intptr_t* expected_count_; // # copies of kUniqueSmi we expect to visit.
603 intptr_t* total_done_; // # tasks that successfully safepointed once.
604 intptr_t* exited_; // # tasks that are no longer running.
605 bool local_done_; // this task has successfully safepointed >= once.
606};
607
608// Test rendezvous of:
609// - helpers in VM code,
610// - main thread in pure Dart,
611// organized by
612// - helpers.
613TEST_CASE(SafepointTestDart) {
614 Isolate* isolate = Thread::Current()->isolate();
615 Monitor monitor;
616 intptr_t expected_count = 0;
617 intptr_t total_done = 0;
618 intptr_t exited = 0;
619 for (int i = 0; i < SafepointTestTask::kTaskCount; i++) {
621 isolate, &monitor, &expected_count, &total_done, &exited);
622 }
623// Run Dart code on the main thread long enough to allow all helpers
624// to get their verification done and exit. Use a specific UserTag
625// to enable the helpers to verify that the main thread is
626// successfully interrupted in the pure Dart loop.
627#if defined(USING_SIMULATOR)
628 const intptr_t kLoopCount = 12345678;
629#else
630 const intptr_t kLoopCount = 1234567890;
631#endif // defined(USING_SIMULATOR)
632 char buffer[1024];
634 "import 'dart:developer';\n"
635 "int dummy = 0;\n"
636 "main() {\n"
637 " new UserTag('foo').makeCurrent();\n"
638 " for (dummy = 0; dummy < %" Pd
639 "; ++dummy) {\n"
640 " dummy += (dummy & 1);\n"
641 " }\n"
642 "}\n",
643 kLoopCount);
645 EXPECT_VALID(lib);
646 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
648 // Ensure we looped long enough to allow all helpers to succeed and exit.
649 {
650 MonitorLocker ml(&monitor);
651 while (exited != SafepointTestTask::kTaskCount) {
652 ml.Wait();
653 }
654 EXPECT_EQ(SafepointTestTask::kTaskCount, total_done);
655 EXPECT_EQ(SafepointTestTask::kTaskCount, exited);
656 }
657}
658
659// Test rendezvous of:
660// - helpers in VM code, and
661// - main thread in VM code,
662// organized by
663// - helpers.
664ISOLATE_UNIT_TEST_CASE(SafepointTestVM) {
665 Isolate* isolate = thread->isolate();
666 Monitor monitor;
667 intptr_t expected_count = 0;
668 intptr_t total_done = 0;
669 intptr_t exited = 0;
670 for (int i = 0; i < SafepointTestTask::kTaskCount; i++) {
672 isolate, &monitor, &expected_count, &total_done, &exited);
673 }
674 String& label = String::Handle(String::New("foo"));
675 UserTag& tag = UserTag::Handle(UserTag::New(label));
676 isolate->set_current_tag(tag);
677 MonitorLocker ml(&monitor);
678 while (exited != SafepointTestTask::kTaskCount) {
679 ml.WaitWithSafepointCheck(thread);
680 }
681}
682
683// Test case for recursive safepoint operations.
684ISOLATE_UNIT_TEST_CASE(RecursiveSafepointTest1) {
685 intptr_t count = 0;
686 {
687 GcSafepointOperationScope safepoint_scope(thread);
688 count += 1;
689 {
690 GcSafepointOperationScope safepoint_scope(thread);
691 count += 1;
692 {
693 GcSafepointOperationScope safepoint_scope(thread);
694 count += 1;
695 }
696 }
697 }
698 EXPECT(count == 3);
699}
700
701ISOLATE_UNIT_TEST_CASE(ThreadIterator_Count) {
702 intptr_t thread_count_0 = 0;
703 intptr_t thread_count_1 = 0;
704
705 {
707 while (ti.HasNext()) {
708 OSThread* thread = ti.Next();
709 EXPECT(thread != nullptr);
710 thread_count_0++;
711 }
712 }
713
714 {
716 while (ti.HasNext()) {
717 OSThread* thread = ti.Next();
718 EXPECT(thread != nullptr);
719 thread_count_1++;
720 }
721 }
722
723 EXPECT(thread_count_0 > 0);
724 EXPECT(thread_count_1 > 0);
725 EXPECT(thread_count_0 >= thread_count_1);
726}
727
728ISOLATE_UNIT_TEST_CASE(ThreadIterator_FindSelf) {
729 OSThread* current = OSThread::Current();
731}
732
737};
738
741 reinterpret_cast<ThreadIteratorTestParams*>(parameter);
742 OSThread* thread = OSThread::Current();
743 EXPECT(thread != nullptr);
744
745 MonitorLocker ml(params->monitor);
746 params->spawned_thread_id = thread->id();
747 params->spawned_thread_join_id = OSThread::GetCurrentThreadJoinId(thread);
748 EXPECT(params->spawned_thread_id != OSThread::kInvalidThreadId);
750 ml.Notify();
751}
752
753// NOTE: This test case also verifies that known TLS destructors are called
754// on Windows. See |OnDartThreadExit| in os_thread_win.cc for more details.
755TEST_CASE(ThreadIterator_AddFindRemove) {
757 params.spawned_thread_id = OSThread::kInvalidThreadId;
758 params.monitor = new Monitor();
759
760 {
761 MonitorLocker ml(params.monitor);
762 EXPECT(params.spawned_thread_id == OSThread::kInvalidThreadId);
763 // Spawn thread and wait to receive the thread id.
764 OSThread::Start("ThreadIteratorTest", ThreadIteratorTestMain,
765 reinterpret_cast<uword>(&params));
766 while (params.spawned_thread_id == OSThread::kInvalidThreadId) {
767 ml.Wait();
768 }
769 EXPECT(params.spawned_thread_id != OSThread::kInvalidThreadId);
770 EXPECT(params.spawned_thread_join_id != OSThread::kInvalidThreadJoinId);
771 OSThread::Join(params.spawned_thread_join_id);
772 }
773
774 EXPECT(!OSThread::IsThreadInList(params.spawned_thread_id))
775
776 delete params.monitor;
777}
778
779// Test rendezvous of:
780// - helpers in VM code, and
781// - main thread in VM code,
782// organized by
783// - main thread, and
784// - helpers.
785ISOLATE_UNIT_TEST_CASE(SafepointTestVM2) {
786 Isolate* isolate = thread->isolate();
787 Monitor monitor;
788 intptr_t expected_count = 0;
789 intptr_t total_done = 0;
790 intptr_t exited = 0;
791 for (int i = 0; i < SafepointTestTask::kTaskCount; i++) {
793 isolate, &monitor, &expected_count, &total_done, &exited);
794 }
795 bool all_helpers = false;
796 do {
797 GcSafepointOperationScope safepoint_scope(thread);
798 {
799 MonitorLocker ml(&monitor);
800 if (expected_count == SafepointTestTask::kTaskCount) {
801 all_helpers = true;
802 }
803 }
804 } while (!all_helpers);
805 String& label = String::Handle(String::New("foo"));
806 UserTag& tag = UserTag::Handle(UserTag::New(label));
807 isolate->set_current_tag(tag);
808 MonitorLocker ml(&monitor);
809 while (exited != SafepointTestTask::kTaskCount) {
810 ml.WaitWithSafepointCheck(thread);
811 }
812}
813
814// Test recursive safepoint operation scopes with other threads trying
815// to also start a safepoint operation scope.
816ISOLATE_UNIT_TEST_CASE(RecursiveSafepointTest2) {
817 Isolate* isolate = thread->isolate();
818 Monitor monitor;
819 intptr_t expected_count = 0;
820 intptr_t total_done = 0;
821 intptr_t exited = 0;
822 for (int i = 0; i < SafepointTestTask::kTaskCount; i++) {
824 isolate, &monitor, &expected_count, &total_done, &exited);
825 }
826 bool all_helpers = false;
827 do {
828 GcSafepointOperationScope safepoint_scope(thread);
829 {
830 GcSafepointOperationScope safepoint_scope(thread);
831 MonitorLocker ml(&monitor);
832 if (expected_count == SafepointTestTask::kTaskCount) {
833 all_helpers = true;
834 }
835 }
836 } while (!all_helpers);
837 String& label = String::Handle(String::New("foo"));
838 UserTag& tag = UserTag::Handle(UserTag::New(label));
839 isolate->set_current_tag(tag);
840 bool all_exited = false;
841 do {
842 GcSafepointOperationScope safepoint_scope(thread);
843 {
844 GcSafepointOperationScope safepoint_scope(thread);
845 MonitorLocker ml(&monitor);
846 if (exited == SafepointTestTask::kTaskCount) {
847 all_exited = true;
848 }
849 }
850 } while (!all_exited);
851}
852
854 public:
855 AllocAndGCTask(IsolateGroup* isolate_group, Monitor* done_monitor, bool* done)
856 : isolate_group_(isolate_group),
857 done_monitor_(done_monitor),
858 done_(done) {}
859
860 virtual void Run() {
861 const bool kBypassSafepoint = false;
863 kBypassSafepoint);
864 {
865 Thread* thread = Thread::Current();
866 StackZone stack_zone(thread);
867 Zone* zone = stack_zone.GetZone();
868 String& old_str = String::Handle(zone, String::New("old", Heap::kOld));
869 isolate_group_->heap()->CollectAllGarbage();
870 EXPECT(old_str.Equals("old"));
871 }
872 Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
873 // Tell main thread that we are ready.
874 {
875 MonitorLocker ml(done_monitor_);
876 ASSERT(!*done_);
877 *done_ = true;
878 ml.Notify();
879 }
880 }
881
882 private:
883 IsolateGroup* isolate_group_;
884 Monitor* done_monitor_;
885 bool* done_;
886};
887
888ISOLATE_UNIT_TEST_CASE(HelperAllocAndGC) {
889 Monitor done_monitor;
890 bool done = false;
891 auto isolate_group = thread->isolate_group();
892 Dart::thread_pool()->Run<AllocAndGCTask>(isolate_group, &done_monitor, &done);
893 {
894 while (true) {
895 TransitionVMToBlocked transition(thread);
896 MonitorLocker ml(&done_monitor);
897 if (done) {
898 break;
899 }
900 }
901 }
902}
903
905 public:
907 Monitor* done_monitor,
908 bool* done)
909 : isolate_group_(isolate_group),
910 done_monitor_(done_monitor),
911 done_(done) {}
912
913 virtual void Run() {
914 const bool kBypassSafepoint = false;
916 kBypassSafepoint);
917 {
918 Thread* thread = Thread::Current();
919 StackZone stack_zone(thread);
920 Zone* zone = stack_zone.GetZone();
921 int count = 100 * 1000;
922 while (count-- > 0) {
923 String::Handle(zone, String::New("abc"));
924 }
925 }
926 Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
927 // Tell main thread that we are ready.
928 {
929 MonitorLocker ml(done_monitor_);
930 ASSERT(!*done_);
931 *done_ = true;
932 ml.Notify();
933 }
934 }
935
936 private:
937 IsolateGroup* isolate_group_;
938 Monitor* done_monitor_;
939 bool* done_;
940};
941
943 const int NUMBER_TEST_THREADS = 10;
944 Monitor done_monitor[NUMBER_TEST_THREADS];
945 bool done[NUMBER_TEST_THREADS];
946 auto isolate_group = thread->isolate_group();
947 for (int i = 0; i < NUMBER_TEST_THREADS; i++) {
948 done[i] = false;
950 isolate_group, &done_monitor[i], &done[i]);
951 }
952
953 for (int i = 0; i < NUMBER_TEST_THREADS; i++) {
954 MonitorLocker ml(&done_monitor[i]);
955 while (!done[i]) {
956 ml.WaitWithSafepointCheck(thread);
957 }
958 }
959}
960
961ISOLATE_UNIT_TEST_CASE(SafepointRwLockWithReadLock) {
962 SafepointRwLock lock;
963 SafepointReadRwLocker locker(Thread::Current(), &lock);
964 DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
966}
967
968ISOLATE_UNIT_TEST_CASE(SafepointRwLockWithWriteLock) {
969 SafepointRwLock lock;
971 DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
973}
974
975ISOLATE_UNIT_TEST_CASE(SafepointRwLockWithoutAnyLocks) {
976 SafepointRwLock lock;
977 DEBUG_ONLY(EXPECT(!lock.IsCurrentThreadReader()));
979}
980
981ISOLATE_UNIT_TEST_CASE(SafepointRwLockReentrantReadLock) {
982 SafepointRwLock lock;
983 {
984 SafepointReadRwLocker locker(Thread::Current(), &lock);
985 {
986 SafepointReadRwLocker locker1(Thread::Current(), &lock);
987 DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
989 }
990 DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
992 }
993 DEBUG_ONLY(EXPECT(!lock.IsCurrentThreadReader()));
995}
996
997ISOLATE_UNIT_TEST_CASE(SafepointRwLockReentrantWriteLock) {
998 SafepointRwLock lock;
999 {
1000 SafepointWriteRwLocker locker(Thread::Current(), &lock);
1001 {
1002 SafepointWriteRwLocker locker1(Thread::Current(), &lock);
1003 DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
1005 }
1006 DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
1008 }
1009 DEBUG_ONLY(EXPECT(!lock.IsCurrentThreadReader()));
1011}
1012
1013ISOLATE_UNIT_TEST_CASE(SafepointRwLockWriteToReadLock) {
1014 SafepointRwLock lock;
1015 {
1016 SafepointWriteRwLocker locker(Thread::Current(), &lock);
1017 {
1018 SafepointReadRwLocker locker1(Thread::Current(), &lock);
1019 DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
1021 }
1022 DEBUG_ONLY(EXPECT(lock.IsCurrentThreadReader()));
1024 }
1025 DEBUG_ONLY(EXPECT(!lock.IsCurrentThreadReader()));
1027}
1028
1029template <typename LockType, typename LockerType>
1031 const intptr_t kNumIterations = 5;
1032 volatile intptr_t execution_count = 0;
1033 volatile intptr_t thrown_count = 0;
1034 LockType lock;
1035 for (intptr_t i = 0; i < kNumIterations; ++i) {
1036 LongJumpScope jump;
1037 if (setjmp(*jump.Set()) == 0) {
1038 LockerType locker(Thread::Current(), &lock);
1039 execution_count++;
1041 1, Object::background_compilation_error());
1042 } else {
1043 ASSERT(Thread::Current()->StealStickyError() ==
1044 Object::background_compilation_error().ptr());
1045 thrown_count++;
1046 }
1047 }
1048 EXPECT_EQ(kNumIterations, execution_count);
1049 EXPECT_EQ(kNumIterations, thrown_count);
1050}
1051ISOLATE_UNIT_TEST_CASE(SafepointRwLockWriteWithLongJmp) {
1052 RunLockerWithLongJumpTest<SafepointRwLock, SafepointWriteRwLocker>();
1053}
1054
1055ISOLATE_UNIT_TEST_CASE(SafepointRwLockReadWithLongJmp) {
1056 RunLockerWithLongJumpTest<SafepointRwLock, SafepointReadRwLocker>();
1057}
1058
1059ISOLATE_UNIT_TEST_CASE(SafepointMutexLockerWithLongJmp) {
1060 RunLockerWithLongJumpTest<Mutex, SafepointMutexLocker>();
1061}
1062
1067 Monitor* monitor = nullptr;
1068 bool child_started = false;
1069 intptr_t value = -1;
1070 intptr_t observed_value = -1;
1071};
1072
1073void Helper(uword arg) {
1074 auto state = reinterpret_cast<ReaderThreadState*>(arg);
1076 // Notify other thread.
1077 {
1078 MonitorLocker ml(state->monitor);
1079 state->child_started = true;
1080 ml.Notify();
1081 }
1082 const bool kBypassSafepoint = false;
1084 kBypassSafepoint);
1085 {
1086 auto thread = Thread::Current();
1087 intptr_t observed_value = -1;
1088 {
1089 SafepointReadRwLocker reader(thread, state->rw_lock);
1090 observed_value = state->value;
1091 }
1092 state->observed_value = observed_value;
1093 }
1094 Thread::ExitIsolateGroupAsHelper(kBypassSafepoint);
1095}
1096
1097ISOLATE_UNIT_TEST_CASE(SafepointRwLockExclusiveNestedWriter_Regress44000) {
1098 auto isolate_group = IsolateGroup::Current();
1099
1100 SafepointRwLock lock;
1102 state.rw_lock = &lock;
1103 state.isolate_group = isolate_group;
1104 state.value = 0;
1105 state.child_started = false;
1106 state.monitor = new Monitor();
1107 {
1108 // Hold one writer lock.
1109 SafepointWriteRwLocker locker(Thread::Current(), &lock);
1110 {
1111 // Hold another, nested, writer lock.
1112 SafepointWriteRwLocker locker2(Thread::Current(), &lock);
1113
1114 // Start a thread, it will try to acquire read lock but it will have to
1115 // wait until we have exited both writer scopes.
1116 if (OSThread::Start("DartWorker", &Helper,
1117 reinterpret_cast<uword>(&state)) != 0) {
1118 FATAL("Could not start worker thread");
1119 }
1120 // Wait for the thread to start.
1121 {
1122 MonitorLocker ml(state.monitor);
1123 while (!state.child_started) {
1124 ml.Wait();
1125 }
1126 }
1127 state.value = 1;
1128 }
1129 state.value = 2;
1130 }
1131 // Join the other thread.
1132 OSThread::Join(state.reader_id);
1133
1134 // Ensure the reader thread had to wait before it entered the
1135 // SafepointWriteRwLocker scope.
1136 EXPECT(state.observed_value == 2);
1137
1138 delete state.monitor;
1139}
1140
1142 // This test uses ASSERT instead of EXPECT because IsOwnedByCurrentThread is
1143 // only available in debug mode. Since our vm/cc tests run in DEBUG mode that
1144 // is sufficient for this test.
1145 Monitor monitor;
1146 {
1147 SafepointMonitorLocker ml(&monitor);
1148 ASSERT(monitor.IsOwnedByCurrentThread());
1149 {
1150 SafepointMonitorUnlockScope ml_unlocker(&ml);
1151 ASSERT(!monitor.IsOwnedByCurrentThread());
1152 {
1153 SafepointMonitorLocker inner_ml(&monitor);
1154 ASSERT(monitor.IsOwnedByCurrentThread());
1155 }
1156 }
1157 }
1158}
1159
1160} // namespace dart
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
Definition: DM.cpp:263
int count
Definition: FontMgrTest.cpp:50
#define EXPECT(type, expectedAlignment, expectedSize)
AllocAndGCTask(IsolateGroup *isolate_group, Monitor *done_monitor, bool *done)
Definition: thread_test.cc:855
virtual void Run()
Definition: thread_test.cc:860
AllocateGlobsOfMemoryTask(IsolateGroup *isolate_group, Monitor *done_monitor, bool *done)
Definition: thread_test.cc:906
static ArrayPtr NewBoxed(intptr_t type_args_len, intptr_t num_arguments, const Array &optional_arguments_names, Heap::Space space=Heap::kOld)
Definition: dart_entry.h:83
ObjectPtr AtAcquire(intptr_t index) const
Definition: object.h:10891
static ArrayPtr New(intptr_t len, Heap::Space space=Heap::kNew)
Definition: object.h:10959
void SetAtRelease(intptr_t index, const Object &value) const
Definition: object.h:10895
ObjectPtr At(intptr_t index) const
Definition: object.h:10875
intptr_t Length() const
Definition: object.h:10829
void Add(const T &value)
static ClassPtr New(IsolateGroup *isolate_group, bool register_class=true)
Definition: object.cc:3053
static ThreadPool * thread_pool()
Definition: dart.h:73
static FunctionTypePtr New(intptr_t num_parent_type_arguments=0, Nullability nullability=Nullability::kNonNullable, Heap::Space space=Heap::kOld)
Definition: object.cc:11631
static FunctionPtr New(const FunctionType &signature, const String &name, UntaggedFunction::Kind kind, bool is_static, bool is_const, bool is_abstract, bool is_external, bool is_native, const Object &owner, TokenPosition token_pos, Heap::Space space=Heap::kOld)
Definition: object.cc:10243
void IterateStackPointers(ObjectPointerVisitor *visitor, ValidationPolicy validate_frames)
Definition: heap.cc:364
@ kOld
Definition: heap.h:39
void CollectAllGarbage(GCReason reason=GCReason::kFull, bool compact=false)
Definition: heap.cc:573
virtual void Run()
Definition: thread_test.cc:397
ICDataTestTask(IsolateGroup *isolate_group, const Array &ic_datas, Monitor *monitor, intptr_t *exited, std::atomic< bool > *done)
Definition: thread_test.cc:385
static constexpr intptr_t kTaskCount
Definition: thread_test.cc:383
void AddReceiverCheck(intptr_t receiver_class_id, const Function &target, intptr_t count=1, StaticTypeExactnessState exactness=StaticTypeExactnessState::NotTracking()) const
Definition: object.cc:16889
ArrayPtr entries() const
Definition: object.h:2783
intptr_t NumberOfChecks() const
Definition: object.cc:16577
Heap * heap() const
Definition: isolate.h:296
static IsolateGroup * Current()
Definition: isolate.h:539
UserTagPtr current_tag() const
Definition: isolate.h:1348
UserTagPtr default_tag() const
Definition: isolate.h:1351
IsolateGroup * group() const
Definition: isolate.h:1037
void set_current_tag(const UserTag &tag)
Definition: isolate.cc:3222
DART_NORETURN void Jump(int value, const Error &error)
Definition: longjump.cc:22
jmp_buf * Set()
Definition: longjump.cc:16
Monitor::WaitResult WaitWithSafepointCheck(Thread *thread, int64_t millis=Monitor::kNoTimeout)
Definition: lockers.cc:12
Monitor::WaitResult Wait(int64_t millis=Monitor::kNoTimeout)
Definition: lockers.h:172
bool IsOwnedByCurrentThread() const
Definition: os_thread.h:371
bool HasNext() const
Definition: os_thread.cc:343
static int Start(const char *name, ThreadStartFunction function, uword parameter)
ThreadId id() const
Definition: os_thread.h:96
void DisableThreadInterrupts()
Definition: os_thread.cc:143
static void Join(ThreadJoinId id)
static OSThread * Current()
Definition: os_thread.h:179
static const ThreadId kInvalidThreadId
Definition: os_thread.h:248
static ThreadJoinId GetCurrentThreadJoinId(OSThread *thread)
static bool IsThreadInList(ThreadId id)
Definition: os_thread.cc:230
static const ThreadJoinId kInvalidThreadJoinId
Definition: os_thread.h:249
static int64_t GetCurrentMonotonicMicros()
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
ObjectCounter(IsolateGroup *isolate_group, const Object *obj)
Definition: thread_test.cc:85
void VisitPointers(ObjectPtr *first, ObjectPtr *last) override
Definition: thread_test.cc:88
intptr_t count() const
Definition: thread_test.cc:108
IsolateGroup * isolate_group() const
Definition: visitor.h:25
void VisitCompressedPointers(uword heap_base, CompressedObjectPtr *first, CompressedObjectPtr *last)
Definition: visitor.h:43
ObjectPtr ptr() const
Definition: object.h:332
static Object & Handle()
Definition: object.h:407
static Object & ZoneHandle()
Definition: object.h:419
bool IsCurrentThreadWriter()
Definition: lockers.h:354
SafepointTestTask(Isolate *isolate, Monitor *monitor, intptr_t *expected_count, intptr_t *total_done, intptr_t *exited)
Definition: thread_test.cc:527
static constexpr intptr_t kTaskCount
Definition: thread_test.cc:525
SimpleTaskWithZoneAllocation(intptr_t id, IsolateGroup *isolate_group, Thread **thread_ptr, Monitor *sync, Monitor *monitor, intptr_t *done_count, bool *wait)
Definition: thread_test.cc:230
static SmiPtr New(intptr_t value)
Definition: object.h:10006
intptr_t Value() const
Definition: object.h:9990
Zone * GetZone()
Definition: zone.h:213
bool Equals(const String &str) const
Definition: object.h:13337
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition: object.cc:23698
static StringPtr New(Thread *thread, const char *cstr)
Definition: symbols.h:723
TaskWithZoneAllocation(IsolateGroup *isolate_group, Monitor *monitor, bool *done, intptr_t id)
Definition: thread_test.cc:117
static Dart_Handle LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true, bool allow_compile_errors=false)
Definition: unit_test.cc:436
static Dart_Isolate CreateTestIsolate(const char *name=nullptr, void *isolate_group_data=nullptr, void *isolate_data=nullptr)
Definition: unit_test.cc:140
bool Run(Args &&... args)
Definition: thread_pool.h:45
Zone * zone() const
Definition: thread_state.h:37
LongJumpScope * long_jump_base() const
Definition: thread_state.h:47
bool OwnsSafepoint() const
Definition: thread.cc:1367
bool force_growth() const
Definition: thread.h:633
@ kUnknownTask
Definition: thread.h:346
static Thread * Current()
Definition: thread.h:362
static void ExitIsolateGroupAsHelper(bool bypass_safepoint)
Definition: thread.cc:499
Isolate * isolate() const
Definition: thread.h:534
IsolateGroup * isolate_group() const
Definition: thread.h:541
static void EnterIsolate(Isolate *isolate)
Definition: thread.cc:371
static void ExitIsolate(bool isolate_shutdown=false)
Definition: thread.cc:428
static bool EnterIsolateGroupAsHelper(IsolateGroup *isolate_group, TaskKind kind, bool bypass_safepoint)
Definition: thread.cc:481
static UserTagPtr New(const String &label, Heap::Space space=Heap::kOld)
Definition: object.cc:26949
StringPtr label() const
Definition: object.h:13168
static int SNPrint(char *str, size_t size, const char *format,...) PRINTF_ATTRIBUTE(3
char * PrintToString(const char *format,...) PRINTF_ATTRIBUTE(2
Definition: zone.cc:313
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
struct _Dart_Isolate * Dart_Isolate
Definition: dart_api.h:88
const EmbeddedViewParams * params
#define ASSERT(E)
#define FATAL(error)
AtkStateType state
GAsyncResult * result
Dart_NativeFunction function
Definition: fuchsia.cc:51
#define HANDLESCOPE(thread)
Definition: handles.h:321
Definition: dart_vm.cc:33
constexpr intptr_t kMicrosecondsPerMillisecond
Definition: globals.h:561
const char *const name
DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate)
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
pthread_t ThreadJoinId
const char *const class_name
uintptr_t uword
Definition: globals.h:501
void ThreadIteratorTestMain(uword parameter)
Definition: thread_test.cc:739
ISOLATE_UNIT_TEST_CASE(StackAllocatedDestruction)
static void USE(T &&)
Definition: globals.h:618
DART_EXPORT void Dart_ExitIsolate()
TEST_CASE(DirectoryCurrent)
Dart_Handle NewString(const char *str)
static void RunLockerWithLongJumpTest()
static FunctionPtr CreateFunction(const char *name)
void Helper(uword arg)
const char *const function_name
DART_EXPORT void Dart_ShutdownIsolate()
pthread_t ThreadId
VM_UNIT_TEST_CASE(DirectoryCurrentNoScope)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
#define DEBUG_ONLY(code)
Definition: globals.h:141
#define Pd64
Definition: globals.h:416
#define Pd
Definition: globals.h:408
IsolateGroup * isolate_group
SafepointRwLock * rw_lock
const uintptr_t id
#define EXPECT_VALID(handle)
Definition: unit_test.h:643