| 316 | } |
| 317 | |
| 318 | void TimerThread::run() { |
| 319 | run_worker_startfn(); |
| 320 | #ifdef BAIDU_INTERNAL |
| 321 | logging::ComlogInitializer comlog_initializer; |
| 322 | #endif |
| 323 | |
| 324 | int64_t last_sleep_time = butil::gettimeofday_us(); |
| 325 | BT_VLOG << "Started TimerThread=" << pthread_self(); |
| 326 | |
| 327 | // min heap of tasks (ordered by run_time) |
| 328 | std::vector<Task*> tasks; |
| 329 | tasks.reserve(4096); |
| 330 | |
| 331 | // vars |
| 332 | size_t nscheduled = 0; |
| 333 | bvar::PassiveStatus<size_t> nscheduled_var(deref_value<size_t>, &nscheduled); |
| 334 | bvar::PerSecond<bvar::PassiveStatus<size_t> > nscheduled_second(&nscheduled_var); |
| 335 | size_t ntriggered = 0; |
| 336 | bvar::PassiveStatus<size_t> ntriggered_var(deref_value<size_t>, &ntriggered); |
| 337 | bvar::PerSecond<bvar::PassiveStatus<size_t> > ntriggered_second(&ntriggered_var); |
| 338 | double busy_seconds = 0; |
| 339 | bvar::PassiveStatus<double> busy_seconds_var(deref_value<double>, &busy_seconds); |
| 340 | bvar::PerSecond<bvar::PassiveStatus<double> > busy_seconds_second(&busy_seconds_var); |
| 341 | if (!_options.bvar_prefix.empty()) { |
| 342 | nscheduled_second.expose_as(_options.bvar_prefix, "scheduled_second"); |
| 343 | ntriggered_second.expose_as(_options.bvar_prefix, "triggered_second"); |
| 344 | busy_seconds_second.expose_as(_options.bvar_prefix, "usage"); |
| 345 | } |
| 346 | |
| 347 | while (!_stop.load(butil::memory_order_relaxed)) { |
| 348 | // Clear _nearest_run_time before consuming tasks from buckets. |
| 349 | // This helps us to be aware of earliest task of the new tasks before we |
| 350 | // would run the consumed tasks. |
| 351 | { |
| 352 | BAIDU_SCOPED_LOCK(_mutex); |
| 353 | // This check of _stop ensures we won't miss the reset of _nearest_run_time |
| 354 | // to 0 in stop_and_join, avoiding potential race conditions. |
| 355 | if (BAIDU_UNLIKELY(_stop.load(butil::memory_order_relaxed))) { |
| 356 | break; |
| 357 | } |
| 358 | _nearest_run_time = std::numeric_limits<int64_t>::max(); |
| 359 | } |
| 360 | |
| 361 | // Pull tasks from buckets. |
| 362 | for (size_t i = 0; i < _options.num_buckets; ++i) { |
| 363 | Bucket& bucket = _buckets[i]; |
| 364 | for (Task* p = bucket.consume_tasks(); p != nullptr; ++nscheduled) { |
| 365 | // p->next should be kept first |
| 366 | // in case of the deletion of Task p which is unscheduled |
| 367 | Task* next_task = p->next; |
| 368 | |
| 369 | if (!p->try_delete()) { // remove the task if it's unscheduled |
| 370 | tasks.push_back(p); |
| 371 | std::push_heap(tasks.begin(), tasks.end(), task_greater); |
| 372 | } |
| 373 | p = next_task; |
| 374 | } |
| 375 | } |
no test coverage detected