Example #1
0
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);
    }
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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();
    }
}