| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/thread_pool.h" | 5 #include "vm/thread_pool.h" |
| 6 | 6 |
| 7 #include "vm/dart.h" | 7 #include "vm/dart.h" |
| 8 #include "vm/flags.h" | 8 #include "vm/flags.h" |
| 9 #include "vm/lockers.h" | 9 #include "vm/lockers.h" |
| 10 | 10 |
| 11 namespace dart { | 11 namespace dart { |
| 12 | 12 |
| 13 DEFINE_FLAG(int, worker_timeout_millis, 5000, | 13 DEFINE_FLAG(int, |
| 14 worker_timeout_millis, |
| 15 5000, |
| 14 "Free workers when they have been idle for this amount of time."); | 16 "Free workers when they have been idle for this amount of time."); |
| 15 | 17 |
| 16 ThreadPool::ThreadPool() | 18 ThreadPool::ThreadPool() |
| 17 : shutting_down_(false), | 19 : shutting_down_(false), |
| 18 all_workers_(NULL), | 20 all_workers_(NULL), |
| 19 idle_workers_(NULL), | 21 idle_workers_(NULL), |
| 20 count_started_(0), | 22 count_started_(0), |
| 21 count_stopped_(0), | 23 count_stopped_(0), |
| 22 count_running_(0), | 24 count_running_(0), |
| 23 count_idle_(0), | 25 count_idle_(0), |
| 24 shutting_down_workers_(NULL), | 26 shutting_down_workers_(NULL), |
| 25 join_list_(NULL) { | 27 join_list_(NULL) {} |
| 26 } | |
| 27 | 28 |
| 28 | 29 |
| 29 ThreadPool::~ThreadPool() { | 30 ThreadPool::~ThreadPool() { |
| 30 Shutdown(); | 31 Shutdown(); |
| 31 } | 32 } |
| 32 | 33 |
| 33 | 34 |
| 34 bool ThreadPool::Run(Task* task) { | 35 bool ThreadPool::Run(Task* task) { |
| 35 Worker* worker = NULL; | 36 Worker* worker = NULL; |
| 36 bool new_worker = false; | 37 bool new_worker = false; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 { | 140 { |
| 140 MutexLocker ml(&mutex_); | 141 MutexLocker ml(&mutex_); |
| 141 ASSERT(join_list_ == NULL); | 142 ASSERT(join_list_ == NULL); |
| 142 } | 143 } |
| 143 #endif | 144 #endif |
| 144 } | 145 } |
| 145 | 146 |
| 146 | 147 |
| 147 bool ThreadPool::IsIdle(Worker* worker) { | 148 bool ThreadPool::IsIdle(Worker* worker) { |
| 148 ASSERT(worker != NULL && worker->owned_); | 149 ASSERT(worker != NULL && worker->owned_); |
| 149 for (Worker* current = idle_workers_; | 150 for (Worker* current = idle_workers_; current != NULL; |
| 150 current != NULL; | |
| 151 current = current->idle_next_) { | 151 current = current->idle_next_) { |
| 152 if (current == worker) { | 152 if (current == worker) { |
| 153 return true; | 153 return true; |
| 154 } | 154 } |
| 155 } | 155 } |
| 156 return false; | 156 return false; |
| 157 } | 157 } |
| 158 | 158 |
| 159 | 159 |
| 160 bool ThreadPool::RemoveWorkerFromIdleList(Worker* worker) { | 160 bool ThreadPool::RemoveWorkerFromIdleList(Worker* worker) { |
| 161 ASSERT(worker != NULL && worker->owned_); | 161 ASSERT(worker != NULL && worker->owned_); |
| 162 if (idle_workers_ == NULL) { | 162 if (idle_workers_ == NULL) { |
| 163 return false; | 163 return false; |
| 164 } | 164 } |
| 165 | 165 |
| 166 // Special case head of list. | 166 // Special case head of list. |
| 167 if (idle_workers_ == worker) { | 167 if (idle_workers_ == worker) { |
| 168 idle_workers_ = worker->idle_next_; | 168 idle_workers_ = worker->idle_next_; |
| 169 worker->idle_next_ = NULL; | 169 worker->idle_next_ = NULL; |
| 170 return true; | 170 return true; |
| 171 } | 171 } |
| 172 | 172 |
| 173 for (Worker* current = idle_workers_; | 173 for (Worker* current = idle_workers_; current->idle_next_ != NULL; |
| 174 current->idle_next_ != NULL; | |
| 175 current = current->idle_next_) { | 174 current = current->idle_next_) { |
| 176 if (current->idle_next_ == worker) { | 175 if (current->idle_next_ == worker) { |
| 177 current->idle_next_ = worker->idle_next_; | 176 current->idle_next_ = worker->idle_next_; |
| 178 worker->idle_next_ = NULL; | 177 worker->idle_next_ = NULL; |
| 179 return true; | 178 return true; |
| 180 } | 179 } |
| 181 } | 180 } |
| 182 return false; | 181 return false; |
| 183 } | 182 } |
| 184 | 183 |
| 185 | 184 |
| 186 bool ThreadPool::RemoveWorkerFromAllList(Worker* worker) { | 185 bool ThreadPool::RemoveWorkerFromAllList(Worker* worker) { |
| 187 ASSERT(worker != NULL && worker->owned_); | 186 ASSERT(worker != NULL && worker->owned_); |
| 188 if (all_workers_ == NULL) { | 187 if (all_workers_ == NULL) { |
| 189 return false; | 188 return false; |
| 190 } | 189 } |
| 191 | 190 |
| 192 // Special case head of list. | 191 // Special case head of list. |
| 193 if (all_workers_ == worker) { | 192 if (all_workers_ == worker) { |
| 194 all_workers_ = worker->all_next_; | 193 all_workers_ = worker->all_next_; |
| 195 worker->all_next_ = NULL; | 194 worker->all_next_ = NULL; |
| 196 worker->owned_ = false; | 195 worker->owned_ = false; |
| 197 worker->done_ = true; | 196 worker->done_ = true; |
| 198 return true; | 197 return true; |
| 199 } | 198 } |
| 200 | 199 |
| 201 for (Worker* current = all_workers_; | 200 for (Worker* current = all_workers_; current->all_next_ != NULL; |
| 202 current->all_next_ != NULL; | |
| 203 current = current->all_next_) { | 201 current = current->all_next_) { |
| 204 if (current->all_next_ == worker) { | 202 if (current->all_next_ == worker) { |
| 205 current->all_next_ = worker->all_next_; | 203 current->all_next_ = worker->all_next_; |
| 206 worker->all_next_ = NULL; | 204 worker->all_next_ = NULL; |
| 207 worker->owned_ = false; | 205 worker->owned_ = false; |
| 208 return true; | 206 return true; |
| 209 } | 207 } |
| 210 } | 208 } |
| 211 return false; | 209 return false; |
| 212 } | 210 } |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 291 ASSERT(exit_monitor_.IsOwnedByCurrentThread()); | 289 ASSERT(exit_monitor_.IsOwnedByCurrentThread()); |
| 292 | 290 |
| 293 // Special case head of list. | 291 // Special case head of list. |
| 294 if (shutting_down_workers_ == worker) { | 292 if (shutting_down_workers_ == worker) { |
| 295 shutting_down_workers_ = worker->shutdown_next_; | 293 shutting_down_workers_ = worker->shutdown_next_; |
| 296 worker->shutdown_next_ = NULL; | 294 worker->shutdown_next_ = NULL; |
| 297 return true; | 295 return true; |
| 298 } | 296 } |
| 299 | 297 |
| 300 for (Worker* current = shutting_down_workers_; | 298 for (Worker* current = shutting_down_workers_; |
| 301 current->shutdown_next_ != NULL; | 299 current->shutdown_next_ != NULL; current = current->shutdown_next_) { |
| 302 current = current->shutdown_next_) { | |
| 303 if (current->shutdown_next_ == worker) { | 300 if (current->shutdown_next_ == worker) { |
| 304 current->shutdown_next_ = worker->shutdown_next_; | 301 current->shutdown_next_ = worker->shutdown_next_; |
| 305 worker->shutdown_next_ = NULL; | 302 worker->shutdown_next_ = NULL; |
| 306 return true; | 303 return true; |
| 307 } | 304 } |
| 308 } | 305 } |
| 309 return false; | 306 return false; |
| 310 } | 307 } |
| 311 | 308 |
| 312 | 309 |
| 313 void ThreadPool::JoinList::AddLocked(ThreadJoinId id, JoinList** list) { | 310 void ThreadPool::JoinList::AddLocked(ThreadJoinId id, JoinList** list) { |
| 314 *list = new JoinList(id, *list); | 311 *list = new JoinList(id, *list); |
| 315 } | 312 } |
| 316 | 313 |
| 317 | 314 |
| 318 void ThreadPool::JoinList::Join(JoinList** list) { | 315 void ThreadPool::JoinList::Join(JoinList** list) { |
| 319 while (*list != NULL) { | 316 while (*list != NULL) { |
| 320 JoinList* current = *list; | 317 JoinList* current = *list; |
| 321 *list = current->next(); | 318 *list = current->next(); |
| 322 OSThread::Join(current->id()); | 319 OSThread::Join(current->id()); |
| 323 delete current; | 320 delete current; |
| 324 } | 321 } |
| 325 } | 322 } |
| 326 | 323 |
| 327 | 324 |
| 328 ThreadPool::Task::Task() { | 325 ThreadPool::Task::Task() {} |
| 329 } | |
| 330 | 326 |
| 331 | 327 |
| 332 ThreadPool::Task::~Task() { | 328 ThreadPool::Task::~Task() {} |
| 333 } | |
| 334 | 329 |
| 335 | 330 |
| 336 ThreadPool::Worker::Worker(ThreadPool* pool) | 331 ThreadPool::Worker::Worker(ThreadPool* pool) |
| 337 : pool_(pool), | 332 : pool_(pool), |
| 338 task_(NULL), | 333 task_(NULL), |
| 339 id_(OSThread::kInvalidThreadId), | 334 id_(OSThread::kInvalidThreadId), |
| 340 done_(false), | 335 done_(false), |
| 341 owned_(false), | 336 owned_(false), |
| 342 all_next_(NULL), | 337 all_next_(NULL), |
| 343 idle_next_(NULL), | 338 idle_next_(NULL), |
| 344 shutdown_next_(NULL) { | 339 shutdown_next_(NULL) {} |
| 345 } | |
| 346 | 340 |
| 347 | 341 |
| 348 ThreadId ThreadPool::Worker::id() { | 342 ThreadId ThreadPool::Worker::id() { |
| 349 MonitorLocker ml(&monitor_); | 343 MonitorLocker ml(&monitor_); |
| 350 return id_; | 344 return id_; |
| 351 } | 345 } |
| 352 | 346 |
| 353 | 347 |
| 354 void ThreadPool::Worker::StartThread() { | 348 void ThreadPool::Worker::StartThread() { |
| 355 #if defined(DEBUG) | 349 #if defined(DEBUG) |
| 356 // Must call SetTask before StartThread. | 350 // Must call SetTask before StartThread. |
| 357 { // NOLINT | 351 { // NOLINT |
| 358 MonitorLocker ml(&monitor_); | 352 MonitorLocker ml(&monitor_); |
| 359 ASSERT(task_ != NULL); | 353 ASSERT(task_ != NULL); |
| 360 } | 354 } |
| 361 #endif | 355 #endif |
| 362 int result = OSThread::Start("Dart ThreadPool Worker", | 356 int result = OSThread::Start("Dart ThreadPool Worker", &Worker::Main, |
| 363 &Worker::Main, | |
| 364 reinterpret_cast<uword>(this)); | 357 reinterpret_cast<uword>(this)); |
| 365 if (result != 0) { | 358 if (result != 0) { |
| 366 FATAL1("Could not start worker thread: result = %d.", result); | 359 FATAL1("Could not start worker thread: result = %d.", result); |
| 367 } | 360 } |
| 368 } | 361 } |
| 369 | 362 |
| 370 | 363 |
| 371 void ThreadPool::Worker::SetTask(Task* task) { | 364 void ThreadPool::Worker::SetTask(Task* task) { |
| 372 MonitorLocker ml(&monitor_); | 365 MonitorLocker ml(&monitor_); |
| 373 ASSERT(task_ == NULL); | 366 ASSERT(task_ == NULL); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 471 // This worker is exiting because the thread pool is being shut down. | 464 // This worker is exiting because the thread pool is being shut down. |
| 472 // Inform the thread pool that we are exiting. We remove this worker from | 465 // Inform the thread pool that we are exiting. We remove this worker from |
| 473 // shutting_down_workers_ list because there will be no need for the | 466 // shutting_down_workers_ list because there will be no need for the |
| 474 // ThreadPool to take action for this worker. | 467 // ThreadPool to take action for this worker. |
| 475 ThreadJoinId join_id = OSThread::GetCurrentThreadJoinId(os_thread); | 468 ThreadJoinId join_id = OSThread::GetCurrentThreadJoinId(os_thread); |
| 476 { | 469 { |
| 477 MutexLocker ml(&pool->mutex_); | 470 MutexLocker ml(&pool->mutex_); |
| 478 JoinList::AddLocked(join_id, &pool->join_list_); | 471 JoinList::AddLocked(join_id, &pool->join_list_); |
| 479 } | 472 } |
| 480 | 473 |
| 481 // worker->id_ should never be read again, so set to invalid in debug mode | 474 // worker->id_ should never be read again, so set to invalid in debug mode |
| 482 // for asserts. | 475 // for asserts. |
| 483 #if defined(DEBUG) | 476 #if defined(DEBUG) |
| 484 { | 477 { |
| 485 MonitorLocker ml(&worker->monitor_); | 478 MonitorLocker ml(&worker->monitor_); |
| 486 worker->id_ = OSThread::kInvalidThreadId; | 479 worker->id_ = OSThread::kInvalidThreadId; |
| 487 } | 480 } |
| 488 #endif | 481 #endif |
| 489 | 482 |
| 490 // Remove from the shutdown list, delete, and notify the thread pool. | 483 // Remove from the shutdown list, delete, and notify the thread pool. |
| 491 { | 484 { |
| 492 MonitorLocker eml(&pool->exit_monitor_); | 485 MonitorLocker eml(&pool->exit_monitor_); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 505 } | 498 } |
| 506 | 499 |
| 507 // Call the thread exit hook here to notify the embedder that the | 500 // Call the thread exit hook here to notify the embedder that the |
| 508 // thread pool thread is exiting. | 501 // thread pool thread is exiting. |
| 509 if (Dart::thread_exit_callback() != NULL) { | 502 if (Dart::thread_exit_callback() != NULL) { |
| 510 (*Dart::thread_exit_callback())(); | 503 (*Dart::thread_exit_callback())(); |
| 511 } | 504 } |
| 512 } | 505 } |
| 513 | 506 |
| 514 } // namespace dart | 507 } // namespace dart |
| OLD | NEW |