示例#1
0
    void ForegroundJobProcessor::RemoveManager(JobManager *const manager)
    {
        Assert(manager);
        // Managers must remove themselves. Hence, Close does not remove managers. So, not asserting on !IsClosed().

        managers.Unlink(manager);
        if (manager->numJobsAddedToProcessor == 0)
            return;

        // Remove this manager's jobs from the queue
        Job *firstJob = 0;
        for (Job *job = jobs.Head(); job; job = job->Next())
        {
            if (job->Manager() == manager)
            {
                if (!firstJob)
                    firstJob = job;
            }
            else if (firstJob)
            {
                jobs.UnlinkSubsequence(firstJob, job->Previous());
                for (Job *removedJob = firstJob; removedJob;)
                {
                    Job *const next = removedJob->Next();
                    Assert(!removedJob->IsCritical());
                    JobProcessed(manager, removedJob, false); // the job may be deleted during this and should not be used afterwards
                    Assert(manager->numJobsAddedToProcessor != 0);
                    --manager->numJobsAddedToProcessor;
                    removedJob = next;
                }
                firstJob = 0;
            }
        }
        if (firstJob)
        {
            jobs.UnlinkSubsequenceFromEnd(firstJob);
            for (Job *removedJob = firstJob; removedJob;)
            {
                Job *const next = removedJob->Next();
                Assert(!removedJob->IsCritical());
                JobProcessed(manager, removedJob, false); // the job may be deleted during this and should not be used afterwards
                Assert(manager->numJobsAddedToProcessor != 0);
                --manager->numJobsAddedToProcessor;
                removedJob = next;
            }
        }

        Assert(manager->numJobsAddedToProcessor == 0);
        LastJobProcessed(manager);
    }
示例#2
0
    void JobProcessor::PrioritizeManager(JobManager *const manager)
    {
        Assert(manager);
        Assert(!isClosed);

        managers.MoveToBeginning(manager);
        if (manager->numJobsAddedToProcessor == 0)
        {
            return;
        }

        // Move this manager's jobs to the beginning too. Find sequences of this manager's jobs backwards so that their relative
        // order remains intact after the sequences are moved.
        Job *const originalHead = jobs.Head();
        Job *lastJob = 0;
        for (Job *job = jobs.Tail(); job; job = job->Previous())
        {
            if (job->Manager() == manager)
            {
                if (!lastJob)
                    lastJob = job;
            }
            else if (lastJob)
            {
                jobs.MoveSubsequenceToBeginning(job->Next(), lastJob);
                lastJob = 0;
            }

            if (job == originalHead)
            {
                break;
            }
        }
        if (lastJob)
        {
            jobs.MoveSubsequenceToBeginning(originalHead, lastJob);
        }
    }
示例#3
0
    void ForegroundJobProcessor::Close()
    {
        if (IsClosed())
            return;

        for (Job *job = jobs.Head(); job;)
        {
            Job *const next = job->Next();
            JobManager *const manager = job->Manager();
            JobProcessed(
                manager,
                job,
                job->IsCritical() ? Process(job) : false); // the job may be deleted during this and should not be used afterwards
            Assert(manager->numJobsAddedToProcessor != 0);
            --manager->numJobsAddedToProcessor;
            if (manager->numJobsAddedToProcessor == 0)
                LastJobProcessed(manager); // the manager may be deleted during this and should not be used afterwards
            job = next;
        }
        jobs.Clear();

        JobProcessor::Close();
    }
示例#4
0
    void BackgroundJobProcessor::RemoveManager(JobManager *const manager)
    {
        Assert(manager);

        ParallelThreadData *threadDataProcessingCurrentJob = nullptr;
        {
            AutoCriticalSection lock(&criticalSection);
            // Managers must remove themselves. Hence, Close does not remove managers. So, not asserting on !IsClosed().

            managers.Unlink(manager);
            if(manager->numJobsAddedToProcessor == 0)
            {
                Assert(!GetCurrentJobOfManager(manager));
                return;
            }

            // Remove this manager's jobs from the queue
            Job *firstJob = 0;
            for(Job *job = jobs.Head(); job; job = job->Next())
            {
                if(job->Manager() == manager)
                {
                    if(!firstJob)
                        firstJob = job;
                }
                else if(firstJob)
                {
                    jobs.UnlinkSubsequence(firstJob, job->Previous());
                    for(Job *removedJob = firstJob; removedJob;)
                    {
                        Job *const next = removedJob->Next();
                        Assert(!removedJob->IsCritical());
                        Assert(numJobs != 0);
                        --numJobs;
                        JobProcessed(manager, removedJob, false); // the job may be deleted during this and should not be used afterwards
                        Assert(manager->numJobsAddedToProcessor != 0);
                        --manager->numJobsAddedToProcessor;
                        if(manager->isWaitable)
                        {
                            WaitableJobManager *const waitableManager = static_cast<WaitableJobManager *>(manager);
                            if(waitableManager->jobBeingWaitedUpon == removedJob)
                            {
                                waitableManager->jobBeingWaitedUponProcessed.Set();
                                waitableManager->jobBeingWaitedUpon = 0;
                            }
                        }
                        removedJob = next;
                    }
                    firstJob = 0;
                }
            }
            if(firstJob)
            {
                jobs.UnlinkSubsequenceFromEnd(firstJob);
                for(Job *removedJob = firstJob; removedJob;)
                {
                    Job *const next = removedJob->Next();
                    Assert(!removedJob->IsCritical());
                    Assert(numJobs != 0);
                    --numJobs;
                    JobProcessed(manager, removedJob, false); // the job may be deleted during this and should not be used afterwards
                    Assert(manager->numJobsAddedToProcessor != 0);
                    --manager->numJobsAddedToProcessor;
                    if(manager->isWaitable)
                    {
                        WaitableJobManager *const waitableManager = static_cast<WaitableJobManager *>(manager);
                        if(waitableManager->jobBeingWaitedUpon == removedJob)
                        {
                            waitableManager->jobBeingWaitedUponProcessed.Set();
                            waitableManager->jobBeingWaitedUpon = 0;
                        }
                    }
                    removedJob = next;
                }
            }

            if(manager->numJobsAddedToProcessor == 0)
            {
                LastJobProcessed(manager);
                return;
            }

            Assert(manager->numJobsAddedToProcessor >= 1);
            Assert(manager->isWaitable);
            Assert(GetCurrentJobOfManager(manager));

        }

        //Wait for all the on going jobs to complete.
        criticalSection.Enter();
        while (true)
        {
            Job *job = GetCurrentJobOfManager(manager);
            if (!job)
            {
                break;
            }

            WaitableJobManager * const waitableManager = static_cast<WaitableJobManager *>(manager);
            Assert(!waitableManager->jobBeingWaitedUpon);

            waitableManager->jobBeingWaitedUpon = job;
            waitableManager->jobBeingWaitedUponProcessed.Reset();

            threadDataProcessingCurrentJob = GetThreadDataFromCurrentJob(waitableManager->jobBeingWaitedUpon);
            criticalSection.Leave();

            WaitWithThread(threadDataProcessingCurrentJob, waitableManager->jobBeingWaitedUponProcessed);

            criticalSection.Enter();
            waitableManager->jobBeingWaitedUpon = 0;
        }
        criticalSection.Leave();
    }
示例#5
0
    void BackgroundJobProcessor::Run(ParallelThreadData* threadData)
    {
        JS_ETW(EventWriteJSCRIPT_NATIVECODEGEN_START(this, 0));

        ArenaAllocator threadArena(_u("ThreadArena"), threadData->GetPageAllocator(), Js::Throw::OutOfMemory);
        threadData->threadArena = &threadArena;

        {
            // Make sure we take decommit action before the threadArena is torn down, in case the
            // thread context goes away and the loop exits.
            struct AutoDecommit
            {
                AutoDecommit(JobProcessor *proc, ParallelThreadData *data) : processor(proc), threadData(data) {}
                ~AutoDecommit()
                {
                    processor->ForEachManager([this](JobManager *manager){
                        manager->OnDecommit(this->threadData);
                    });
                }
                ParallelThreadData *threadData;
                JobProcessor *processor;
            } autoDecommit(this, threadData);

            criticalSection.Enter();
            while (!IsClosed() || (jobs.Head() && jobs.Head()->IsCritical()))
            {
                Job *job = jobs.UnlinkFromBeginning();

                if(!job)
                {
                    // No jobs in queue, wait for one

                    Assert(!IsClosed());
                    Assert(!threadData->isWaitingForJobs);
                    threadData->isWaitingForJobs = true;
                    criticalSection.Leave();
                    JS_ETW(EventWriteJSCRIPT_NATIVECODEGEN_STOP(this, 0));

                    if (threadService->HasCallback())
                    {
                        // We have a thread service, so simply return the thread back now.
                        // When new jobs are submitted, we will be called to process again.
                        return;
                    }

                    WaitForJobReadyOrShutdown(threadData);

                    JS_ETW(EventWriteJSCRIPT_NATIVECODEGEN_START(this, 0));
                    criticalSection.Enter();
                    threadData->isWaitingForJobs = false;
                    continue;
                }

                Assert(numJobs != 0);
                --numJobs;
                threadData->currentJob = job;
                criticalSection.Leave();

                const bool succeeded = Process(job, threadData);

                criticalSection.Enter();
                threadData->currentJob = 0;
                JobManager *const manager = job->Manager();
                JobProcessed(manager, job, succeeded); // the job may be deleted during this and should not be used afterwards
                Assert(manager->numJobsAddedToProcessor != 0);
                --manager->numJobsAddedToProcessor;
                if(manager->isWaitable)
                {
                    WaitableJobManager *const waitableManager = static_cast<WaitableJobManager *>(manager);
                    Assert(!(waitableManager->jobBeingWaitedUpon && waitableManager->isWaitingForQueuedJobs));
                    if(waitableManager->jobBeingWaitedUpon == job)
                    {
                        waitableManager->jobBeingWaitedUpon = 0;
                        waitableManager->jobBeingWaitedUponProcessed.Set();
                    }
                    else if(waitableManager->isWaitingForQueuedJobs && manager->numJobsAddedToProcessor == 0)
                    {
                        waitableManager->isWaitingForQueuedJobs = false;
                        waitableManager->queuedJobsProcessed.Set();
                    }
                }
                if(manager->numJobsAddedToProcessor == 0)
                    LastJobProcessed(manager); // the manager may be deleted during this and should not be used afterwards
            }
            criticalSection.Leave();

            JS_ETW(EventWriteJSCRIPT_NATIVECODEGEN_STOP(this, 0));
        }
    }