• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

scheduler.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
00003                       Waldo Bastian <bastian@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License version 2 as published by the Free Software Foundation.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
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 // Slaves may be idle for MAX_SLAVE_IDLE time before they are being returned
00041 // to the system wide slave pool. (3 minutes)
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 ) // !! Always check with KLauncher for the first request
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 // There are two kinds of protocol:
00205 // (1) The protocol of the url
00206 // (2) The actual protocol that the io-slave uses.
00207 //
00208 // These two often match, but not necessarily. Most notably, they don't
00209 // match when doing ftp via a proxy.
00210 // In that case (1) is ftp, but (2) is http.
00211 //
00212 // JobData::protocol stores (2) while Job::url().protocol() returns (1).
00213 // The ProtocolInfoDict is indexed with (2).
00214 //
00215 // We schedule slaves based on (2) but tell the slave about (1) via
00216 // Slave::setProtocol().
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 //    kDebug(7006) << "protocol=" << jobData->protocol;
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.removeAll(job);
00386     const JobData& jobData = extraJobData.value(job);
00387 
00388     QString protocol = jobData.protocol;
00389 //    kDebug(7006) << "protocol=" << protocol;
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 //    kDebug(7006) << "Scheduler: canceling job " << job;
00398     Slave *slave = jobSlave(job);
00399     if ( !slave  )
00400     {
00401         // was not yet running (don't call this on a finished job!)
00402         JobData jobData = extraJobData.value(job);
00403         newJobs.removeAll(job);
00404         ProtocolInfo *protInfo = protInfoDict.get(jobData.protocol);
00405         protInfo->joblist.removeAll(job);
00406 
00407         // Search all slaves to see if job is in the queue of a coSlave
00408         foreach( Slave* coSlave, slaveList )
00409         {
00410            JobList *list = coSlaves.value(coSlave);
00411            if (list && list->removeAll(job)) {
00412                // Job was found and removed.
00413                // Fall through to kill the slave as well!
00414                slave = coSlave;
00415                break;
00416            }
00417         }
00418         if (!slave)
00419         {
00420            extraJobData.remove(job);
00421            return; // Job was not yet running and not in a coSlave queue.
00422         }
00423     }
00424     kDebug(7006) << "Scheduler: killing slave " << slave->slave_pid();
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 ) // no port is -1 in QUrl, but in kde3 we used 0 and the kioslaves assume that.
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.begin();
00479                     for ( ; it != l.macdef.end(); ++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 //       kDebug(7006) << "Scheduling job";
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        // Prevent starvation. We skip the first entry in the queue at most
00509        // 2 times in a row. The
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 //          kDebug(7006) << "No slaves available";
00557 //          kDebug(7006) << " -- active: " << protInfo->activeSlaves.count();
00558        return false;
00559     }
00560 
00561     protInfo->activeSlaves.append(slave);
00562     idleSlaves.removeAll(slave);
00563     protInfo->joblist.removeAll(job);
00564 //       kDebug(7006) << "scheduler: job started " << job;
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     // Look for matching slave
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 //       kDebug(7006) << "scheduler: job started " << job;
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 ) // no port is -1 in QUrl, but in kde3 we used 0 and the kioslaves assume that.
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     // Look for slightly matching slave
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        // Make sure that the job wants to do a GET or a POST, and with no offset
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 //       kDebug(7006) << "bCanReuse = " << bCanReuse;
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 //          slave->send( CMD_SLAVE_STATUS );
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     JobList *list = coSlaves.value(slave);
00763     if (list)
00764     {
00765        // coSlave dies, kill jobs waiting in queue
00766        disconnectSlave(slave);
00767     }
00768 
00769     if (!slaveList.removeAll(slave))
00770         kDebug(7006) << "Scheduler: BUG!! Slave " << slave << "/" << slave->slave_pid() << " died, but is NOT in slaveList!!!\n";
00771     else
00772         slave->deref(); // Delete slave
00773 }
00774 
00775 void SchedulerPrivate::slotCleanIdleSlaves()
00776 {
00777     SlaveList::iterator it = idleSlaves.begin();
00778     for( ; it != idleSlaves.end(); )
00779     {
00780         Slave *slave = *it;
00781         if (slave->idleTime() >= MAX_SLAVE_IDLE)
00782         {
00783            // kDebug(7006) << "Removing idle slave: " << slave->slaveProtocol() << " " << slave->host();
00784            Slave *removeSlave = slave;
00785            it = idleSlaves.erase( it );
00786            slaveList.removeAll( removeSlave );
00787            removeSlave->connection()->close();
00788            removeSlave->deref();
00789         }
00790         else
00791         {
00792             ++it;
00793         }
00794     }
00795     scheduleCleanup();
00796 }
00797 
00798 void SchedulerPrivate::scheduleCleanup()
00799 {
00800     if (idleSlaves.count())
00801     {
00802         if (!cleanupTimer.isActive())
00803             cleanupTimer.start( MAX_SLAVE_IDLE*1000 );
00804     }
00805 }
00806 
00807 void SchedulerPrivate::putSlaveOnHold(KIO::SimpleJob *job, const KUrl &url)
00808 {
00809     Slave *slave = jobSlave(job);
00810     slave->disconnect(job);
00811 
00812     if (slaveOnHold)
00813     {
00814         slaveOnHold->kill();
00815     }
00816     slaveOnHold = slave;
00817     urlOnHold = url;
00818     slaveOnHold->suspend();
00819 }
00820 
00821 void SchedulerPrivate::publishSlaveOnHold()
00822 {
00823     if (!slaveOnHold)
00824        return;
00825 
00826     slaveOnHold->hold(urlOnHold);
00827 }
00828 
00829 void SchedulerPrivate::removeSlaveOnHold()
00830 {
00831     if (slaveOnHold)
00832     {
00833         slaveOnHold->kill();
00834     }
00835     slaveOnHold = 0;
00836     urlOnHold = KUrl();
00837 }
00838 
00839 Slave *
00840 SchedulerPrivate::getConnectedSlave(const KUrl &url, const KIO::MetaData &config )
00841 {
00842     QString proxy;
00843     QString protocol = KProtocolManager::slaveProtocol(url, proxy);
00844     bool dummy;
00845     Slave *slave = searchIdleList(idleSlaves, url, protocol, dummy);
00846     if (!slave)
00847     {
00848        ProtocolInfo *protInfo = protInfoDict.get(protocol);
00849        slave = createSlave(protInfo, 0, url);
00850     }
00851     if (!slave)
00852        return 0; // Error
00853     idleSlaves.removeAll(slave);
00854 
00855     setupSlave(slave, url, protocol, proxy, true, &config);
00856 
00857     slave->send( CMD_CONNECT );
00858     q->connect(slave, SIGNAL(connected()),
00859                SLOT(slotSlaveConnected()));
00860     q->connect(slave, SIGNAL(error(int, const QString &)),
00861                SLOT(slotSlaveError(int, const QString &)));
00862 
00863     coSlaves.insert(slave, new JobList);
00864 //    kDebug(7006) << "_getConnectedSlave( " << slave << ")";
00865     return slave;
00866 }
00867 
00868 void
00869 SchedulerPrivate::slotScheduleCoSlave()
00870 {
00871     slaveConfig = SlaveConfig::self();
00872     SlaveList::iterator it = coIdleSlaves.begin();
00873     for( ; it != coIdleSlaves.end(); )
00874     {
00875         Slave* slave = *it;
00876         JobList *list = coSlaves.value(slave);
00877         assert(list);
00878         if (list && !list->isEmpty())
00879         {
00880            SimpleJob *job = list->takeFirst();
00881            it = coIdleSlaves.erase( it );
00882 //           kDebug(7006) << "scheduler: job started " << job;
00883 
00884            KUrl url =job->url();
00885            QString host = url.host();
00886            int port = url.port();
00887            if ( port == -1 ) // no port is -1 in QUrl, but in kde3 we used 0 and the kioslaves assume that.
00888                port = 0;
00889 
00890            if (slave->host() == "<reset>")
00891            {
00892               QString user = url.user();
00893               QString passwd = url.pass();
00894 
00895               MetaData configData = slaveConfig->configData(url.protocol(), url.host());
00896               slave->setConfig(configData);
00897               slave->setProtocol(url.protocol());
00898               slave->setHost(host, port, user, passwd);
00899            }
00900 
00901            assert(slave->protocol() == url.protocol());
00902            assert(slave->host() == host);
00903            assert(slave->port() == port);
00904            startJob(job, slave);
00905         } else {
00906             ++it;
00907         }
00908     }
00909 }
00910 
00911 void
00912 SchedulerPrivate::slotSlaveConnected()
00913 {
00914     Slave *slave = static_cast<Slave *>(q->sender());
00915 //    kDebug(7006) << "slotSlaveConnected( " << slave << ")";
00916     slave->setConnected(true);
00917     q->disconnect(slave, SIGNAL(connected()),
00918                   q, SLOT(slotSlaveConnected()));
00919     emit q->slaveConnected(slave);
00920     assert(!coIdleSlaves.contains(slave));
00921     coIdleSlaves.append(slave);
00922     coSlaveTimer.start(0);
00923 }
00924 
00925 void
00926 SchedulerPrivate::slotSlaveError(int errorNr, const QString &errorMsg)
00927 {
00928     Slave *slave = static_cast<Slave *>(q->sender());
00929     if (!slave->isConnected() || coIdleSlaves.contains(slave))
00930     {
00931        // Only forward to application if slave is idle or still connecting.
00932        emit q->slaveError(slave, errorNr, errorMsg);
00933     }
00934 }
00935 
00936 bool
00937 SchedulerPrivate::assignJobToSlave(KIO::Slave *slave, SimpleJob *job)
00938 {
00939 //    kDebug(7006) << "_assignJobToSlave( " << job << ", " << slave << ")";
00940     QString dummy;
00941     if ((slave->slaveProtocol() != KProtocolManager::slaveProtocol( job->url(), dummy ))
00942         ||
00943         (!newJobs.removeAll(job)))
00944     {
00945         kDebug(7006) << "_assignJobToSlave(): ERROR, nonmatching or unknown job.";
00946         job->kill();
00947         return false;
00948     }
00949 
00950     JobList *list = coSlaves.value(slave);
00951     assert(list);
00952     if (!list)
00953     {
00954         kDebug(7006) << "_assignJobToSlave(): ERROR, unknown slave.";
00955         job->kill();
00956         return false;
00957     }
00958 
00959     assert(!list->contains(job));
00960     list->append(job);
00961     coSlaveTimer.start(0); // Start job on timer event
00962 
00963     return true;
00964 }
00965 
00966 bool
00967 SchedulerPrivate::disconnectSlave(KIO::Slave *slave)
00968 {
00969 //    kDebug(7006) << "_disconnectSlave( " << slave << ")";
00970     CoSlaveMap::iterator coSlaveIt = coSlaves.find( slave );
00971     assert( coSlaveIt != coSlaves.end() );
00972     JobList *list = *coSlaveIt;
00973     coSlaves.erase( coSlaveIt );
00974     assert(list);
00975     if (!list)
00976        return false;
00977     // Kill jobs still in queue.
00978     while(!list->isEmpty())
00979     {
00980        Job *job = list->takeFirst();
00981        job->kill();
00982     }
00983     delete list;
00984     coIdleSlaves.removeAll(slave);
00985     assert(!coIdleSlaves.contains(slave));
00986     QObject::disconnect(slave, SIGNAL(connected()),
00987                         q, SLOT(slotSlaveConnected()));
00988     QObject::disconnect(slave, SIGNAL(error(int, const QString &)),
00989                         q, SLOT(slotSlaveError(int, const QString &)));
00990     if (slave->isAlive())
00991     {
00992        idleSlaves.append(slave);
00993        slave->send( CMD_DISCONNECT );
00994        slave->setIdle();
00995        slave->setConnected(false);
00996        scheduleCleanup();
00997     }
00998     return true;
00999 }
01000 
01001 void
01002 SchedulerPrivate::checkSlaveOnHold(bool b)
01003 {
01004     checkOnHold = b;
01005 }
01006 
01007 void
01008 SchedulerPrivate::registerWindow(QWidget *wid)
01009 {
01010    if (!wid)
01011       return;
01012 
01013    QObject *obj = static_cast<QObject *>(wid);
01014    if (!m_windowList.contains(obj))
01015    {
01016       // We must store the window Id because by the time
01017       // the destroyed signal is emitted we can no longer
01018       // access QWidget::winId() (already destructed)
01019       WId windowId = wid->winId();
01020       m_windowList.insert(obj, windowId);
01021       q->connect(wid, SIGNAL(destroyed(QObject *)),
01022                  SLOT(slotUnregisterWindow(QObject*)));
01023       QDBusInterface("org.kde.kded", "/kded", "org.kde.kded").
01024           call(QDBus::NoBlock, "registerWindowId", qlonglong(windowId));
01025    }
01026 }
01027 
01028 void
01029 SchedulerPrivate::slotUnregisterWindow(QObject *obj)
01030 {
01031    if (!obj)
01032       return;
01033 
01034    QMap<QObject *, WId>::Iterator it = m_windowList.find(obj);
01035    if (it == m_windowList.end())
01036       return;
01037    WId windowId = it.value();
01038    q->disconnect(it.key(), SIGNAL(destroyed(QObject *)),
01039                  q, SLOT(slotUnregisterWindow(QObject*)));
01040    m_windowList.erase( it );
01041    QDBusInterface("org.kde.kded", "/kded", "org.kde.kded").
01042        call(QDBus::NoBlock, "unregisterWindowId", qlonglong(windowId));
01043 }
01044 
01045 #include "scheduler.moc"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.6
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal