Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
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) {
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
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
#define EXPECT(type, expectedAlignment, expectedSize)
AllocAndGCTask(IsolateGroup *isolate_group, Monitor *done_monitor, bool *done)
virtual void Run()
AllocateGlobsOfMemoryTask(IsolateGroup *isolate_group, Monitor *done_monitor, bool *done)
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:10867
static ArrayPtr New(intptr_t len, Heap::Space space=Heap::kNew)
Definition object.h:10933
void SetAtRelease(intptr_t index, const Object &value) const
Definition object.h:10870
ObjectPtr At(intptr_t index) const
Definition object.h:10854
intptr_t Length() const
Definition object.h:10808
void Add(const T &value)
static ClassPtr New(IsolateGroup *isolate_group, bool register_class=true)
Definition object.cc:3114
static ThreadPool * thread_pool()
Definition dart.h:73
static FunctionTypePtr New(intptr_t num_parent_type_arguments=0, Nullability nullability=Nullability::kLegacy, Heap::Space space=Heap::kOld)
Definition object.cc:11682
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:10301
void IterateStackPointers(ObjectPointerVisitor *visitor, ValidationPolicy validate_frames)
Definition heap.cc:363
@ kOld
Definition heap.h:39
void CollectAllGarbage(GCReason reason=GCReason::kFull, bool compact=false)
Definition heap.cc:562
virtual void Run()
ICDataTestTask(IsolateGroup *isolate_group, const Array &ic_datas, Monitor *monitor, intptr_t *exited, std::atomic< bool > *done)
static constexpr intptr_t kTaskCount
void AddReceiverCheck(intptr_t receiver_class_id, const Function &target, intptr_t count=1, StaticTypeExactnessState exactness=StaticTypeExactnessState::NotTracking()) const
Definition object.cc:16936
ArrayPtr entries() const
Definition object.h:2763
intptr_t NumberOfChecks() const
Definition object.cc:16624
Heap * heap() const
Definition isolate.h:295
static IsolateGroup * Current()
Definition isolate.h:534
UserTagPtr current_tag() const
Definition isolate.h:1301
UserTagPtr default_tag() const
Definition isolate.h:1304
IsolateGroup * group() const
Definition isolate.h:990
void set_current_tag(const UserTag &tag)
Definition isolate.cc:3176
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:370
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:175
static const ThreadId kInvalidThreadId
Definition os_thread.h:244
static ThreadJoinId GetCurrentThreadJoinId(OSThread *thread)
static bool IsThreadInList(ThreadId id)
Definition os_thread.cc:230
static const ThreadJoinId kInvalidThreadJoinId
Definition os_thread.h:245
static int64_t GetCurrentMonotonicMicros()
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
ObjectCounter(IsolateGroup *isolate_group, const Object *obj)
void VisitPointers(ObjectPtr *first, ObjectPtr *last) override
intptr_t count() const
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)
static constexpr intptr_t kTaskCount
SimpleTaskWithZoneAllocation(intptr_t id, IsolateGroup *isolate_group, Thread **thread_ptr, Monitor *sync, Monitor *monitor, intptr_t *done_count, bool *wait)
static SmiPtr New(intptr_t value)
Definition object.h:9985
intptr_t Value() const
Definition object.h:9969
Zone * GetZone()
Definition zone.h:213
bool Equals(const String &str) const
Definition object.h:13311
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition object.cc:23777
static StringPtr New(Thread *thread, const char *cstr)
Definition symbols.h:722
TaskWithZoneAllocation(IsolateGroup *isolate_group, Monitor *monitor, bool *done, intptr_t id)
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:422
static Dart_Isolate CreateTestIsolate(const char *name=nullptr, void *isolate_group_data=nullptr, void *isolate_data=nullptr)
Definition unit_test.cc:139
bool Run(Args &&... args)
Definition thread_pool.h:45
Zone * zone() const
LongJumpScope * long_jump_base() const
bool OwnsSafepoint() const
Definition thread.cc:1301
bool force_growth() const
Definition thread.h:628
static Thread * Current()
Definition thread.h:361
static void ExitIsolateGroupAsHelper(bool bypass_safepoint)
Definition thread.cc:494
Isolate * isolate() const
Definition thread.h:533
IsolateGroup * isolate_group() const
Definition thread.h:540
static void EnterIsolate(Isolate *isolate)
Definition thread.cc:366
static void ExitIsolate(bool isolate_shutdown=false)
Definition thread.cc:423
static bool EnterIsolateGroupAsHelper(IsolateGroup *isolate_group, TaskKind kind, bool bypass_safepoint)
Definition thread.cc:476
static UserTagPtr New(const String &label, Heap::Space space=Heap::kOld)
Definition object.cc:27028
StringPtr label() const
Definition object.h:13142
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
static const uint8_t buffer[]
GAsyncResult * result
Dart_NativeFunction function
Definition fuchsia.cc:51
#define HANDLESCOPE(thread)
Definition handles.h:321
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)
static void USE(T &&)
Definition globals.h:618
DART_EXPORT void Dart_ExitIsolate()
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
#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 VM_UNIT_TEST_CASE(name)
Definition unit_test.h:33
#define ISOLATE_UNIT_TEST_CASE(name)
Definition unit_test.h:64
#define TEST_CASE(name)
Definition unit_test.h:85
#define EXPECT_VALID(handle)
Definition unit_test.h:650