Skip to content

Commit 868d2c6

Browse files
committed
The sweeper must not be running during isolate shutdown.
In release mode, there seems to be nothing to prevent this. In debug mode, the "Verify" call waits for the sweeper, but there is still a race between the task count update and the ExitIsolateAsHelper call, which could cause problems. Fix both of these, and add more assertions and verbose error messages. - make sweeper task cleanly exit isolate *before* notifying - wait for sweeper before shutting down isolate - verbose pthread failures BUG= R=asiva@google.com Review URL: https://codereview.chromium.org//1233563004 .
1 parent 1ef2b68 commit 868d2c6

File tree

8 files changed

+67
-10
lines changed

8 files changed

+67
-10
lines changed

runtime/vm/gc_sweeper.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,14 @@ class SweeperTask : public ThreadPool::Task {
137137
if (page == last_) break;
138138
page = next_page;
139139
}
140+
// Exit isolate cleanly *before* notifying it, to avoid shutdown race.
141+
Thread::ExitIsolateAsHelper();
140142
// This sweeper task is done. Notify the original isolate.
141143
{
142144
MonitorLocker ml(old_space_->tasks_lock());
143145
old_space_->set_tasks(old_space_->tasks() - 1);
144146
ml.Notify();
145147
}
146-
Thread::ExitIsolateAsHelper();
147148
}
148149

149150
private:

runtime/vm/isolate.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,15 @@ void Isolate::Shutdown() {
14371437
// avoid exposing it in a state of decay.
14381438
RemoveIsolateFromList(this);
14391439

1440+
if (heap_ != NULL) {
1441+
// Wait for any concurrent GC tasks to finish before shutting down.
1442+
PageSpace* old_space = heap_->old_space();
1443+
MonitorLocker ml(old_space->tasks_lock());
1444+
while (old_space->tasks() > 0) {
1445+
ml.Wait();
1446+
}
1447+
}
1448+
14401449
// Create an area where we do have a zone and a handle scope so that we can
14411450
// call VM functions while tearing this isolate down.
14421451
{
@@ -1490,6 +1499,8 @@ void Isolate::Shutdown() {
14901499
// TODO(5411455): For now just make sure there are no current isolates
14911500
// as we are shutting down the isolate.
14921501
Thread::ExitIsolate();
1502+
// All threads should have exited by now.
1503+
thread_registry()->CheckNotScheduled(this);
14931504
Profiler::ShutdownProfilingForIsolate(this);
14941505
}
14951506

runtime/vm/os_thread_android.cc

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ namespace dart {
2323
}
2424

2525

26+
#if defined(DEBUG)
27+
#define ASSERT_PTHREAD_SUCCESS(result) VALIDATE_PTHREAD_RESULT(result)
28+
#else
29+
// NOTE: This (currently) expands to a no-op.
30+
#define ASSERT_PTHREAD_SUCCESS(result) ASSERT(result == 0)
31+
#endif
32+
33+
2634
#ifdef DEBUG
2735
#define RETURN_ON_PTHREAD_FAILURE(result) \
2836
if (result != 0) { \
@@ -217,7 +225,7 @@ void Mutex::Lock() {
217225
int result = pthread_mutex_lock(data_.mutex());
218226
// Specifically check for dead lock to help debugging.
219227
ASSERT(result != EDEADLK);
220-
ASSERT(result == 0); // Verify no other errors.
228+
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
221229
// When running with assertions enabled we do track the owner.
222230
#if defined(DEBUG)
223231
owner_ = OSThread::GetCurrentThreadId();
@@ -231,7 +239,7 @@ bool Mutex::TryLock() {
231239
if (result == EBUSY) {
232240
return false;
233241
}
234-
ASSERT(result == 0); // Verify no other errors.
242+
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
235243
// When running with assertions enabled we do track the owner.
236244
#if defined(DEBUG)
237245
owner_ = OSThread::GetCurrentThreadId();
@@ -249,7 +257,7 @@ void Mutex::Unlock() {
249257
int result = pthread_mutex_unlock(data_.mutex());
250258
// Specifically check for wrong thread unlocking to aid debugging.
251259
ASSERT(result != EPERM);
252-
ASSERT(result == 0); // Verify no other errors.
260+
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
253261
}
254262

255263

runtime/vm/os_thread_linux.cc

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ namespace dart {
2424
}
2525

2626

27+
#if defined(DEBUG)
28+
#define ASSERT_PTHREAD_SUCCESS(result) VALIDATE_PTHREAD_RESULT(result)
29+
#else
30+
// NOTE: This (currently) expands to a no-op.
31+
#define ASSERT_PTHREAD_SUCCESS(result) ASSERT(result == 0)
32+
#endif
33+
34+
2735
#ifdef DEBUG
2836
#define RETURN_ON_PTHREAD_FAILURE(result) \
2937
if (result != 0) { \
@@ -218,7 +226,7 @@ void Mutex::Lock() {
218226
int result = pthread_mutex_lock(data_.mutex());
219227
// Specifically check for dead lock to help debugging.
220228
ASSERT(result != EDEADLK);
221-
ASSERT(result == 0); // Verify no other errors.
229+
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
222230
// When running with assertions enabled we do track the owner.
223231
#if defined(DEBUG)
224232
owner_ = OSThread::GetCurrentThreadId();
@@ -232,7 +240,7 @@ bool Mutex::TryLock() {
232240
if (result == EBUSY) {
233241
return false;
234242
}
235-
ASSERT(result == 0); // Verify no other errors.
243+
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
236244
// When running with assertions enabled we do track the owner.
237245
#if defined(DEBUG)
238246
owner_ = OSThread::GetCurrentThreadId();
@@ -250,7 +258,7 @@ void Mutex::Unlock() {
250258
int result = pthread_mutex_unlock(data_.mutex());
251259
// Specifically check for wrong thread unlocking to aid debugging.
252260
ASSERT(result != EPERM);
253-
ASSERT(result == 0); // Verify no other errors.
261+
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
254262
}
255263

256264

runtime/vm/os_thread_macos.cc

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ namespace dart {
3131
}
3232

3333

34+
#if defined(DEBUG)
35+
#define ASSERT_PTHREAD_SUCCESS(result) VALIDATE_PTHREAD_RESULT(result)
36+
#else
37+
// NOTE: This (currently) expands to a no-op.
38+
#define ASSERT_PTHREAD_SUCCESS(result) ASSERT(result == 0)
39+
#endif
40+
41+
3442
#ifdef DEBUG
3543
#define RETURN_ON_PTHREAD_FAILURE(result) \
3644
if (result != 0) { \
@@ -223,7 +231,7 @@ void Mutex::Lock() {
223231
int result = pthread_mutex_lock(data_.mutex());
224232
// Specifically check for dead lock to help debugging.
225233
ASSERT(result != EDEADLK);
226-
ASSERT(result == 0); // Verify no other errors.
234+
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
227235
// When running with assertions enabled we do track the owner.
228236
#if defined(DEBUG)
229237
owner_ = OSThread::GetCurrentThreadId();
@@ -237,7 +245,7 @@ bool Mutex::TryLock() {
237245
if ((result == EBUSY) || (result == EDEADLK)) {
238246
return false;
239247
}
240-
ASSERT(result == 0); // Verify no other errors.
248+
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
241249
// When running with assertions enabled we do track the owner.
242250
#if defined(DEBUG)
243251
owner_ = OSThread::GetCurrentThreadId();
@@ -255,7 +263,7 @@ void Mutex::Unlock() {
255263
int result = pthread_mutex_unlock(data_.mutex());
256264
// Specifically check for wrong thread unlocking to aid debugging.
257265
ASSERT(result != EPERM);
258-
ASSERT(result == 0); // Verify no other errors.
266+
ASSERT_PTHREAD_SUCCESS(result); // Verify no other errors.
259267
}
260268

261269

runtime/vm/thread.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ static void DeleteThread(void* thread) {
2727
}
2828

2929

30+
Thread::~Thread() {
31+
// We should cleanly exit any isolate before destruction.
32+
ASSERT(isolate_ == NULL);
33+
}
34+
35+
3036
void Thread::InitOnceBeforeIsolate() {
3137
ASSERT(thread_key_ == OSThread::kUnsetThreadLocalKey);
3238
thread_key_ = OSThread::CreateThreadLocal(DeleteThread);

runtime/vm/thread.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ class Thread {
7575
static void InitOnceBeforeIsolate();
7676
static void InitOnceAfterObjectAndStubCode();
7777

78+
~Thread();
79+
7880
// The topmost zone used for allocation in this thread.
7981
Zone* zone() const { return state_.zone; }
8082

runtime/vm/thread_registry.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,19 @@ class ThreadRegistry {
6363
return (FindEntry(thread) != NULL);
6464
}
6565

66+
void CheckNotScheduled(Isolate* isolate) {
67+
MutexLocker ml(mutex_);
68+
for (int i = 0; i < entries_.length(); ++i) {
69+
const Entry& entry = entries_[i];
70+
if (entry.scheduled) {
71+
FATAL3("Isolate %p still scheduled on %p (whose isolate_ is %p)\n",
72+
isolate,
73+
entry.thread,
74+
entry.thread->isolate());
75+
}
76+
}
77+
}
78+
6679
void VisitObjectPointers(ObjectPointerVisitor* visitor) {
6780
MutexLocker ml(mutex_);
6881
for (int i = 0; i < entries_.length(); ++i) {

0 commit comments

Comments
 (0)