@@ -84,7 +84,8 @@ JobScheduler::GetQueueForJob(Job* aJob)
84
84
}
85
85
86
86
Job::Job (SyncObject* aStart, SyncObject* aCompletion, WorkerThread* aThread)
87
- : mStartSync (aStart)
87
+ : mNextWaitingJob (nullptr )
88
+ , mStartSync (aStart)
88
89
, mCompletionSync (aCompletion)
89
90
, mPinToThread (aThread)
90
91
{
@@ -124,6 +125,7 @@ SetEventJob::~SetEventJob()
124
125
125
126
SyncObject::SyncObject (uint32_t aNumPrerequisites)
126
127
: mSignals (aNumPrerequisites)
128
+ , mFirstWaitingJob (nullptr )
127
129
#ifdef DEBUG
128
130
, mNumPrerequisites (aNumPrerequisites)
129
131
, mAddedPrerequisites (0 )
@@ -132,7 +134,7 @@ SyncObject::SyncObject(uint32_t aNumPrerequisites)
132
134
133
135
SyncObject::~SyncObject ()
134
136
{
135
- MOZ_ASSERT (mWaitingJobs . size () == 0 );
137
+ MOZ_ASSERT (mFirstWaitingJob == nullptr );
136
138
}
137
139
138
140
bool
@@ -184,28 +186,41 @@ SyncObject::Signal()
184
186
void
185
187
SyncObject::AddWaitingJob (Job* aJob)
186
188
{
187
- CriticalSectionAutoEnter lock (&mWaitingJobsSection );
188
- mWaitingJobs .push_back (aJob);
189
+ // Push (using atomics) the task into the list of waiting tasks.
190
+ for (;;) {
191
+ Job* first = mFirstWaitingJob ;
192
+ aJob->mNextWaitingJob = first;
193
+ if (mFirstWaitingJob .compareExchange (first, aJob)) {
194
+ break ;
195
+ }
196
+ }
189
197
}
190
198
191
199
void SyncObject::SubmitWaitingJobs ()
192
200
{
193
- std::vector<Job*> tasksToSubmit;
194
- {
195
- // Scheduling the tasks can cause code that modifies <this>'s reference
196
- // count to run concurrently, and cause the caller of this function to
197
- // be owned by another thread. We need to make sure the reference count
198
- // does not reach 0 on another thread before mWaitingJobs.clear(), so
199
- // hold a strong ref to prevent that!
200
- RefPtr<SyncObject> kungFuDeathGrip (this );
201
-
202
- CriticalSectionAutoEnter lock (&mWaitingJobsSection );
203
- tasksToSubmit = Move (mWaitingJobs );
204
- mWaitingJobs .clear ();
201
+ // Scheduling the tasks can cause code that modifies <this>'s reference
202
+ // count to run concurrently, and cause the caller of this function to
203
+ // be owned by another thread. We need to make sure the reference count
204
+ // does not reach 0 on another thread before the end of this method, so
205
+ // hold a strong ref to prevent that!
206
+ RefPtr<SyncObject> kungFuDeathGrip (this );
207
+
208
+ // First atomically swap mFirstWaitingJob and waitingJobs...
209
+ Job* waitingJobs = nullptr ;
210
+ for (;;) {
211
+ waitingJobs = mFirstWaitingJob ;
212
+ if (mFirstWaitingJob .compareExchange (waitingJobs, nullptr )) {
213
+ break ;
214
+ }
205
215
}
206
216
207
- for (Job* task : tasksToSubmit) {
208
- JobScheduler::GetQueueForJob (task)->SubmitJob (task);
217
+ // ... and submit all of the waiting tasks in waitingJob now that they belong
218
+ // to this thread.
219
+ while (waitingJobs) {
220
+ Job* next = waitingJobs->mNextWaitingJob ;
221
+ waitingJobs->mNextWaitingJob = nullptr ;
222
+ JobScheduler::GetQueueForJob (waitingJobs)->SubmitJob (waitingJobs);
223
+ waitingJobs = next;
209
224
}
210
225
}
211
226
0 commit comments