libplasma
runnermanager.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "runnermanager.h"
00023
00024 #include <KServiceTypeTrader>
00025 #include <KPluginInfo>
00026 #include <KDebug>
00027
00028 #include <Solid/Device>
00029 #include <Solid/DeviceInterface>
00030
00031 #include <threadweaver/DebuggingAids.h>
00032 #include <ThreadWeaver/Thread>
00033 #include <ThreadWeaver/Job>
00034 #include <ThreadWeaver/QueuePolicy>
00035 #include <ThreadWeaver/Weaver>
00036 #include <QMutex>
00037 #include <QTimer>
00038 #include <QCoreApplication>
00039
00040 #include "querymatch.h"
00041
00042 using ThreadWeaver::Weaver;
00043 using ThreadWeaver::Job;
00044
00045
00046 namespace Plasma
00047 {
00048
00049
00050
00051
00052
00053
00054
00055 class RunnerRestrictionPolicy : public ThreadWeaver::QueuePolicy
00056 {
00057 public:
00058 ~RunnerRestrictionPolicy();
00059
00060 static RunnerRestrictionPolicy& instance();
00061
00062 void setCap(int cap)
00063 {
00064 m_cap = cap;
00065 }
00066 int cap() const
00067 {
00068 return m_cap;
00069 }
00070
00071 bool canRun(Job* job);
00072 void free(Job* job);
00073 void release(Job* job);
00074 void destructed(Job* job);
00075 private:
00076 RunnerRestrictionPolicy();
00077
00078
00079 int m_count;
00080 int m_cap;
00081 QMutex m_mutex;
00082 };
00083
00084 RunnerRestrictionPolicy::RunnerRestrictionPolicy()
00085 : QueuePolicy(),
00086 m_count(0),
00087 m_cap(2)
00088 {
00089 }
00090
00091 RunnerRestrictionPolicy::~RunnerRestrictionPolicy()
00092 {
00093 }
00094
00095 RunnerRestrictionPolicy& RunnerRestrictionPolicy::instance()
00096 {
00097 static RunnerRestrictionPolicy policy;
00098 return policy;
00099 }
00100
00101 bool RunnerRestrictionPolicy::canRun(Job* job)
00102 {
00103 Q_UNUSED(job)
00104 QMutexLocker l(&m_mutex);
00105
00106 if (m_count > m_cap) {
00107
00108 return false;
00109 } else {
00110
00111 ++m_count;
00112 return true;
00113 }
00114 }
00115
00116 void RunnerRestrictionPolicy::free(Job* job)
00117 {
00118 Q_UNUSED(job)
00119 QMutexLocker l(&m_mutex);
00120
00121 --m_count;
00122
00123
00124
00125 }
00126
00127 void RunnerRestrictionPolicy::release(Job* job)
00128 {
00129 free(job);
00130 }
00131
00132 void RunnerRestrictionPolicy::destructed(Job* job)
00133 {
00134 Q_UNUSED(job)
00135 }
00136
00137
00138
00139
00140
00141
00142 class FindMatchesJob : public Job
00143 {
00144 public:
00145 FindMatchesJob(Plasma::AbstractRunner* runner, Plasma::RunnerContext* context, QObject* parent = 0);
00146
00147 int priority() const;
00148 Plasma::AbstractRunner* runner() const;
00149
00150 protected:
00151 void run();
00152 private:
00153 Plasma::RunnerContext* m_context;
00154 Plasma::AbstractRunner* m_runner;
00155 };
00156
00157 FindMatchesJob::FindMatchesJob(Plasma::AbstractRunner* runner,
00158 Plasma::RunnerContext* context, QObject* parent)
00159 : ThreadWeaver::Job(parent),
00160 m_context(context),
00161 m_runner(runner)
00162 {
00163 if (runner->speed() == Plasma::AbstractRunner::SlowSpeed) {
00164 assignQueuePolicy(&RunnerRestrictionPolicy::instance());
00165 }
00166 }
00167
00168 void FindMatchesJob::run()
00169 {
00170
00171 m_runner->performMatch(*m_context);
00172 }
00173
00174 int FindMatchesJob::priority() const
00175 {
00176 return m_runner->priority();
00177 }
00178
00179 Plasma::AbstractRunner* FindMatchesJob::runner() const
00180 {
00181 return m_runner;
00182 }
00183
00184
00185
00186
00187
00188 class RunnerManagerPrivate
00189 {
00190 public:
00191
00192 RunnerManagerPrivate(RunnerManager *parent)
00193 : q(parent),
00194 deferredRun(0)
00195 {
00196 matchChangeTimer.setSingleShot(true);
00197 QObject::connect(&matchChangeTimer, SIGNAL(timeout()), q, SLOT(matchesChanged()));
00198 QObject::connect(&context, SIGNAL(matchesChanged()), q, SLOT(scheduleMatchesChanged()));
00199 }
00200
00201 void scheduleMatchesChanged()
00202 {
00203 matchChangeTimer.start(100);
00204 }
00205
00206 void matchesChanged()
00207 {
00208 emit q->matchesChanged(context.matches());
00209 }
00210
00211 void loadConfiguration(KConfigGroup& conf)
00212 {
00213 config = conf;
00214
00215
00216 const int numProcs = qMax(Solid::Device::listFromType(Solid::DeviceInterface::Processor).count(), 1);
00217
00218 const int maxThreads = config.readEntry("maxThreads",16);
00219 const int numThreads = qMin(maxThreads, 2 + ((numProcs - 1) * 2));
00220
00221 Weaver::instance()->setMaximumNumberOfThreads(numThreads);
00222
00223
00224
00225
00226
00227
00228 }
00229
00230 void loadRunners()
00231 {
00232 KService::List offers = KServiceTypeTrader::self()->query("Plasma/Runner");
00233
00234 bool loadAll = config.readEntry("loadAll", false);
00235 KConfigGroup conf(KGlobal::config(), "Plugins");
00236
00237 foreach (const KService::Ptr &service, offers) {
00238
00239 KPluginInfo description(service);
00240 QString runnerName = description.pluginName();
00241 description.load(conf);
00242
00243 bool loaded = runners.contains(runnerName);
00244 bool selected = loadAll || description.isPluginEnabled();
00245
00246 if (selected) {
00247 if (!loaded) {
00248 QString api = service->property("X-Plasma-API").toString();
00249 QString error;
00250 AbstractRunner* runner = 0;
00251
00252 if (api.isEmpty()) {
00253 QVariantList args;
00254 args << service->storageId();
00255 if (Plasma::isPluginVersionCompatible(KPluginLoader(*service).pluginVersion())) {
00256 runner = service->createInstance<AbstractRunner>(q, args, &error);
00257 }
00258 } else {
00259
00260 runner = new AbstractRunner(q, service->storageId());
00261 }
00262
00263 if (runner) {
00264 kDebug() << "loading runner:" << service->name();
00265 runners.insert(runnerName, runner);
00266 } else {
00267 kDebug() << "failed to load runner:" << service->name() << ". error reported:" << error;
00268 }
00269 }
00270 } else if (loaded) {
00271
00272 AbstractRunner* runner = runners.take(runnerName);
00273 kDebug() << "Removing runner: " << runnerName;
00274 delete runner;
00275 }
00276 }
00277
00278
00279 }
00280
00281 void jobDone(ThreadWeaver::Job* job)
00282 {
00283 FindMatchesJob *runJob = static_cast<FindMatchesJob*>(job);
00284 if (deferredRun.isEnabled() && runJob->runner() == deferredRun.runner()) {
00285
00286 deferredRun.run(context);
00287 deferredRun = QueryMatch(0);
00288 }
00289 searchJobs.removeAll(runJob);
00290 delete runJob;
00291 }
00292
00293 RunnerManager *q;
00294 QueryMatch deferredRun;
00295 RunnerContext context;
00296 QTimer matchChangeTimer;
00297 QHash<QString, AbstractRunner*> runners;
00298 QList<FindMatchesJob*> searchJobs;
00299
00300 bool loadAll;
00301 KConfigGroup config;
00302 };
00303
00304
00305
00306
00307
00308
00309
00310 RunnerManager::RunnerManager(QObject *parent)
00311 : QObject(parent),
00312 d(new RunnerManagerPrivate(this))
00313 {
00314 KConfigGroup config(KGlobal::config(), "PlasmaRunnerManager");
00315 d->loadConfiguration(config);
00316
00317 }
00318
00319
00320 RunnerManager::RunnerManager(KConfigGroup& config, QObject *parent)
00321 : QObject(parent),
00322 d(new RunnerManagerPrivate(this))
00323 {
00324 d->loadConfiguration(config);
00325
00326 }
00327
00328 RunnerManager::~RunnerManager()
00329 {
00330 delete d;
00331 }
00332
00333 void RunnerManager::reloadConfiguration()
00334 {
00335 d->loadConfiguration(d->config);
00336 d->loadRunners();
00337 }
00338
00339 AbstractRunner* RunnerManager::runner(const QString &name) const
00340 {
00341 if (d->runners.isEmpty()) {
00342 d->loadRunners();
00343 }
00344
00345 return d->runners.value(name);
00346 }
00347
00348 RunnerContext* RunnerManager::searchContext() const
00349 {
00350 return &d->context;
00351 }
00352
00353
00354 QList<QueryMatch> RunnerManager::matches() const
00355 {
00356 return d->context.matches();
00357 }
00358
00359 void RunnerManager::run(const QString &id)
00360 {
00361 run(d->context.match(id));
00362 }
00363
00364 void RunnerManager::run(const QueryMatch &match)
00365 {
00366 if (!match.isEnabled()) {
00367 return;
00368 }
00369
00370
00371 AbstractRunner *runner = match.runner();
00372
00373 foreach (FindMatchesJob *job, d->searchJobs) {
00374 if (job->runner() == runner && !job->isFinished()) {
00375
00376 d->deferredRun = match;
00377 return;
00378 }
00379 }
00380
00381 match.run(d->context);
00382
00383 if (d->deferredRun.isValid()) {
00384 d->deferredRun = QueryMatch(0);
00385 }
00386 }
00387
00388 void RunnerManager::launchQuery(const QString &term)
00389 {
00390 launchQuery(term, QString());
00391 }
00392
00393 void RunnerManager::launchQuery(const QString &term, const QString &runnerName)
00394 {
00395 if (d->runners.isEmpty()) {
00396 d->loadRunners();
00397 }
00398
00399 if (term.isEmpty()) {
00400 reset();
00401 return;
00402 }
00403
00404 if (d->context.query() == term) {
00405
00406 return;
00407 }
00408
00409 reset();
00410
00411 d->context.setQuery(term);
00412
00413 AbstractRunner::List runable;
00414
00415
00416 if (!runnerName.isEmpty()) {
00417 runable.append(runner(runnerName));
00418 } else {
00419 runable = d->runners.values();
00420 }
00421
00422 foreach (Plasma::AbstractRunner* r, runable) {
00423 if ((r->ignoredTypes() & d->context.type()) == 0) {
00424
00425 FindMatchesJob *job = new FindMatchesJob(r, &d->context, this);
00426 connect(job, SIGNAL(done(ThreadWeaver::Job*)), this, SLOT(jobDone(ThreadWeaver::Job*)));
00427 Weaver::instance()->enqueue(job);
00428 d->searchJobs.append(job);
00429 }
00430 }
00431 }
00432
00433 bool RunnerManager::execQuery(const QString &term)
00434 {
00435 return execQuery(term, QString());
00436 }
00437
00438 bool RunnerManager::execQuery(const QString &term, const QString &runnerName)
00439 {
00440 if (d->runners.isEmpty()) {
00441 d->loadRunners();
00442 }
00443
00444 if (term.isEmpty()) {
00445 reset();
00446 return false;
00447 }
00448
00449 if (d->context.query() == term) {
00450
00451 emit matchesChanged(d->context.matches());
00452 return false;
00453 }
00454
00455 reset();
00456
00457 d->context.setQuery(term);
00458 AbstractRunner *r = runner(runnerName);
00459
00460 if (!r) {
00461
00462 return false;
00463 }
00464
00465 if ((r->ignoredTypes() & d->context.type()) != 0) {
00466
00467 return false;
00468 }
00469
00470 r->performMatch(d->context);
00471
00472 emit matchesChanged(d->context.matches());
00473 return true;
00474 }
00475
00476 QString RunnerManager::query() const
00477 {
00478 return d->context.query();
00479 }
00480
00481 void RunnerManager::reset()
00482 {
00483
00484 if (Weaver::instance()->isIdle()) {
00485 qDeleteAll(d->searchJobs);
00486 d->searchJobs.clear();
00487 } else {
00488 Weaver::instance()->dequeue();
00489 }
00490
00491 if (d->deferredRun.isEnabled()) {
00492
00493 d->deferredRun.run(d->context);
00494 d->deferredRun = QueryMatch(0);
00495 }
00496
00497 d->context.reset();
00498 }
00499
00500 }
00501
00502 #include "runnermanager.moc"