TEST(WebTaskRunnerTest, CancellationCheckerTest) { scheduler::FakeWebTaskRunner taskRunner; int count = 0; TaskHandle handle = taskRunner.postCancellableTask( BLINK_FROM_HERE, WTF::bind(&increment, WTF::unretained(&count))); EXPECT_EQ(0, count); // TaskHandle::isActive should detect the deletion of posted task. auto queue = taskRunner.takePendingTasksForTesting(); ASSERT_EQ(1u, queue.size()); EXPECT_FALSE(queue[0].IsCancelled()); EXPECT_TRUE(handle.isActive()); queue.clear(); EXPECT_FALSE(handle.isActive()); EXPECT_EQ(0, count); count = 0; CancellationTestHelper helper; handle = taskRunner.postCancellableTask( BLINK_FROM_HERE, WTF::bind(&CancellationTestHelper::incrementCounter, helper.createWeakPtr())); EXPECT_EQ(0, helper.counter()); // The cancellation of the posted task should be propagated to TaskHandle. queue = taskRunner.takePendingTasksForTesting(); ASSERT_EQ(1u, queue.size()); EXPECT_FALSE(queue[0].IsCancelled()); EXPECT_TRUE(handle.isActive()); helper.revokeWeakPtrs(); EXPECT_TRUE(queue[0].IsCancelled()); EXPECT_FALSE(handle.isActive()); }
static uint32_t PeriodicTask_TimerRunner(uint32_t interval, void * param) { TaskHandle handle = (TaskHandle) param; if(!handle->valid) return 0; if(handle->enabled) handle->function(handle->param); return 1; }
void ParticleSource::emit(const U64 deltaTimeUS, std::shared_ptr<ParticleData> p) { ParticleData& data = *p; const F32 dt = Time::MicrosecondsToSeconds<F32>(deltaTimeUS); const U32 maxNewParticles = to_U32(dt * _emitRate); const U32 startID = data.aliveCount(); const U32 endID = std::min(startID + maxNewParticles, data.totalCount() - 1); TaskHandle generateTask = CreateTask(_context.context(), DELEGATE_CBK<void, const Task&>()); for (std::shared_ptr<ParticleGenerator>& gen : _particleGenerators) { gen->generate(generateTask, deltaTimeUS, data, startID, endID); } generateTask.startTask().wait(); for (U32 i = startID; i < endID; ++i) { p->wake(i); } }
void TaskAllocator::ReleaseTask( TaskHandle& task_handle ) { ASSERT( task_handle != INVALID_TASK_HANDLE ); // Make task available to others. task_handle.m_task->Clear(); // Calculate pool marker as difference between pointers: size_t pool_marker = task_handle.m_task - m_taskPool; m_poolMarkers[ pool_marker ].Store( 0, MemoryOrder::Release ); // Invalidate pointer to avoid using released task! task_handle.Invalidate(); }
void BackgroundProcessingPool::threadFunction() { setThreadName("BackgrProcPool"); MemoryTracker memory_tracker; memory_tracker.setMetric(CurrentMetrics::MemoryTrackingInBackgroundProcessingPool); current_memory_tracker = &memory_tracker; std::mt19937 rng(reinterpret_cast<intptr_t>(&rng)); std::this_thread::sleep_for(std::chrono::duration<double>(std::uniform_real_distribution<double>(0, sleep_seconds_random_part)(rng))); while (!shutdown) { bool done_work = false; TaskHandle task; try { Poco::Timestamp min_time; { std::unique_lock<std::mutex> lock(tasks_mutex); if (!tasks.empty()) { for (const auto & time_handle : tasks) { if (!time_handle.second->removed) { min_time = time_handle.first; task = time_handle.second; break; } } } } if (shutdown) break; if (!task) { std::unique_lock<std::mutex> lock(tasks_mutex); wake_event.wait_for(lock, std::chrono::duration<double>(sleep_seconds + std::uniform_real_distribution<double>(0, sleep_seconds_random_part)(rng))); continue; } /// No tasks ready for execution. Poco::Timestamp current_time; if (min_time > current_time) { std::unique_lock<std::mutex> lock(tasks_mutex); wake_event.wait_for(lock, std::chrono::microseconds( min_time - current_time + std::uniform_int_distribution<uint64_t>(0, sleep_seconds_random_part * 1000000)(rng))); } Poco::ScopedReadRWLock rlock(task->rwlock); if (task->removed) continue; { CurrentMetrics::Increment metric_increment{CurrentMetrics::BackgroundPoolTask}; done_work = task->function(); } } catch (...) { tryLogCurrentException(__PRETTY_FUNCTION__); } if (shutdown) break; /// If task has done work, it could be executed again immediately. /// If not, add delay before next run. Poco::Timestamp next_time_to_execute = Poco::Timestamp() + (done_work ? 0 : sleep_seconds * 1000000); { std::unique_lock<std::mutex> lock(tasks_mutex); if (task->removed) continue; tasks.erase(task->iterator); task->iterator = tasks.emplace(next_time_to_execute, task); } } current_memory_tracker = nullptr; }
TEST(WebTaskRunnerTest, PostCancellableTaskTest) { scheduler::FakeWebTaskRunner taskRunner; // Run without cancellation. int count = 0; TaskHandle handle = taskRunner.postCancellableTask( BLINK_FROM_HERE, WTF::bind(&increment, WTF::unretained(&count))); EXPECT_EQ(0, count); EXPECT_TRUE(handle.isActive()); taskRunner.runUntilIdle(); EXPECT_EQ(1, count); EXPECT_FALSE(handle.isActive()); count = 0; handle = taskRunner.postDelayedCancellableTask( BLINK_FROM_HERE, WTF::bind(&increment, WTF::unretained(&count)), 1); EXPECT_EQ(0, count); EXPECT_TRUE(handle.isActive()); taskRunner.runUntilIdle(); EXPECT_EQ(1, count); EXPECT_FALSE(handle.isActive()); // Cancel a task. count = 0; handle = taskRunner.postCancellableTask( BLINK_FROM_HERE, WTF::bind(&increment, WTF::unretained(&count))); handle.cancel(); EXPECT_EQ(0, count); EXPECT_FALSE(handle.isActive()); taskRunner.runUntilIdle(); EXPECT_EQ(0, count); // The task should be cancelled when the handle is dropped. { count = 0; TaskHandle handle2 = taskRunner.postCancellableTask( BLINK_FROM_HERE, WTF::bind(&increment, WTF::unretained(&count))); EXPECT_TRUE(handle2.isActive()); } EXPECT_EQ(0, count); taskRunner.runUntilIdle(); EXPECT_EQ(0, count); // The task should be cancelled when another TaskHandle is assigned on it. count = 0; handle = taskRunner.postCancellableTask( BLINK_FROM_HERE, WTF::bind(&increment, WTF::unretained(&count))); handle = taskRunner.postCancellableTask(BLINK_FROM_HERE, WTF::bind([] {})); EXPECT_EQ(0, count); taskRunner.runUntilIdle(); EXPECT_EQ(0, count); // Self assign should be nop. count = 0; handle = taskRunner.postCancellableTask( BLINK_FROM_HERE, WTF::bind(&increment, WTF::unretained(&count))); #if COMPILER(CLANG) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wself-move" handle = std::move(handle); #pragma GCC diagnostic pop #else handle = std::move(handle); #endif // COMPILER(CLANG) EXPECT_EQ(0, count); taskRunner.runUntilIdle(); EXPECT_EQ(1, count); // handle->isActive() should switch to false before the task starts running. bool isActive = false; handle = taskRunner.postCancellableTask( BLINK_FROM_HERE, WTF::bind(&getIsActive, WTF::unretained(&isActive), WTF::unretained(&handle))); EXPECT_TRUE(handle.isActive()); taskRunner.runUntilIdle(); EXPECT_FALSE(isActive); EXPECT_FALSE(handle.isActive()); }