00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "scheduler.h"
00021
00022 #include "sessiondata.h"
00023 #include "slaveconfig.h"
00024 #include "authinfo.h"
00025 #include "slave.h"
00026 #include "connection.h"
00027 #include "job_p.h"
00028
00029 #include <kdebug.h>
00030 #include <kglobal.h>
00031 #include <kprotocolmanager.h>
00032 #include <kprotocolinfo.h>
00033 #include <assert.h>
00034 #include <kdesu/client.h>
00035
00036 #include <QtCore/QHash>
00037 #include <QtGui/QWidget>
00038 #include <QtDBus/QtDBus>
00039
00040
00041
00042 #define MAX_SLAVE_IDLE (3*60)
00043
00044 using namespace KIO;
00045
00046 #ifndef KDE_USE_FINAL // already defined in job.cpp
00047 static inline Slave *jobSlave(SimpleJob *job)
00048 {
00049 return SimpleJobPrivate::get(job)->m_slave;
00050 }
00051 #endif
00052
00053 static inline int jobCommand(SimpleJob *job)
00054 {
00055 return SimpleJobPrivate::get(job)->m_command;
00056 }
00057
00058 static inline void startJob(SimpleJob *job, Slave *slave)
00059 {
00060 SimpleJobPrivate::get(job)->start(slave);
00061 }
00062
00063 typedef QList<Slave *> SlaveList;
00064
00065 class KIO::SchedulerPrivate
00066 {
00067 public:
00068 class JobData;
00069 class ProtocolInfo;
00070 class ProtocolInfoDict : public QHash<QString, ProtocolInfo*>
00071 {
00072 public:
00073 ProtocolInfoDict() { }
00074
00075 ProtocolInfo *get(const QString &protocol);
00076 };
00077
00078 typedef QHash<KIO::SimpleJob*, JobData> ExtraJobData;
00079 typedef QList<SimpleJob *> JobList;
00080 typedef QMap<Slave*, JobList *> CoSlaveMap;
00081
00082 SchedulerPrivate() :
00083 q(new Scheduler),
00084 busy( false ),
00085 slaveOnHold( 0 ),
00086 slaveConfig( SlaveConfig::self() ),
00087 sessionData( new SessionData ),
00088 checkOnHold( true )
00089 {
00090 slaveTimer.setObjectName( "Scheduler::slaveTimer" );
00091 slaveTimer.setSingleShot( true );
00092 q->connect(&slaveTimer, SIGNAL(timeout()), SLOT(startStep()));
00093 coSlaveTimer.setObjectName( "Scheduler::coSlaveTimer" );
00094 coSlaveTimer.setSingleShot( true );
00095 q->connect(&coSlaveTimer, SIGNAL(timeout()), SLOT(slotScheduleCoSlave()));
00096 cleanupTimer.setObjectName( "Scheduler::cleanupTimer" );
00097 cleanupTimer.setSingleShot( true );
00098 q->connect(&cleanupTimer, SIGNAL(timeout()), SLOT(slotCleanIdleSlaves()));
00099 }
00100 ~SchedulerPrivate()
00101 {
00102 delete q; q = 0;
00103 qDeleteAll( protInfoDict );
00104 qDeleteAll( slaveList );
00105 delete sessionData;
00106 }
00107 Scheduler *q;
00108
00109 QTimer slaveTimer;
00110 QTimer coSlaveTimer;
00111 QTimer cleanupTimer;
00112 bool busy;
00113
00114 SlaveList slaveList;
00115 SlaveList idleSlaves;
00116 SlaveList coIdleSlaves;
00117
00118 ProtocolInfoDict protInfoDict;
00119 Slave *slaveOnHold;
00120 KUrl urlOnHold;
00121 JobList newJobs;
00122
00123 CoSlaveMap coSlaves;
00124 ExtraJobData extraJobData;
00125 SlaveConfig *slaveConfig;
00126 SessionData *sessionData;
00127 bool checkOnHold;
00128 QMap<QObject *,WId> m_windowList;
00129
00130 void doJob(SimpleJob *job);
00131 void scheduleJob(SimpleJob *job);
00132 void cancelJob(SimpleJob *job);
00133 void jobFinished(KIO::SimpleJob *job, KIO::Slave *slave);
00134 void scheduleCleanup();
00135 void putSlaveOnHold(KIO::SimpleJob *job, const KUrl &url);
00136 void removeSlaveOnHold();
00137 Slave *getConnectedSlave(const KUrl &url, const KIO::MetaData &metaData );
00138 bool assignJobToSlave(KIO::Slave *slave, KIO::SimpleJob *job);
00139 bool disconnectSlave(KIO::Slave *slave);
00140 void checkSlaveOnHold(bool b);
00141 void publishSlaveOnHold();
00142 void registerWindow(QWidget *wid);
00143
00144 Slave *findIdleSlave(ProtocolInfo *protInfo, SimpleJob *job, bool &exact);
00145 Slave *createSlave(ProtocolInfo *protInfo, SimpleJob *job, const KUrl &url);
00146
00147 void debug_info();
00148
00149 void setupSlave(KIO::Slave *slave, const KUrl &url, const QString &protocol, const QString &proxy , bool newSlave, const KIO::MetaData *config=0);
00150 bool startJobScheduled(ProtocolInfo *protInfo);
00151 bool startJobDirect();
00152
00153 void slotSlaveDied(KIO::Slave *slave);
00154 void slotSlaveStatus(pid_t pid, const QByteArray &protocol,
00155 const QString &host, bool connected);
00156
00157 void slotReparseSlaveConfiguration(const QString &);
00158
00159 void startStep();
00160 void slotCleanIdleSlaves();
00161 void slotSlaveConnected();
00162 void slotSlaveError(int error, const QString &errorMsg);
00163 void slotScheduleCoSlave();
00164 void slotUnregisterWindow(QObject *);
00165 };
00166
00167 class KIO::SchedulerPrivate::ProtocolInfo
00168 {
00169 public:
00170 ProtocolInfo() : maxSlaves(1), skipCount(0)
00171 {
00172 }
00173
00174 QList<SimpleJob *> joblist;
00175 SlaveList activeSlaves;
00176 int maxSlaves;
00177 int skipCount;
00178 QString protocol;
00179 };
00180
00181 KIO::SchedulerPrivate::ProtocolInfo *
00182 KIO::SchedulerPrivate::ProtocolInfoDict::get(const QString &protocol)
00183 {
00184 ProtocolInfo *info = value(protocol, 0);
00185 if (!info)
00186 {
00187 info = new ProtocolInfo;
00188 info->protocol = protocol;
00189 info->maxSlaves = KProtocolInfo::maxSlaves( protocol );
00190
00191 insert(protocol, info);
00192 }
00193 return info;
00194 }
00195
00196 K_GLOBAL_STATIC(SchedulerPrivate, schedulerPrivate)
00197 Scheduler* Scheduler::self()
00198 {
00199 return schedulerPrivate->q;
00200 }
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 class KIO::SchedulerPrivate::JobData
00219 {
00220 public:
00221 JobData() : checkOnHold(false) { }
00222
00223 public:
00224 QString protocol;
00225 QString proxy;
00226 bool checkOnHold;
00227 };
00228
00229
00230 Scheduler::Scheduler()
00231 : QObject(), d(0)
00232 {
00233 setObjectName( "scheduler" );
00234
00235 const QString dbusPath = "/KIO/Scheduler";
00236 const QString dbusInterface = "org.kde.KIO.Scheduler";
00237 QDBusConnection dbus = QDBusConnection::sessionBus();
00238 dbus.registerObject( "/KIO/Scheduler", this, QDBusConnection::ExportScriptableSlots |
00239 QDBusConnection::ExportScriptableSignals );
00240 dbus.connect(QString(), dbusPath, dbusInterface, "reparseSlaveConfiguration",
00241 this, SLOT(slotReparseSlaveConfiguration(QString)));
00242 }
00243
00244 Scheduler::~Scheduler()
00245 {
00246 }
00247
00248 void Scheduler::doJob(SimpleJob *job)
00249 {
00250 schedulerPrivate->doJob(job);
00251 }
00252
00253 void Scheduler::scheduleJob(SimpleJob *job)
00254 {
00255 schedulerPrivate->scheduleJob(job);
00256 }
00257
00258 void Scheduler::cancelJob(SimpleJob *job)
00259 {
00260 schedulerPrivate->cancelJob(job);
00261 }
00262
00263 void Scheduler::jobFinished(KIO::SimpleJob *job, KIO::Slave *slave)
00264 {
00265 schedulerPrivate->jobFinished(job, slave);
00266 }
00267
00268 void Scheduler::putSlaveOnHold(KIO::SimpleJob *job, const KUrl &url)
00269 {
00270 schedulerPrivate->putSlaveOnHold(job, url);
00271 }
00272
00273 void Scheduler::removeSlaveOnHold()
00274 {
00275 schedulerPrivate->removeSlaveOnHold();
00276 }
00277
00278 void Scheduler::publishSlaveOnHold()
00279 {
00280 schedulerPrivate->publishSlaveOnHold();
00281 }
00282
00283 KIO::Slave *Scheduler::getConnectedSlave(const KUrl &url,
00284 const KIO::MetaData &config )
00285 {
00286 return schedulerPrivate->getConnectedSlave(url, config);
00287 }
00288
00289 bool Scheduler::assignJobToSlave(KIO::Slave *slave, KIO::SimpleJob *job)
00290 {
00291 return schedulerPrivate->assignJobToSlave(slave, job);
00292 }
00293
00294 bool Scheduler::disconnectSlave(KIO::Slave *slave)
00295 {
00296 return schedulerPrivate->disconnectSlave(slave);
00297 }
00298
00299 void Scheduler::registerWindow(QWidget *wid)
00300 {
00301 schedulerPrivate->registerWindow(wid);
00302 }
00303
00304 void Scheduler::unregisterWindow(QObject *wid)
00305 {
00306 schedulerPrivate->slotUnregisterWindow(wid);
00307 }
00308
00309 bool Scheduler::connect( const char *signal, const QObject *receiver,
00310 const char *member)
00311 {
00312 return QObject::connect(self(), signal, receiver, member);
00313 }
00314
00315 bool Scheduler::connect( const QObject* sender, const char* signal,
00316 const QObject* receiver, const char* member )
00317 {
00318 return QObject::connect(sender, signal, receiver, member);
00319 }
00320
00321 bool Scheduler::disconnect( const QObject* sender, const char* signal,
00322 const QObject* receiver, const char* member )
00323 {
00324 return QObject::disconnect(sender, signal, receiver, member);
00325 }
00326
00327 bool Scheduler::connect( const QObject *sender, const char *signal,
00328 const char *member )
00329 {
00330 return QObject::connect(sender, signal, member);
00331 }
00332
00333 void Scheduler::checkSlaveOnHold(bool b)
00334 {
00335 schedulerPrivate->checkSlaveOnHold(b);
00336 }
00337
00338 void Scheduler::emitReparseSlaveConfiguration()
00339 {
00340 self()->reparseSlaveConfiguration( QString() );
00341 }
00342
00343 void
00344 SchedulerPrivate::debug_info()
00345 {
00346 }
00347
00348 void SchedulerPrivate::slotReparseSlaveConfiguration(const QString &proto)
00349 {
00350 kDebug( 7006 ) << "reparseSlaveConfiguration( " << proto << " )";
00351 KProtocolManager::reparseConfiguration();
00352 slaveConfig->reset();
00353 sessionData->reset();
00354 NetRC::self()->reload();
00355
00356 foreach( Slave *slave, slaveList )
00357 {
00358 if ( slave->slaveProtocol() == proto || proto.isEmpty() )
00359 {
00360 slave->send( CMD_REPARSECONFIGURATION );
00361 slave->resetHost();
00362 }
00363 }
00364 }
00365
00366 void SchedulerPrivate::doJob(SimpleJob *job) {
00367 JobData jobData;
00368 jobData.protocol = KProtocolManager::slaveProtocol(job->url(), jobData.proxy);
00369
00370 if (jobCommand(job) == CMD_GET)
00371 {
00372 jobData.checkOnHold = checkOnHold;
00373 checkOnHold = false;
00374 }
00375 extraJobData.insert(job, jobData);
00376 newJobs.append(job);
00377 slaveTimer.start(0);
00378 #ifndef NDEBUG
00379 if (newJobs.count() > 150)
00380 kDebug() << "WARNING - KIO::Scheduler got more than 150 jobs! This shows a misuse in your app (yes, a job is a QObject).";
00381 #endif
00382 }
00383
00384 void SchedulerPrivate::scheduleJob(SimpleJob *job) {
00385 newJobs.removeOne(job);
00386 const JobData& jobData = extraJobData.value(job);
00387
00388 QString protocol = jobData.protocol;
00389
00390 ProtocolInfo *protInfo = protInfoDict.get(protocol);
00391 protInfo->joblist.append(job);
00392
00393 slaveTimer.start(0);
00394 }
00395
00396 void SchedulerPrivate::cancelJob(SimpleJob *job) {
00397
00398 Slave *slave = jobSlave(job);
00399 if ( !slave )
00400 {
00401
00402 JobData jobData = extraJobData.value(job);
00403 newJobs.removeAll(job);
00404 ProtocolInfo *protInfo = protInfoDict.get(jobData.protocol);
00405 protInfo->joblist.removeAll(job);
00406
00407
00408 foreach( Slave* coSlave, slaveList )
00409 {
00410 JobList *list = coSlaves.value(coSlave);
00411 if (list && list->removeAll(job)) {
00412
00413
00414 slave = coSlave;
00415 break;
00416 }
00417 }
00418 if (!slave)
00419 {
00420 extraJobData.remove(job);
00421 return;
00422 }
00423 }
00424
00425 slave->kill();
00426 jobFinished( job, slave );
00427 slotSlaveDied(slave);
00428 }
00429
00430 void SchedulerPrivate::startStep()
00431 {
00432 while (newJobs.count()) {
00433 (void) startJobDirect();
00434 }
00435
00436 QHashIterator<QString, ProtocolInfo*> it(protInfoDict);
00437 while(it.hasNext()) {
00438 it.next();
00439 if (startJobScheduled(it.value())) return;
00440 }
00441 }
00442
00443 void SchedulerPrivate::setupSlave(KIO::Slave *slave, const KUrl &url, const QString &protocol, const QString &proxy , bool newSlave, const KIO::MetaData *config)
00444 {
00445 QString host = url.host();
00446 int port = url.port();
00447 if ( port == -1 )
00448 port = 0;
00449 QString user = url.user();
00450 QString passwd = url.pass();
00451
00452 if ((newSlave) ||
00453 (slave->host() != host) ||
00454 (slave->port() != port) ||
00455 (slave->user() != user) ||
00456 (slave->passwd() != passwd))
00457 {
00458 slaveConfig = SlaveConfig::self();
00459
00460 MetaData configData = slaveConfig->configData(protocol, host);
00461 sessionData->configDataFor( configData, protocol, host );
00462
00463 configData["UseProxy"] = proxy;
00464
00465 QString autoLogin = configData["EnableAutoLogin"].toLower();
00466 if ( autoLogin == "true" )
00467 {
00468 NetRC::AutoLogin l;
00469 l.login = user;
00470 bool usern = (protocol == "ftp");
00471 if ( NetRC::self()->lookup( url, l, usern) )
00472 {
00473 configData["autoLoginUser"] = l.login;
00474 configData["autoLoginPass"] = l.password;
00475 if ( usern )
00476 {
00477 QString macdef;
00478 QMap<QString, QStringList>::ConstIterator it = l.macdef.constBegin();
00479 for ( ; it != l.macdef.constEnd(); ++it )
00480 macdef += it.key() + '\\' + it.value().join( "\\" ) + '\n';
00481 configData["autoLoginMacro"] = macdef;
00482 }
00483 }
00484 }
00485 if (config)
00486 configData += *config;
00487 slave->setConfig(configData);
00488 slave->setProtocol(url.protocol());
00489 slave->setHost(host, port, user, passwd);
00490 }
00491 }
00492
00493 bool SchedulerPrivate::startJobScheduled(ProtocolInfo *protInfo)
00494 {
00495 if (protInfo->joblist.isEmpty())
00496 return false;
00497
00498
00499 debug_info();
00500 bool newSlave = false;
00501
00502 SimpleJob *job = 0;
00503 Slave *slave = 0;
00504
00505 if (protInfo->skipCount > 2)
00506 {
00507 bool dummy;
00508
00509
00510 protInfo->skipCount = 0;
00511 job = protInfo->joblist.at(0);
00512 slave = findIdleSlave(protInfo, job, dummy );
00513 }
00514 else
00515 {
00516 bool exact=false;
00517 SimpleJob *firstJob = 0;
00518 Slave *firstSlave = 0;
00519 for(int i = 0; (i < protInfo->joblist.count()) && (i < 10); i++)
00520 {
00521 job = protInfo->joblist.at(i);
00522 slave = findIdleSlave(protInfo, job, exact);
00523 if (!firstSlave)
00524 {
00525 firstJob = job;
00526 firstSlave = slave;
00527 }
00528 if (!slave) break;
00529 if (exact) break;
00530 }
00531
00532 if (!exact)
00533 {
00534 slave = firstSlave;
00535 job = firstJob;
00536 }
00537 if (job == firstJob)
00538 protInfo->skipCount = 0;
00539 else
00540 protInfo->skipCount++;
00541 }
00542
00543 if (!slave)
00544 {
00545 if ( protInfo->maxSlaves > static_cast<int>(protInfo->activeSlaves.count()) )
00546 {
00547 newSlave = true;
00548 slave = createSlave(protInfo, job, job->url());
00549 if (!slave)
00550 slaveTimer.start(0);
00551 }
00552 }
00553
00554 if (!slave)
00555 {
00556
00557
00558 return false;
00559 }
00560
00561 protInfo->activeSlaves.append(slave);
00562 idleSlaves.removeAll(slave);
00563 protInfo->joblist.removeOne(job);
00564
00565
00566
00567 SchedulerPrivate::JobData jobData = extraJobData.value(job);
00568 setupSlave(slave, job->url(), jobData.protocol, jobData.proxy, newSlave);
00569 startJob(job, slave);
00570
00571 slaveTimer.start(0);
00572 return true;
00573 }
00574
00575 bool SchedulerPrivate::startJobDirect()
00576 {
00577 debug_info();
00578 SimpleJob *job = newJobs.takeFirst();
00579 SchedulerPrivate::JobData jobData = extraJobData.value(job);
00580
00581 QString protocol = jobData.protocol;
00582 ProtocolInfo *protInfo = protInfoDict.get(protocol);
00583
00584 bool newSlave = false;
00585 bool dummy;
00586
00587
00588 Slave *slave = findIdleSlave(protInfo, job, dummy);
00589
00590 if (!slave)
00591 {
00592 newSlave = true;
00593 slave = createSlave(protInfo, job, job->url());
00594 }
00595
00596 if (!slave)
00597 return false;
00598
00599 idleSlaves.removeAll(slave);
00600
00601
00602 setupSlave(slave, job->url(), protocol, jobData.proxy, newSlave);
00603 startJob(job, slave);
00604 return true;
00605 }
00606
00607 static Slave *searchIdleList(SlaveList &idleSlaves, const KUrl &url, const QString &protocol, bool &exact)
00608 {
00609 QString host = url.host();
00610 int port = url.port();
00611 if ( port == -1 )
00612 port = 0;
00613 QString user = url.user();
00614 exact = true;
00615
00616 foreach( Slave *slave, idleSlaves )
00617 {
00618 if ((protocol == slave->slaveProtocol()) &&
00619 (host == slave->host()) &&
00620 (port == slave->port()) &&
00621 (user == slave->user()))
00622 return slave;
00623 }
00624
00625 exact = false;
00626
00627
00628 foreach( Slave *slave, idleSlaves )
00629 {
00630 if (protocol == slave->slaveProtocol())
00631 return slave;
00632 }
00633 return 0;
00634 }
00635
00636 Slave *SchedulerPrivate::findIdleSlave(ProtocolInfo *, SimpleJob *job, bool &exact)
00637 {
00638 Slave *slave = 0;
00639 JobData jobData = extraJobData.value(job);
00640
00641 if (jobData.checkOnHold)
00642 {
00643 slave = Slave::holdSlave(jobData.protocol, job->url());
00644 if (slave)
00645 return slave;
00646 }
00647 if (slaveOnHold)
00648 {
00649
00650 bool bCanReuse = (jobCommand(job) == CMD_GET);
00651 KIO::TransferJob * tJob = qobject_cast<KIO::TransferJob *>(job);
00652 if ( tJob )
00653 {
00654 bCanReuse = (jobCommand(job) == CMD_GET || jobCommand(job) == CMD_SPECIAL);
00655 if ( bCanReuse )
00656 {
00657 KIO::MetaData outgoing = tJob->outgoingMetaData();
00658 QString resume = (!outgoing.contains("resume")) ? QString() : outgoing["resume"];
00659 kDebug(7006) << "Resume metadata is" << resume;
00660 bCanReuse = (resume.isEmpty() || resume == "0");
00661 }
00662 }
00663
00664 if (bCanReuse)
00665 {
00666 if (job->url() == urlOnHold)
00667 {
00668 kDebug(7006) << "HOLD: Reusing held slave for" << urlOnHold;
00669 slave = slaveOnHold;
00670 }
00671 else
00672 {
00673 kDebug(7006) << "HOLD: Discarding held slave (" << urlOnHold << ")";
00674 slaveOnHold->kill();
00675 }
00676 slaveOnHold = 0;
00677 urlOnHold = KUrl();
00678 }
00679 if (slave)
00680 return slave;
00681 }
00682
00683 return searchIdleList(idleSlaves, job->url(), jobData.protocol, exact);
00684 }
00685
00686 Slave *SchedulerPrivate::createSlave(ProtocolInfo *protInfo, SimpleJob *job, const KUrl &url)
00687 {
00688 int error;
00689 QString errortext;
00690 Slave *slave = Slave::createSlave(protInfo->protocol, url, error, errortext);
00691 if (slave)
00692 {
00693 slaveList.append(slave);
00694 idleSlaves.append(slave);
00695 q->connect(slave, SIGNAL(slaveDied(KIO::Slave *)),
00696 SLOT(slotSlaveDied(KIO::Slave *)));
00697 q->connect(slave, SIGNAL(slaveStatus(pid_t,const QByteArray&,const QString &, bool)),
00698 SLOT(slotSlaveStatus(pid_t,const QByteArray&, const QString &, bool)));
00699 }
00700 else
00701 {
00702 kError() << "couldn't create slave:" << errortext;
00703 if (job)
00704 {
00705 protInfo->joblist.removeAll(job);
00706 extraJobData.remove(job);
00707 job->slotError( error, errortext );
00708 }
00709 }
00710 return slave;
00711 }
00712
00713 void SchedulerPrivate::slotSlaveStatus(pid_t, const QByteArray&, const QString &, bool)
00714 {
00715 }
00716
00717 void SchedulerPrivate::jobFinished(SimpleJob *job, Slave *slave)
00718 {
00719 JobData jobData = extraJobData.take(job);
00720
00721 ProtocolInfo *protInfo = protInfoDict.get(jobData.protocol);
00722 slave->disconnect(job);
00723 protInfo->activeSlaves.removeAll(slave);
00724 if (slave->isAlive())
00725 {
00726 JobList *list = coSlaves.value(slave);
00727 if (list)
00728 {
00729 assert(slave->isConnected());
00730 assert(!coIdleSlaves.contains(slave));
00731 coIdleSlaves.append(slave);
00732 if (!list->isEmpty())
00733 coSlaveTimer.start(0);
00734 return;
00735 }
00736 else
00737 {
00738 assert(!slave->isConnected());
00739 idleSlaves.append(slave);
00740 slave->setIdle();
00741 scheduleCleanup();
00742
00743 }
00744 }
00745 if (protInfo->joblist.count())
00746 {
00747 slaveTimer.start(0);
00748 }
00749 }
00750
00751 void SchedulerPrivate::slotSlaveDied(KIO::Slave *slave)
00752 {
00753 assert(!slave->isAlive());
00754 ProtocolInfo *protInfo = protInfoDict.get(slave->slaveProtocol());
00755 protInfo->activeSlaves.removeAll(slave);
00756 if (slave == slaveOnHold)
00757 {
00758 slaveOnHold = 0;
00759 urlOnHold = KUrl();
00760 }
00761 idleSlaves.removeAll(slave);
00762
00763 disconnectSlave(slave);
00764
00765 if (!slaveList.removeAll(slave))
00766 kDebug(7006) << "Scheduler: BUG!! Slave " << slave << "/" << slave->slave_pid() << " died, but is NOT in slaveList!!!\n";
00767 else
00768 slave->deref();
00769 }
00770
00771 void SchedulerPrivate::slotCleanIdleSlaves()
00772 {
00773 SlaveList::iterator it = idleSlaves.begin();
00774 for( ; it != idleSlaves.end(); )
00775 {
00776 Slave *slave = *it;
00777 if (slave->idleTime() >= MAX_SLAVE_IDLE)
00778 {
00779
00780 Slave *removeSlave = slave;
00781 it = idleSlaves.erase( it );
00782 slaveList.removeAll( removeSlave );
00783 removeSlave->connection()->close();
00784 removeSlave->deref();
00785 }
00786 else
00787 {
00788 ++it;
00789 }
00790 }
00791 scheduleCleanup();
00792 }
00793
00794 void SchedulerPrivate::scheduleCleanup()
00795 {
00796 if (idleSlaves.count())
00797 {
00798 if (!cleanupTimer.isActive())
00799 cleanupTimer.start( MAX_SLAVE_IDLE*1000 );
00800 }
00801 }
00802
00803 void SchedulerPrivate::putSlaveOnHold(KIO::SimpleJob *job, const KUrl &url)
00804 {
00805 Slave *slave = jobSlave(job);
00806 slave->disconnect(job);
00807
00808 if (slaveOnHold)
00809 {
00810 slaveOnHold->kill();
00811 }
00812 slaveOnHold = slave;
00813 urlOnHold = url;
00814 slaveOnHold->suspend();
00815 }
00816
00817 void SchedulerPrivate::publishSlaveOnHold()
00818 {
00819 if (!slaveOnHold)
00820 return;
00821
00822 slaveOnHold->hold(urlOnHold);
00823 }
00824
00825 void SchedulerPrivate::removeSlaveOnHold()
00826 {
00827 if (slaveOnHold)
00828 {
00829 slaveOnHold->kill();
00830 }
00831 slaveOnHold = 0;
00832 urlOnHold = KUrl();
00833 }
00834
00835 Slave *
00836 SchedulerPrivate::getConnectedSlave(const KUrl &url, const KIO::MetaData &config )
00837 {
00838 QString proxy;
00839 QString protocol = KProtocolManager::slaveProtocol(url, proxy);
00840 bool dummy;
00841 Slave *slave = searchIdleList(idleSlaves, url, protocol, dummy);
00842 if (!slave)
00843 {
00844 ProtocolInfo *protInfo = protInfoDict.get(protocol);
00845 slave = createSlave(protInfo, 0, url);
00846 }
00847 if (!slave)
00848 return 0;
00849 idleSlaves.removeAll(slave);
00850
00851 setupSlave(slave, url, protocol, proxy, true, &config);
00852
00853 slave->send( CMD_CONNECT );
00854 q->connect(slave, SIGNAL(connected()),
00855 SLOT(slotSlaveConnected()));
00856 q->connect(slave, SIGNAL(error(int, const QString &)),
00857 SLOT(slotSlaveError(int, const QString &)));
00858
00859 coSlaves.insert(slave, new JobList);
00860
00861 return slave;
00862 }
00863
00864 void
00865 SchedulerPrivate::slotScheduleCoSlave()
00866 {
00867 slaveConfig = SlaveConfig::self();
00868 SlaveList::iterator it = coIdleSlaves.begin();
00869 for( ; it != coIdleSlaves.end(); )
00870 {
00871 Slave* slave = *it;
00872 JobList *list = coSlaves.value(slave);
00873 assert(list);
00874 if (list && !list->isEmpty())
00875 {
00876 SimpleJob *job = list->takeFirst();
00877 it = coIdleSlaves.erase( it );
00878
00879
00880 KUrl url =job->url();
00881 QString host = url.host();
00882 int port = url.port();
00883 if ( port == -1 )
00884 port = 0;
00885
00886 if (slave->host() == "<reset>")
00887 {
00888 QString user = url.user();
00889 QString passwd = url.pass();
00890
00891 MetaData configData = slaveConfig->configData(url.protocol(), url.host());
00892 slave->setConfig(configData);
00893 slave->setProtocol(url.protocol());
00894 slave->setHost(host, port, user, passwd);
00895 }
00896
00897 assert(slave->protocol() == url.protocol());
00898 assert(slave->host() == host);
00899 assert(slave->port() == port);
00900 startJob(job, slave);
00901 } else {
00902 ++it;
00903 }
00904 }
00905 }
00906
00907 void
00908 SchedulerPrivate::slotSlaveConnected()
00909 {
00910 Slave *slave = static_cast<Slave *>(q->sender());
00911
00912 slave->setConnected(true);
00913 q->disconnect(slave, SIGNAL(connected()),
00914 q, SLOT(slotSlaveConnected()));
00915 emit q->slaveConnected(slave);
00916 assert(!coIdleSlaves.contains(slave));
00917 coIdleSlaves.append(slave);
00918 coSlaveTimer.start(0);
00919 }
00920
00921 void
00922 SchedulerPrivate::slotSlaveError(int errorNr, const QString &errorMsg)
00923 {
00924 Slave *slave = static_cast<Slave *>(q->sender());
00925 if (!slave->isConnected() || coIdleSlaves.contains(slave))
00926 {
00927
00928 emit q->slaveError(slave, errorNr, errorMsg);
00929 }
00930 }
00931
00932 bool
00933 SchedulerPrivate::assignJobToSlave(KIO::Slave *slave, SimpleJob *job)
00934 {
00935
00936 QString dummy;
00937 if ((slave->slaveProtocol() != KProtocolManager::slaveProtocol( job->url(), dummy ))
00938 ||
00939 (!newJobs.removeAll(job)))
00940 {
00941 kDebug(7006) << "_assignJobToSlave(): ERROR, nonmatching or unknown job.";
00942 job->kill();
00943 return false;
00944 }
00945
00946 JobList *list = coSlaves.value(slave);
00947 assert(list);
00948 if (!list)
00949 {
00950 kDebug(7006) << "_assignJobToSlave(): ERROR, unknown slave.";
00951 job->kill();
00952 return false;
00953 }
00954
00955 assert(!list->contains(job));
00956 list->append(job);
00957 coSlaveTimer.start(0);
00958
00959 return true;
00960 }
00961
00962 bool
00963 SchedulerPrivate::disconnectSlave(KIO::Slave *slave)
00964 {
00965
00966 CoSlaveMap::iterator coSlaveIt = coSlaves.find( slave );
00967 if ( coSlaveIt != coSlaves.end() ) {
00968 JobList *list = *coSlaveIt;
00969 coSlaves.erase( coSlaveIt );
00970 if (list)
00971 {
00972
00973 while(!list->isEmpty())
00974 {
00975 Job *job = list->takeFirst();
00976 job->kill();
00977 }
00978 delete list;
00979 }
00980 }
00981 coIdleSlaves.removeAll(slave);
00982 assert(!coIdleSlaves.contains(slave));
00983 QObject::disconnect(slave, SIGNAL(connected()),
00984 q, SLOT(slotSlaveConnected()));
00985 QObject::disconnect(slave, SIGNAL(error(int, const QString &)),
00986 q, SLOT(slotSlaveError(int, const QString &)));
00987 if (slave->isAlive())
00988 {
00989 idleSlaves.append(slave);
00990 slave->send( CMD_DISCONNECT );
00991 slave->setIdle();
00992 slave->setConnected(false);
00993 scheduleCleanup();
00994 }
00995 return true;
00996 }
00997
00998 void
00999 SchedulerPrivate::checkSlaveOnHold(bool b)
01000 {
01001 checkOnHold = b;
01002 }
01003
01004 void
01005 SchedulerPrivate::registerWindow(QWidget *wid)
01006 {
01007 if (!wid)
01008 return;
01009
01010 QWidget* window = wid->window();
01011
01012 QObject *obj = static_cast<QObject *>(window);
01013 if (!m_windowList.contains(obj))
01014 {
01015
01016
01017
01018 WId windowId = window->winId();
01019 m_windowList.insert(obj, windowId);
01020 q->connect(window, SIGNAL(destroyed(QObject *)),
01021 SLOT(slotUnregisterWindow(QObject*)));
01022 QDBusInterface("org.kde.kded", "/kded", "org.kde.kded").
01023 call(QDBus::NoBlock, "registerWindowId", qlonglong(windowId));
01024 }
01025 }
01026
01027 void
01028 SchedulerPrivate::slotUnregisterWindow(QObject *obj)
01029 {
01030 if (!obj)
01031 return;
01032
01033 QMap<QObject *, WId>::Iterator it = m_windowList.find(obj);
01034 if (it == m_windowList.end())
01035 return;
01036 WId windowId = it.value();
01037 q->disconnect(it.key(), SIGNAL(destroyed(QObject *)),
01038 q, SLOT(slotUnregisterWindow(QObject*)));
01039 m_windowList.erase( it );
01040 QDBusInterface("org.kde.kded", "/kded", "org.kde.kded").
01041 call(QDBus::NoBlock, "unregisterWindowId", qlonglong(windowId));
01042 }
01043
01044 #include "scheduler.moc"