u64 RuntimeQueue::Queue( ThreadId const& targetThread, RuntimeTask&& task, rqe& ec) { if(!VerifyTask(task, ec)) return 0; if(task.flags & RuntimeTask::Periodic) { task.time = RuntimeTask::clock::now() + task.interval; } if(!context->globalMod.try_lock()) { ec = RQE::ShuttingDown; return 0; } auto thread_id = targetThread.hash(); auto q_it = context->queues.find(thread_id); if(q_it == context->queues.end()) { context->globalMod.unlock(); ec = RQE::InvalidQueue; return 0; } else { context->globalMod.unlock(); return Queue(&q_it->second, std::move(task), ec); } }
bool RuntimeQueue::Block(const ThreadId& targetThread, u64 taskId, rqe& ec) { if(context->shutdownFlag.load()) { ec = RQE::ShuttingDown; return false; } DProfContext __(RQ_API "Blocking task"); auto thread_id = targetThread.hash(); RuntimeQueue* pQueue = nullptr; { Lock _(context->globalMod); auto q_it = context->queues.find(thread_id); if(q_it == context->queues.end()) { ec = RQE::InvalidQueue; return false; } pQueue = &(*q_it).second; } auto& queue = *pQueue; RuntimeTask const* task = nullptr; szptr idx = 0; if(!(task = GetTask(queue.mTasks, taskId, ec, &idx))) { ec = RQE::InvalidTaskId; return false; } { /* We do this check in case we are executing in the queue */ /* Otherwise we deadlock */ RecLock ___(queue.mTasksLock); if(!queue.mTasks[idx].alive) { ec = RQE::TaskAlreadyBlocked; return false; } auto currentBase = RuntimeTask::clock::now(); auto previousNextTime = queue.timeTillNext(currentBase); queue.mTasks[idx].alive = false; NotifyThread(context, thread_id, previousNextTime, currentBase); } return true; }
void LldbEngine::selectThread(ThreadId threadId) { DebuggerCommand cmd1("selectThread"); cmd1.arg("id", threadId.raw()); runCommand(cmd1); DebuggerCommand cmd("reportStack"); cmd.arg("nativeMixed", isNativeMixedActive()); cmd.arg("stacklimit", action(MaximalStackDepth)->value().toInt()); cmd.arg("continuation", "updateLocals"); runCommand(cmd); }
bool RuntimeQueue::CancelTask(const ThreadId& targetThread, u64 taskId, rqe& ec) { if(context->shutdownFlag.load()) { ec = RQE::ShuttingDown; return false; } auto thread_id = targetThread.hash(); RuntimeQueue* pQueue = nullptr; { Lock _(context->globalMod); auto q_it = context->queues.find(thread_id); if(q_it == context->queues.end()) { ec = RQE::InvalidQueue; return false; } pQueue = &(*q_it).second; } auto& queue = *pQueue; { RecLock _(queue.mTasksLock); RuntimeTask const* task = nullptr; szptr idx = 0; if(!(task = GetTask(queue.mTasks, taskId, ec, &idx))) { ec = RQE::InvalidTaskId; return false; } queue.mTasks[idx].alive = false; queue.mTasks[idx].to_dispose = true; auto currentBase = RuntimeTask::clock::now(); auto previousNextTime = queue.timeTillNext(currentBase); NotifyThread(context, thread_id, previousNextTime, currentBase); } return true; }
void ThreadsHandler::setCurrentThread(ThreadId id) { if (id == m_currentId) return; const int index = indexOf(id); if (index == -1) { qWarning("ThreadsHandler::setCurrentThreadId: No such thread %d.", int(id.raw())); return; } // Emit changed for previous frame. threadDataChanged(m_currentId); m_currentId = id; // Emit changed for new frame. threadDataChanged(m_currentId); updateThreadBox(); }
void RuntimeQueue::AwaitTask(const ThreadId& targetThread, u64 taskId, rqe& ec) { if(taskId == 0) return; if(context->shutdownFlag.load()) { ec = RQE::ShuttingDown; return; } if(ThreadId().hash() == targetThread.hash()) { ec = RQE::SameThread; return; } RuntimeQueue const* queueRef = nullptr; { Lock _(context->globalMod); auto queue = context->queues.find(targetThread.hash()); /* If thread has no queue, return */ if(queue == context->queues.end()) { ec = RQE::InvalidQueue; return; } queueRef = &queue->second; } RuntimeTask const* task = nullptr; szptr idx = 0; if(!(task = GetTask(queueRef->mTasks, taskId, ec, &idx))) { ec = RQE::InvalidTaskId; return; } /* We cannot reliably await periodic tasks */ if(task->flags & RuntimeTask::Periodic) { ec = RQE::IncompatibleTaskAwait; return; } /* Do not await a past event */ if(!(task->flags & RuntimeTask::Immediate) && RuntimeTask::clock::now() > task->time) { ec = RQE::ExpiredTaskDeadline; return; } DProfContext _(RQ_API "Awaiting task..."); CurrentThread::sleep_until(task->time); { DProfContext _(RQ_API "Busy-waiting task"); /* I know this is bad, but we must await the task */ while(queueRef->mTasks[idx].alive) CurrentThread::yield(); } }