Changeset View
Changeset View
Standalone View
Standalone View
kdevplatform/language/backgroundparser/backgroundparser.cpp
Show All 33 Lines | |||||
34 | #include <KConfigGroup> | 34 | #include <KConfigGroup> | ||
35 | #include <KSharedConfig> | 35 | #include <KSharedConfig> | ||
36 | #include <KLocalizedString> | 36 | #include <KLocalizedString> | ||
37 | 37 | | |||
38 | #include <ThreadWeaver/State> | 38 | #include <ThreadWeaver/State> | ||
39 | #include <ThreadWeaver/ThreadWeaver> | 39 | #include <ThreadWeaver/ThreadWeaver> | ||
40 | #include <ThreadWeaver/DebuggingAids> | 40 | #include <ThreadWeaver/DebuggingAids> | ||
41 | 41 | | |||
42 | #include <KJob> | ||||
43 | | ||||
42 | #include <interfaces/icore.h> | 44 | #include <interfaces/icore.h> | ||
43 | #include <interfaces/idocumentcontroller.h> | 45 | #include <interfaces/idocumentcontroller.h> | ||
44 | #include <interfaces/ilanguagecontroller.h> | 46 | #include <interfaces/ilanguagecontroller.h> | ||
45 | #include <interfaces/ilanguagesupport.h> | 47 | #include <interfaces/ilanguagesupport.h> | ||
46 | #include <interfaces/isession.h> | 48 | #include <interfaces/isession.h> | ||
47 | #include <interfaces/iproject.h> | 49 | #include <interfaces/iproject.h> | ||
48 | #include <interfaces/iprojectcontroller.h> | 50 | #include <interfaces/iprojectcontroller.h> | ||
51 | #include <interfaces/iruncontroller.h> | ||||
49 | 52 | | |||
50 | #include <debug.h> | 53 | #include <debug.h> | ||
51 | 54 | | |||
52 | #include "parsejob.h" | 55 | #include "parsejob.h" | ||
53 | 56 | | |||
54 | using namespace KDevelop; | 57 | using namespace KDevelop; | ||
55 | 58 | | |||
56 | namespace { | 59 | namespace { | ||
▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Line(s) | 171 | { | |||
175 | 178 | | |||
176 | return ret; | 179 | return ret; | ||
177 | } | 180 | } | ||
178 | }; | 181 | }; | ||
179 | 182 | | |||
180 | Q_DECLARE_TYPEINFO(DocumentParseTarget, Q_MOVABLE_TYPE); | 183 | Q_DECLARE_TYPEINFO(DocumentParseTarget, Q_MOVABLE_TYPE); | ||
181 | Q_DECLARE_TYPEINFO(DocumentParsePlan, Q_MOVABLE_TYPE); | 184 | Q_DECLARE_TYPEINFO(DocumentParsePlan, Q_MOVABLE_TYPE); | ||
182 | 185 | | |||
186 | class BGParserControllerProxy : public KJob | ||||
187 | { | ||||
188 | Q_OBJECT | ||||
189 | public: | ||||
190 | BGParserControllerProxy(BackgroundParserPrivate *proxy); | ||||
191 | | ||||
192 | ~BGParserControllerProxy(); | ||||
193 | | ||||
194 | /* | ||||
195 | * has the @p url been registered by this proxy controller? | ||||
196 | */ | ||||
197 | bool isUrlRegistered(const KDevelop::IndexedString &url); | ||||
198 | | ||||
199 | void start(); | ||||
200 | bool doKill(); | ||||
201 | void done(); | ||||
202 | | ||||
203 | BackgroundParserPrivate* m_proxied; | ||||
204 | QSet<KDevelop::IndexedString> m_urls; | ||||
205 | bool beingKilled = false; | ||||
206 | | ||||
207 | public Q_SLOTS: | ||||
208 | /* | ||||
209 | * Register @p url with this proxy controller, make it possible | ||||
210 | * to prevent it from being started. | ||||
211 | * This has to be done via a queued-connection signal to ensure that | ||||
212 | * the registering with the the RunController is done in the | ||||
213 | * appropriate thread. | ||||
214 | */ | ||||
215 | void registerUrl(const KDevelop::IndexedString &url); | ||||
216 | /** | ||||
217 | * Unregister @p url from this proxy controller. | ||||
218 | */ | ||||
219 | void unregisterUrl(const KDevelop::IndexedString &url); | ||||
220 | }; | ||||
221 | | ||||
183 | class KDevelop::BackgroundParserPrivate | 222 | class KDevelop::BackgroundParserPrivate | ||
184 | { | 223 | { | ||
185 | public: | 224 | public: | ||
186 | BackgroundParserPrivate(BackgroundParser* parser, ILanguageController* languageController) | 225 | BackgroundParserPrivate(BackgroundParser* parser, ILanguageController* languageController) | ||
187 | : m_parser(parser) | 226 | : m_parser(parser) | ||
188 | , m_languageController(languageController) | 227 | , m_languageController(languageController) | ||
189 | , m_shuttingDown(false) | 228 | , m_shuttingDown(false) | ||
190 | , m_mutex(QMutex::Recursive) | 229 | , m_mutex(QMutex::Recursive) | ||
Show All 14 Lines | |||||
205 | { | 244 | { | ||
206 | QMetaObject::invokeMethod(m_parser, "startTimer", Qt::QueuedConnection, Q_ARG(int, delay)); | 245 | QMetaObject::invokeMethod(m_parser, "startTimer", Qt::QueuedConnection, Q_ARG(int, delay)); | ||
207 | } | 246 | } | ||
208 | 247 | | |||
209 | ~BackgroundParserPrivate() | 248 | ~BackgroundParserPrivate() | ||
210 | { | 249 | { | ||
211 | m_weaver.resume(); | 250 | m_weaver.resume(); | ||
212 | m_weaver.finish(); | 251 | m_weaver.finish(); | ||
252 | if (m_bgControlledJobProxy) { | ||||
253 | delete m_bgControlledJobProxy; | ||||
254 | } | ||||
213 | } | 255 | } | ||
214 | 256 | | |||
215 | // Non-mutex guarded functions, only call with m_mutex acquired. | 257 | // Non-mutex guarded functions, only call with m_mutex acquired. | ||
216 | 258 | | |||
217 | int currentBestRunningPriority() const | 259 | int currentBestRunningPriority() const | ||
218 | { | 260 | { | ||
219 | int bestRunningPriority = BackgroundParser::WorstPriority; | 261 | int bestRunningPriority = BackgroundParser::WorstPriority; | ||
220 | for (const auto* decorator : m_parseJobs) { | 262 | for (const auto* decorator : m_parseJobs) { | ||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Line(s) | 330 | if (!url.isEmpty()) { | |||
326 | if (decorator) { | 368 | if (decorator) { | ||
327 | if (m_parseJobs.count() == m_threads + 1 && !specialParseJob) | 369 | if (m_parseJobs.count() == m_threads + 1 && !specialParseJob) | ||
328 | specialParseJob = decorator; //This parse-job is allocated into the reserved thread | 370 | specialParseJob = decorator; //This parse-job is allocated into the reserved thread | ||
329 | 371 | | |||
330 | m_parseJobs.insert(url, decorator); | 372 | m_parseJobs.insert(url, decorator); | ||
331 | m_weaver.enqueue(ThreadWeaver::JobPointer(decorator)); | 373 | m_weaver.enqueue(ThreadWeaver::JobPointer(decorator)); | ||
332 | } else { | 374 | } else { | ||
333 | --m_maxParseJobs; | 375 | --m_maxParseJobs; | ||
376 | if (m_bgControlledJobProxy) { | ||||
377 | QMetaObject::invokeMethod(m_bgControlledJobProxy, "unregisterUrl", | ||||
378 | Qt::QueuedConnection, Q_ARG(const KDevelop::IndexedString, url)); | ||||
379 | } | ||||
334 | } | 380 | } | ||
335 | 381 | | |||
336 | if (!m_documents.isEmpty()) { | 382 | if (!m_documents.isEmpty()) { | ||
337 | // Only try creating one parse-job at a time, else we might iterate through thousands of files | 383 | // Only try creating one parse-job at a time, else we might iterate through thousands of files | ||
338 | // without finding a language-support, and block the UI for a long time. | 384 | // without finding a language-support, and block the UI for a long time. | ||
339 | QMetaObject::invokeMethod(m_parser, "parseDocuments", Qt::QueuedConnection); | 385 | QMetaObject::invokeMethod(m_parser, "parseDocuments", Qt::QueuedConnection); | ||
340 | } else { | 386 | } else { | ||
341 | // make sure we cleaned up properly | 387 | // make sure we cleaned up properly | ||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Line(s) | 506 | { | |||
466 | } | 512 | } | ||
467 | 513 | | |||
468 | m_timer.start(m_delay); | 514 | m_timer.start(m_delay); | ||
469 | m_weaver.resume(); | 515 | m_weaver.resume(); | ||
470 | } | 516 | } | ||
471 | 517 | | |||
472 | BackgroundParser* m_parser; | 518 | BackgroundParser* m_parser; | ||
473 | ILanguageController* m_languageController; | 519 | ILanguageController* m_languageController; | ||
520 | BGParserControllerProxy* m_bgControlledJobProxy = nullptr; | ||||
521 | QHash<IndexedString,QPointer<KJob> > m_controllerJobs; | ||||
474 | 522 | | |||
475 | //Current parse-job that is executed in the additional thread | 523 | //Current parse-job that is executed in the additional thread | ||
476 | QPointer<QObject> specialParseJob; | 524 | QPointer<QObject> specialParseJob; | ||
477 | 525 | | |||
478 | QTimer m_timer; | 526 | QTimer m_timer; | ||
479 | int m_delay = 500; | 527 | int m_delay = 500; | ||
480 | int m_threads = 1; | 528 | int m_threads = 1; | ||
481 | 529 | | |||
▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Line(s) | 639 | if ((*it).targets.isEmpty()) { | |||
595 | continue; | 643 | continue; | ||
596 | } | 644 | } | ||
597 | 645 | | |||
598 | d->m_documentsForPriority[it.value().priority()].insert(it.key()); | 646 | d->m_documentsForPriority[it.value().priority()].insert(it.key()); | ||
599 | ++it; | 647 | ++it; | ||
600 | } | 648 | } | ||
601 | } | 649 | } | ||
602 | 650 | | |||
603 | void BackgroundParser::addDocument(const IndexedString& url, TopDUContext::Features features, int priority, | 651 | void BackgroundParser::addControlledDocument(const IndexedString& url, QPointer<KJob> controlledJob, TopDUContext::Features features, int priority, | ||
604 | QObject* notifyWhenReady, ParseJob::SequentialProcessingFlags flags, int delay) | 652 | QObject* notifyWhenReady, ParseJob::SequentialProcessingFlags flags, int delay) | ||
605 | { | 653 | { | ||
606 | Q_D(BackgroundParser); | 654 | Q_D(BackgroundParser); | ||
607 | 655 | | |||
608 | qCDebug(LANGUAGE) << "BackgroundParser::addDocument" << url << url.toUrl(); | 656 | qCDebug(LANGUAGE) << "BackgroundParser::addControlledDocument" << url << url.toUrl(); | ||
609 | Q_ASSERT(isValidURL(url)); | 657 | Q_ASSERT(isValidURL(url)); | ||
610 | QMutexLocker lock(&d->m_mutex); | 658 | QMutexLocker lock(&d->m_mutex); | ||
611 | { | 659 | { | ||
612 | DocumentParseTarget target; | 660 | DocumentParseTarget target; | ||
613 | target.priority = priority; | 661 | target.priority = priority; | ||
614 | target.features = features; | 662 | target.features = features; | ||
615 | target.sequentialProcessingFlags = flags; | 663 | target.sequentialProcessingFlags = flags; | ||
616 | target.notifyWhenReady = QPointer<QObject>(notifyWhenReady); | 664 | target.notifyWhenReady = QPointer<QObject>(notifyWhenReady); | ||
617 | 665 | | |||
618 | auto it = d->m_documents.find(url); | 666 | auto it = d->m_documents.find(url); | ||
619 | 667 | | |||
620 | if (it != d->m_documents.end()) { | 668 | if (it != d->m_documents.end()) { | ||
621 | //Update the stored plan | 669 | //Update the stored plan | ||
622 | 670 | | |||
623 | d->m_documentsForPriority[it.value().priority()].remove(url); | 671 | d->m_documentsForPriority[it.value().priority()].remove(url); | ||
624 | it.value().targets << target; | 672 | it.value().targets << target; | ||
625 | d->m_documentsForPriority[it.value().priority()].insert(url); | 673 | d->m_documentsForPriority[it.value().priority()].insert(url); | ||
626 | } else { | 674 | } else { | ||
627 | // qCDebug(LANGUAGE) << "BackgroundParser::addDocument: queuing" << cleanedUrl; | 675 | // qCDebug(LANGUAGE) << "BackgroundParser::addDocument: queuing" << cleanedUrl; | ||
628 | d->m_documents[url].targets << target; | 676 | d->m_documents[url].targets << target; | ||
629 | d->m_documentsForPriority[d->m_documents[url].priority()].insert(url); | 677 | d->m_documentsForPriority[d->m_documents[url].priority()].insert(url); | ||
630 | ++d->m_maxParseJobs; //So the progress-bar waits for this document | 678 | ++d->m_maxParseJobs; //So the progress-bar waits for this document | ||
631 | } | 679 | } | ||
680 | // for simplicity we don't track documents under control of m_bgControlledJobProxy | ||||
681 | if (controlledJob != d->m_bgControlledJobProxy) { | ||||
682 | d->m_controllerJobs.insert(url, controlledJob); | ||||
683 | } | ||||
632 | 684 | | |||
633 | if (delay == ILanguageSupport::DefaultDelay) { | 685 | if (delay == ILanguageSupport::DefaultDelay) { | ||
634 | delay = d->m_delay; | 686 | delay = d->m_delay; | ||
635 | } | 687 | } | ||
636 | d->startTimerThreadSafe(delay); | 688 | d->startTimerThreadSafe(delay); | ||
637 | } | 689 | } | ||
638 | } | 690 | } | ||
639 | 691 | | |||
692 | void BackgroundParser::addDocument(const IndexedString& url, TopDUContext::Features features, int priority, | ||||
693 | QObject* notifyWhenReady, ParseJob::SequentialProcessingFlags flags, int delay) | ||||
694 | { | ||||
695 | Q_D(BackgroundParser); | ||||
696 | | ||||
697 | if (d->m_controllerJobs.contains(url)) { | ||||
698 | if (d->m_controllerJobs[url]) { | ||||
699 | #ifdef QT_DEBUG | ||||
700 | qCDebug(LANGUAGE) << "url" << url << "already managed by" << d->m_controllerJobs[url]; | ||||
701 | #endif | ||||
702 | // document already under control of a job managed upstream that is being rescheduled for parsing | ||||
703 | addControlledDocument(url, d->m_controllerJobs[url], features, priority, notifyWhenReady, flags, delay); | ||||
704 | return; | ||||
705 | } else { | ||||
706 | qCDebug(LANGUAGE) << "url" << url << "was registered to stale controller job"; | ||||
707 | d->m_controllerJobs.remove(url); | ||||
708 | } | ||||
709 | } | ||||
710 | if (!d->m_bgControlledJobProxy) { | ||||
711 | d->m_bgControlledJobProxy = new BGParserControllerProxy(d); | ||||
712 | } | ||||
713 | QMetaObject::invokeMethod(d->m_bgControlledJobProxy, "registerUrl", | ||||
714 | Qt::QueuedConnection, Q_ARG(const KDevelop::IndexedString, url)); | ||||
715 | addControlledDocument(url, d->m_bgControlledJobProxy, features, priority, notifyWhenReady, flags, delay); | ||||
716 | } | ||||
717 | | ||||
640 | void BackgroundParser::removeDocument(const IndexedString& url, QObject* notifyWhenReady) | 718 | void BackgroundParser::removeDocument(const IndexedString& url, QObject* notifyWhenReady) | ||
641 | { | 719 | { | ||
642 | Q_D(BackgroundParser); | 720 | Q_D(BackgroundParser); | ||
643 | 721 | | |||
644 | Q_ASSERT(isValidURL(url)); | 722 | Q_ASSERT(isValidURL(url)); | ||
645 | 723 | | |||
646 | QMutexLocker lock(&d->m_mutex); | 724 | QMutexLocker lock(&d->m_mutex); | ||
647 | 725 | | |||
Show All 12 Lines | 727 | if (documentParsePlanIt != d->m_documents.end()) { | |||
660 | if (documentParsePlan.targets.isEmpty()) { | 738 | if (documentParsePlan.targets.isEmpty()) { | ||
661 | d->m_documents.erase(documentParsePlanIt); | 739 | d->m_documents.erase(documentParsePlanIt); | ||
662 | --d->m_maxParseJobs; | 740 | --d->m_maxParseJobs; | ||
663 | } else { | 741 | } else { | ||
664 | //Insert with an eventually different priority | 742 | //Insert with an eventually different priority | ||
665 | d->m_documentsForPriority[documentParsePlan.priority()].insert(url); | 743 | d->m_documentsForPriority[documentParsePlan.priority()].insert(url); | ||
666 | } | 744 | } | ||
667 | } | 745 | } | ||
746 | if (d->m_bgControlledJobProxy) { | ||||
747 | QMetaObject::invokeMethod(d->m_bgControlledJobProxy, "unregisterUrl", | ||||
748 | Qt::QueuedConnection, Q_ARG(const KDevelop::IndexedString, url)); | ||||
749 | } | ||||
668 | } | 750 | } | ||
669 | 751 | | |||
670 | void BackgroundParser::parseDocuments() | 752 | void BackgroundParser::parseDocuments() | ||
671 | { | 753 | { | ||
672 | Q_D(BackgroundParser); | 754 | Q_D(BackgroundParser); | ||
673 | 755 | | |||
674 | if (d->isSuspended() || !d->m_loadingProjects.empty()) { | 756 | if (d->isSuspended() || !d->m_loadingProjects.empty()) { | ||
675 | startTimer(d->m_delay); | 757 | startTimer(d->m_delay); | ||
Show All 12 Lines | 766 | { | |||
688 | Q_ASSERT(decorator); | 770 | Q_ASSERT(decorator); | ||
689 | auto* parseJob = dynamic_cast<ParseJob*>(decorator->job()); | 771 | auto* parseJob = dynamic_cast<ParseJob*>(decorator->job()); | ||
690 | Q_ASSERT(parseJob); | 772 | Q_ASSERT(parseJob); | ||
691 | emit parseJobFinished(parseJob); | 773 | emit parseJobFinished(parseJob); | ||
692 | 774 | | |||
693 | { | 775 | { | ||
694 | QMutexLocker lock(&d->m_mutex); | 776 | QMutexLocker lock(&d->m_mutex); | ||
695 | 777 | | |||
696 | d->m_parseJobs.remove(parseJob->document()); | 778 | const auto url = parseJob->document(); | ||
779 | d->m_parseJobs.remove(url); | ||||
697 | 780 | | |||
698 | d->m_jobProgress.remove(parseJob); | 781 | d->m_jobProgress.remove(parseJob); | ||
699 | 782 | | |||
700 | ++d->m_doneParseJobs; | 783 | ++d->m_doneParseJobs; | ||
784 | if (d->m_bgControlledJobProxy) { | ||||
785 | QMetaObject::invokeMethod(d->m_bgControlledJobProxy, "unregisterUrl", | ||||
786 | Qt::QueuedConnection, Q_ARG(const KDevelop::IndexedString, url)); | ||||
787 | } | ||||
701 | updateProgressData(); | 788 | updateProgressData(); | ||
702 | } | 789 | } | ||
703 | 790 | | |||
704 | //Continue creating more parse-jobs | 791 | //Continue creating more parse-jobs | ||
705 | QMetaObject::invokeMethod(this, "parseDocuments", Qt::QueuedConnection); | 792 | QMetaObject::invokeMethod(this, "parseDocuments", Qt::QueuedConnection); | ||
706 | } | 793 | } | ||
707 | 794 | | |||
708 | void BackgroundParser::disableProcessing() | 795 | void BackgroundParser::disableProcessing() | ||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Line(s) | 885 | } else { | |||
802 | } | 889 | } | ||
803 | 890 | | |||
804 | d->m_progressMax = d->m_maxParseJobs * 1000; | 891 | d->m_progressMax = d->m_maxParseJobs * 1000; | ||
805 | d->m_progressDone = (additionalProgress + d->m_doneParseJobs) * 1000; | 892 | d->m_progressDone = (additionalProgress + d->m_doneParseJobs) * 1000; | ||
806 | 893 | | |||
807 | if (!d->m_progressTimer.isActive()) { | 894 | if (!d->m_progressTimer.isActive()) { | ||
808 | d->m_progressTimer.start(); | 895 | d->m_progressTimer.start(); | ||
809 | } | 896 | } | ||
897 | if (!d->m_totalTimer.isValid()) { | ||||
898 | d->m_totalTimer.start(); | ||||
899 | d->m_totalJobs = d->m_maxParseJobs; | ||||
900 | } | ||||
810 | } | 901 | } | ||
811 | 902 | | |||
812 | // Cancel progress updating and hide progress-bar when parsing is done. | 903 | // Cancel progress updating and hide progress-bar when parsing is done. | ||
813 | if (d->m_doneParseJobs == d->m_maxParseJobs | 904 | if (d->m_doneParseJobs == d->m_maxParseJobs | ||
814 | || (d->m_neededPriority == BackgroundParser::BestPriority && d->m_weaver.queueLength() == 0)) { | 905 | || (d->m_neededPriority == BackgroundParser::BestPriority && d->m_weaver.queueLength() == 0)) { | ||
815 | if (d->m_progressTimer.isActive()) { | 906 | if (d->m_progressTimer.isActive()) { | ||
816 | d->m_progressTimer.stop(); | 907 | d->m_progressTimer.stop(); | ||
817 | } | 908 | } | ||
909 | if (d->m_totalTimer.isValid()) { | ||||
910 | qreal elapsed = d->m_totalTimer.elapsed() / 1000.0; | ||||
911 | d->m_totalTimer.invalidate(); | ||||
912 | if (d->m_totalJobs > 0 && qEnvironmentVariableIsSet("KDEV_BACKGROUNDPARSER_TIMINGS") && elapsed > 0.5) { | ||||
913 | if (d->m_totalJobs > 1) { | ||||
914 | qCInfo(LANGUAGE) << "Parsed" << d->m_totalJobs << "file(s) in" << elapsed << "seconds"; | ||||
915 | } | ||||
916 | timingSum += elapsed / d->m_totalJobs; | ||||
917 | timingCount += 1; | ||||
918 | } | ||||
919 | } | ||||
818 | emit d->m_parser->hideProgress(d->m_parser); | 920 | emit d->m_parser->hideProgress(d->m_parser); | ||
819 | } | 921 | } | ||
820 | } | 922 | } | ||
821 | 923 | | |||
822 | ParseJob* BackgroundParser::parseJobForDocument(const IndexedString& document) const | 924 | ParseJob* BackgroundParser::parseJobForDocument(const IndexedString& document) const | ||
823 | { | 925 | { | ||
824 | Q_D(const BackgroundParser); | 926 | Q_D(const BackgroundParser); | ||
825 | 927 | | |||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Line(s) | 1021 | if (document->textDocument()) { | |||
930 | QMutexLocker l2(&d->m_managedMutex); | 1032 | QMutexLocker l2(&d->m_managedMutex); | ||
931 | auto urlIt = d->m_managed.find(url); | 1033 | auto urlIt = d->m_managed.find(url); | ||
932 | Q_ASSERT(urlIt != d->m_managed.end()); | 1034 | Q_ASSERT(urlIt != d->m_managed.end()); | ||
933 | 1035 | | |||
934 | qCDebug(LANGUAGE) << "removing" << url.str() << "from background parser"; | 1036 | qCDebug(LANGUAGE) << "removing" << url.str() << "from background parser"; | ||
935 | delete *urlIt; | 1037 | delete *urlIt; | ||
936 | d->m_managedTextDocumentUrls.erase(documentUrlIt); | 1038 | d->m_managedTextDocumentUrls.erase(documentUrlIt); | ||
937 | d->m_managed.erase(urlIt); | 1039 | d->m_managed.erase(urlIt); | ||
1040 | if (d->m_bgControlledJobProxy) { | ||||
1041 | QMetaObject::invokeMethod(d->m_bgControlledJobProxy, "unregisterUrl", | ||||
1042 | Qt::QueuedConnection, Q_ARG(const KDevelop::IndexedString, url)); | ||||
1043 | } | ||||
1044 | if (d->m_controllerJobs.contains(url)) { | ||||
1045 | d->m_controllerJobs.remove(url); | ||||
1046 | } | ||||
938 | } | 1047 | } | ||
939 | } | 1048 | } | ||
940 | 1049 | | |||
941 | void BackgroundParser::documentLoaded(IDocument* document) | 1050 | void BackgroundParser::documentLoaded(IDocument* document) | ||
942 | { | 1051 | { | ||
943 | Q_D(BackgroundParser); | 1052 | Q_D(BackgroundParser); | ||
944 | 1053 | | |||
945 | QMutexLocker l(&d->m_mutex); | 1054 | QMutexLocker l(&d->m_mutex); | ||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Line(s) | |||||
1008 | } | 1117 | } | ||
1009 | 1118 | | |||
1010 | void BackgroundParser::updateProgressBar() | 1119 | void BackgroundParser::updateProgressBar() | ||
1011 | { | 1120 | { | ||
1012 | Q_D(BackgroundParser); | 1121 | Q_D(BackgroundParser); | ||
1013 | 1122 | | |||
1014 | emit showProgress(this, 0, d->m_progressMax, d->m_progressDone); | 1123 | emit showProgress(this, 0, d->m_progressMax, d->m_progressDone); | ||
1015 | } | 1124 | } | ||
1125 | | ||||
1126 | BGParserControllerProxy::BGParserControllerProxy(BackgroundParserPrivate *proxy) | ||||
1127 | : KJob() | ||||
1128 | , m_proxied(proxy) | ||||
1129 | { | ||||
1130 | setCapabilities(KJob::Killable); | ||||
1131 | setObjectName(QStringLiteral("Background parser jobs")); | ||||
1132 | } | ||||
1133 | | ||||
1134 | BGParserControllerProxy::~BGParserControllerProxy() | ||||
1135 | { | ||||
1136 | if (m_proxied) { | ||||
1137 | done(); | ||||
1138 | } | ||||
1139 | } | ||||
1140 | | ||||
1141 | void BGParserControllerProxy::registerUrl(const IndexedString &url) | ||||
1142 | { | ||||
1143 | if (!m_urls.contains(url)) { | ||||
1144 | m_urls.insert(url); | ||||
1145 | ICore::self()->runController()->unregisterJob(this); | ||||
1146 | if (m_urls.count() == 1 ) { | ||||
1147 | setObjectName(QStringLiteral("background parser job for") + m_urls.values().at(0).str()); | ||||
1148 | } else { | ||||
1149 | setObjectName(QStringLiteral("%1 background parser jobs").arg(m_urls.count())); | ||||
1150 | } | ||||
1151 | ICore::self()->runController()->registerJob(this); | ||||
1152 | } | ||||
1153 | } | ||||
1154 | | ||||
1155 | void BGParserControllerProxy::unregisterUrl(const IndexedString &url) | ||||
1156 | { | ||||
1157 | if (m_urls.contains(url)) { | ||||
1158 | m_urls.remove(url); | ||||
1159 | } | ||||
1160 | if (m_urls.isEmpty()) { | ||||
1161 | done(); | ||||
1162 | deleteLater(); | ||||
1163 | qCDebug(LANGUAGE) << Q_FUNC_INFO << "last document processed, done"; | ||||
1164 | } else { | ||||
1165 | ICore::self()->runController()->unregisterJob(this); | ||||
1166 | if (m_urls.count() == 1 ) { | ||||
1167 | setObjectName(QStringLiteral("background parser job for") + m_urls.values().at(0).str()); | ||||
1168 | } else { | ||||
1169 | setObjectName(QStringLiteral("%1 background parser jobs").arg(m_urls.count())); | ||||
1170 | } | ||||
1171 | ICore::self()->runController()->registerJob(this); | ||||
1172 | } | ||||
1173 | } | ||||
1174 | | ||||
1175 | bool BGParserControllerProxy::isUrlRegistered(const IndexedString &url) | ||||
1176 | { | ||||
1177 | return m_urls.contains(url); | ||||
1178 | } | ||||
1179 | | ||||
1180 | // we don't run anything ourselves | ||||
1181 | void BGParserControllerProxy::start() | ||||
1182 | {} | ||||
1183 | | ||||
1184 | bool BGParserControllerProxy::doKill() | ||||
1185 | { | ||||
1186 | if (beingKilled) { | ||||
1187 | return false; | ||||
1188 | } | ||||
1189 | if (m_proxied) { | ||||
1190 | beingKilled = true; | ||||
1191 | bool needsResume = false; | ||||
1192 | if (!m_urls.isEmpty()) { | ||||
1193 | if (!m_proxied->isSuspended()) { | ||||
1194 | QEventLoop loop; | ||||
1195 | connect(&m_proxied->m_weaver, &ThreadWeaver::Queue::suspended, &loop, &QEventLoop::quit, Qt::QueuedConnection); | ||||
1196 | m_proxied->suspend(); | ||||
1197 | // wait for the weaver to be suspended so we can't cause race conditions | ||||
1198 | loop.exec(); | ||||
1199 | needsResume = true; | ||||
1200 | } | ||||
1201 | QMutexLocker lock(&m_proxied->m_mutex); | ||||
1202 | for (const auto url : m_urls) { | ||||
1203 | auto decorator = m_proxied->m_parseJobs.value(url); | ||||
1204 | ParseJob *parseJob = decorator ? dynamic_cast<ParseJob*>(decorator->job()) : nullptr; | ||||
1205 | if (parseJob) { | ||||
1206 | m_proxied->m_parseJobs.remove(parseJob->document()); | ||||
1207 | m_proxied->m_jobProgress.remove(parseJob); | ||||
1208 | } | ||||
1209 | if (decorator) { | ||||
1210 | m_proxied->m_weaver.dequeue(ThreadWeaver::JobPointer(decorator)); | ||||
1211 | } | ||||
1212 | m_proxied->m_maxParseJobs -= 1; | ||||
1213 | const auto parsePlanIt = m_proxied->m_documents.find(url); | ||||
1214 | if (parsePlanIt != m_proxied->m_documents.end()) { | ||||
1215 | // Remove all mentions of this document. | ||||
1216 | for (const auto& target : qAsConst(parsePlanIt->targets)) { | ||||
1217 | m_proxied->m_documentsForPriority[target.priority].remove(url); | ||||
1218 | } | ||||
1219 | m_proxied->m_documents.erase(parsePlanIt); | ||||
1220 | } | ||||
1221 | QMutexLocker lock2(&m_proxied->m_managedMutex); | ||||
1222 | if (m_proxied->m_managed.contains(url)) { | ||||
1223 | const auto tracker = m_proxied->m_managed[url]; | ||||
1224 | m_proxied->m_managed.remove(url); | ||||
1225 | if (tracker) { | ||||
1226 | const auto doc = tracker->document(); | ||||
1227 | if (m_proxied->m_managedTextDocumentUrls.contains(doc)) { | ||||
1228 | m_proxied->m_managedTextDocumentUrls.remove(doc); | ||||
1229 | } | ||||
1230 | } | ||||
1231 | } | ||||
1232 | } | ||||
1233 | m_urls.clear(); | ||||
1234 | } | ||||
1235 | m_proxied->m_parser->updateProgressData(); | ||||
1236 | if (needsResume) { | ||||
1237 | m_proxied->resume(); | ||||
1238 | } | ||||
1239 | done(); | ||||
1240 | } | ||||
1241 | return true; | ||||
1242 | } | ||||
1243 | | ||||
1244 | void BGParserControllerProxy::done() | ||||
1245 | { | ||||
1246 | if (m_proxied) { | ||||
1247 | ICore::self()->runController()->unregisterJob(this); | ||||
1248 | m_proxied->m_bgControlledJobProxy = nullptr; | ||||
1249 | m_proxied = nullptr; | ||||
1250 | } | ||||
1251 | } | ||||
1252 | | ||||
1253 | #include "backgroundparser.moc" |