| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# scheduler.cpp

    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., 59 Temple Place - Suite 330,
    00017    Boston, MA 02111-1307, USA.
    00018 */
    00019
    00020 #include "kio/sessiondata.h"
    00021 #include "kio/slaveconfig.h"
    00022 #include "kio/scheduler.h"
    00023 #include "kio/authinfo.h"
    00024 #include "kio/slave.h"
    00025 #include <qptrlist.h>
    00026 #include <qdict.h>
    00027
    00028 #include <dcopclient.h>
    00029
    00030 #include <kdebug.h>
    00031 #include <kglobal.h>
    00032 #include <kprotocolmanager.h>
    00033 #include <kprotocolinfo.h>
    00034 #include <assert.h>
    00035 #include <kstaticdeleter.h>
    00036 #include <kdesu/client.h>
    00037
    00038
    00039 // Slaves may be idle for MAX_SLAVE_IDLE time before they are being returned
    00040 // to the system wide slave pool. (3 minutes)
    00041 #define MAX_SLAVE_IDLE (3*60)
    00042
    00043 using namespace KIO;
    00044
    00045 template class QDict<KIO::Scheduler::ProtocolInfo>;
    00046
    00047 Scheduler *Scheduler::instance = 0;
    00048
    00049 class KIO::SlaveList: public QPtrList<Slave>
    00050 {
    00051    public:
    00052       SlaveList() { }
    00053 };
    00054
    00055 //
    00056 // There are two kinds of protocol:
    00057 // (1) The protocol of the url
    00058 // (2) The actual protocol that the io-slave uses.
    00059 //
    00060 // These two often match, but not necasserily. Most notably, they don't
    00061 // match when doing ftp via a proxy.
    00062 // In that case (1) is ftp, but (2) is http.
    00063 //
    00064 // JobData::protocol stores (2) while Job::url().protocol() returns (1).
    00065 // The ProtocolInfoDict is indexed with (2).
    00066 //
    00067 // We schedule slaves based on (2) but tell the slave about (1) via
    00068 // Slave::setProtocol().
    00069
    00070 class KIO::Scheduler::JobData
    00071 {
    00072 public:
    00073     JobData() : checkOnHold(false) { }
    00074
    00075 public:
    00076     QString protocol;
    00077     QString proxy;
    00078     bool checkOnHold;
    00079 };
    00080
    00081 class KIO::Scheduler::ExtraJobData: public QPtrDict<KIO::Scheduler::JobData>
    00082 {
    00083 public:
    00084     ExtraJobData() { setAutoDelete(true); }
    00085 };
    00086
    00087 class KIO::Scheduler::ProtocolInfo
    00088 {
    00089 public:
    00090     ProtocolInfo() : maxSlaves(1), skipCount(0)
    00091     {
    00092        joblist.setAutoDelete(false);
    00093     }
    00094
    00095     QPtrList<SimpleJob> joblist;
    00096     SlaveList activeSlaves;
    00097     int maxSlaves;
    00098     int skipCount;
    00099     QString protocol;
    00100 };
    00101
    00102 class KIO::Scheduler::ProtocolInfoDict : public QDict<KIO::Scheduler::ProtocolInfo>
    00103 {
    00104   public:
    00105     ProtocolInfoDict() { }
    00106
    00107     KIO::Scheduler::ProtocolInfo *get( const QString &protocol);
    00108 };
    00109
    00110 KIO::Scheduler::ProtocolInfo *
    00111 KIO::Scheduler::ProtocolInfoDict::get(const QString &protocol)
    00112 {
    00113     ProtocolInfo *info = find(protocol);
    00114     if (!info)
    00115     {
    00116         info = new ProtocolInfo;
    00117         info->protocol = protocol;
    00118         info->maxSlaves = KProtocolInfo::maxSlaves( protocol );
    00119
    00120         insert(protocol, info);
    00121     }
    00122     return info;
    00123 }
    00124
    00125
    00126 Scheduler::Scheduler()
    00127           :QObject(kapp, "scheduler"),
    00128            DCOPObject( "KIO::Scheduler" ),
    00129            slaveTimer(0, "Scheduler::slaveTimer"),
    00130            coSlaveTimer(0, "Scheduler::coSlaveTimer"),
    00131            cleanupTimer(0, "Scheduler::cleanupTimer")
    00132 {
    00133     checkOnHold = true; // !! Always check with KLauncher for the first request.
    00134     slaveOnHold = 0;
    00135     protInfoDict = new ProtocolInfoDict;
    00136     slaveList = new SlaveList;
    00137     idleSlaves = new SlaveList;
    00138     coIdleSlaves = new SlaveList;
    00139     extraJobData = new ExtraJobData;
    00140     sessionData = new SessionData;
    00141     slaveConfig = SlaveConfig::self();
    00142     connect(&slaveTimer, SIGNAL(timeout()), SLOT(startStep()));
    00143     connect(&coSlaveTimer, SIGNAL(timeout()), SLOT(slotScheduleCoSlave()));
    00144     connect(&cleanupTimer, SIGNAL(timeout()), SLOT(slotCleanIdleSlaves()));
    00145     busy = false;
    00146 }
    00147
    00148 Scheduler::~Scheduler()
    00149 {
    00150     protInfoDict->setAutoDelete(true);
    00151     delete protInfoDict; protInfoDict = 0;
    00152     delete idleSlaves; idleSlaves = 0;
    00153     delete coIdleSlaves; coIdleSlaves = 0;
    00154     slaveList->setAutoDelete(true);
    00155     delete slaveList; slaveList = 0;
    00156     delete extraJobData; extraJobData = 0;
    00157     delete sessionData; sessionData = 0;
    00158     instance = 0;
    00159 }
    00160
    00161 void
    00162 Scheduler::debug_info()
    00163 {
    00164 }
    00165
    00166 bool Scheduler::process(const QCString &fun, const QByteArray &data, QCString &replyType, QByteArray &replyData )
    00167 {
    00168     if ( fun != "reparseSlaveConfiguration(QString)" )
    00169         return DCOPObject::process( fun, data, replyType, replyData );
    00170
    00171     replyType = "void";
    00172     QDataStream stream( data, IO_ReadOnly );
    00173     QString proto;
    00174     stream >> proto;
    00175
    00176     kdDebug( 7006 ) << "reparseConfiguration( " << proto << " )" << endl;
    00177     KProtocolManager::reparseConfiguration();
    00178     slaveConfig->reset();
    00179     sessionData->reset();
    00180     NetRC::self()->reload();
    00181
    00182     Slave *slave = slaveList->first();
    00183     for (; slave; slave = slaveList->next() )
    00184     if ( slave->slaveProtocol() == proto || proto.isEmpty() )
    00185     {
    00186       slave->connection()->send( CMD_REPARSECONFIGURATION );
    00187       slave->resetHost();
    00188     }
    00189     return true;
    00190 }
    00191
    00192 QCStringList Scheduler::functions()
    00193 {
    00194     QCStringList funcs = DCOPObject::functions();
    00195     funcs << "void reparseSlaveConfiguration(QString)";
    00196     return funcs;
    00197 }
    00198
    00199 void Scheduler::_doJob(SimpleJob *job) {
    00200     JobData *jobData = new JobData;
    00201     jobData->protocol = KProtocolManager::slaveProtocol(job->url(), jobData->proxy);
    00202 //    kdDebug(7006) << "Scheduler::_doJob protocol=" << jobData->protocol << endl;
    00203     if (job->command() == CMD_GET)
    00204     {
    00205        jobData->checkOnHold = checkOnHold;
    00206        checkOnHold = false;
    00207     }
    00208     extraJobData->replace(job, jobData);
    00209     newJobs.append(job);
    00210     slaveTimer.start(0, true);
    00211 }
    00212
    00213 void Scheduler::_scheduleJob(SimpleJob *job) {
    00214     newJobs.removeRef(job);
    00215     JobData *jobData = extraJobData->find(job);
    00216     if (!jobData)
    00217 {
    00218     kdFatal(7006) << "BUG! _ScheduleJob(): No extraJobData for job!" << endl;
    00219     return;
    00220 }
    00221     QString protocol = jobData->protocol;
    00222 //    kdDebug(7006) << "Scheduler::_scheduleJob protocol=" << protocol << endl;
    00223     ProtocolInfo *protInfo = protInfoDict->get(protocol);
    00224     protInfo->joblist.append(job);
    00225
    00226     slaveTimer.start(0, true);
    00227 }
    00228
    00229 void Scheduler::_cancelJob(SimpleJob *job) {
    00230 //    kdDebug(7006) << "Scheduler: canceling job " << job << endl;
    00231     Slave *slave = job->slave();
    00232     if ( !slave  )
    00233     {
    00234         // was not yet running (don't call this on a finished job!)
    00235         JobData *jobData = extraJobData->find(job);
    00236         if (!jobData)
    00237            return; // I said: "Don't call this on a finished job!"
    00238
    00239         newJobs.removeRef(job);
    00240         ProtocolInfo *protInfo = protInfoDict->get(jobData->protocol);
    00241         protInfo->joblist.removeRef(job);
    00242
    00243         // Search all slaves to see if job is in the queue of a coSlave
    00244         slave = slaveList->first();
    00245         for(; slave; slave = slaveList->next())
    00246         {
    00247            JobList *list = coSlaves.find(slave);
    00248            if (list && list->removeRef(job))
    00249               break; // Job was found and removed.
    00250                      // Fall through to kill the slave as well!
    00251         }
    00252         if (!slave)
    00253         {
    00254            extraJobData->remove(job);
    00255            return; // Job was not yet running and not in a coSlave queue.
    00256         }
    00257     }
    00258     kdDebug(7006) << "Scheduler: killing slave " << slave->slave_pid() << endl;
    00259     slave->kill();
    00260     _jobFinished( job, slave );
    00261     slotSlaveDied( slave);
    00262 }
    00263
    00264 void Scheduler::startStep()
    00265 {
    00266     while(newJobs.count())
    00267     {
    00268        (void) startJobDirect();
    00269     }
    00270     QDictIterator<KIO::Scheduler::ProtocolInfo> it(*protInfoDict);
    00271     while(it.current())
    00272     {
    00273        if (startJobScheduled(it.current())) return;
    00274        ++it;
    00275     }
    00276 }
    00277
    00278 void Scheduler::setupSlave(KIO::Slave *slave, const KURL &url, const QString &protocol, const QString &proxy , bool newSlave, const KIO::MetaData *config)
    00279 {
    00280     QString host = url.host();
    00281     int port = url.port();
    00282     QString user = url.user();
    00283     QString passwd = url.pass();
    00284
    00285     if ((newSlave) ||
    00286         (slave->host() != host) ||
    00287         (slave->port() != port) ||
    00288         (slave->user() != user) ||
    00289         (slave->passwd() != passwd))
    00290     {
    00291         MetaData configData = slaveConfig->configData(protocol, host);
    00292         sessionData->configDataFor( configData, protocol, host );
    00293
    00294         configData["UseProxy"] = proxy;
    00295
    00296         QString autoLogin = configData["EnableAutoLogin"].lower();
    00297         if ( autoLogin == "true" )
    00298         {
    00299             NetRC::AutoLogin l;
    00300             l.login = user;
    00301             bool usern = (protocol == "ftp");
    00302             if ( NetRC::self()->lookup( url, l, usern) )
    00303             {
    00304                 configData["autoLoginUser"] = l.login;
    00305                 configData["autoLoginPass"] = l.password;
    00306                 if ( usern )
    00307                 {
    00308                     QString macdef;
    00309                     QMap<QString, QStringList>::ConstIterator it = l.macdef.begin();
    00310                     for ( ; it != l.macdef.end(); ++it )
    00311                         macdef += it.key() + '\\' + it.data().join( "\\" ) + '\n';
    00312                     configData["autoLoginMacro"] = macdef;
    00313                 }
    00314             }
    00315         }
    00316         if (config)
    00317            configData += *config;
    00318         slave->setConfig(configData);
    00319         slave->setProtocol(url.protocol());
    00320         slave->setHost(host, port, user, passwd);
    00321     }
    00322 }
    00323
    00324 bool Scheduler::startJobScheduled(ProtocolInfo *protInfo)
    00325 {
    00326     if (protInfo->joblist.isEmpty())
    00327        return false;
    00328
    00329 //       kdDebug(7006) << "Scheduling job" << endl;
    00330     debug_info();
    00331     bool newSlave = false;
    00332
    00333     SimpleJob *job = 0;
    00334     Slave *slave = 0;
    00335
    00336     if (protInfo->skipCount > 2)
    00337     {
    00338        bool dummy;
    00339        // Prevent starvation. We skip the first entry in the queue at most
    00340        // 2 times in a row. The
    00341        protInfo->skipCount = 0;
    00342        job = protInfo->joblist.at(0);
    00343        slave = findIdleSlave(protInfo, job, dummy );
    00344     }
    00345     else
    00346     {
    00347        bool exact=false;
    00348        SimpleJob *firstJob = 0;
    00349        Slave *firstSlave = 0;
    00350        for(uint i = 0; (i < protInfo->joblist.count()) && (i < 10); i++)
    00351        {
    00352           job = protInfo->joblist.at(i);
    00353           slave = findIdleSlave(protInfo, job, exact);
    00354           if (!firstSlave)
    00355           {
    00356              firstJob = job;
    00357              firstSlave = slave;
    00358           }
    00359           if (!slave) break;
    00360           if (exact) break;
    00361        }
    00362
    00363        if (!exact)
    00364        {
    00365          slave = firstSlave;
    00366          job = firstJob;
    00367        }
    00368        if (job == firstJob)
    00369          protInfo->skipCount = 0;
    00370        else
    00371          protInfo->skipCount++;
    00372     }
    00373
    00374     if (!slave)
    00375     {
    00376        if ( protInfo->maxSlaves > static_cast<int>(protInfo->activeSlaves.count()) )
    00377        {
    00378           newSlave = true;
    00379           slave = createSlave(protInfo, job, job->url());
    00380        }
    00381     }
    00382
    00383     if (!slave)
    00384     {
    00385 //          kdDebug(7006) << "No slaves available" << endl;
    00386 //          kdDebug(7006) << " -- active: " << protInfo->activeSlaves.count() << endl;
    00387        return false;
    00388     }
    00389
    00390     protInfo->activeSlaves.append(slave);
    00391     idleSlaves->removeRef(slave);
    00392     protInfo->joblist.removeRef(job);
    00393 //       kdDebug(7006) << "scheduler: job started " << job << endl;
    00394
    00395
    00396     JobData *jobData = extraJobData->find(job);
    00397     setupSlave(slave, job->url(), jobData->protocol, jobData->proxy, newSlave);
    00398     job->start(slave);
    00399
    00400     slaveTimer.start(0, true);
    00401     return true;
    00402 }
    00403
    00404 bool Scheduler::startJobDirect()
    00405 {
    00406     debug_info();
    00407     SimpleJob *job = newJobs.take(0);
    00408     JobData *jobData = extraJobData->find(job);
    00409 if (!jobData)
    00410 {
    00411         kdFatal(7006) << "BUG! startjobDirect(): No extraJobData for job!"
    00412                       << endl;
    00413     return false;
    00414 }
    00415     QString protocol = jobData->protocol;
    00416     ProtocolInfo *protInfo = protInfoDict->get(protocol);
    00417
    00418     bool newSlave = false;
    00419     bool dummy;
    00420
    00421     // Look for matching slave
    00422     Slave *slave = findIdleSlave(protInfo, job, dummy);
    00423
    00424     if (!slave)
    00425     {
    00426        newSlave = true;
    00427        slave = createSlave(protInfo, job, job->url());
    00428     }
    00429
    00430     if (!slave)
    00431        return false;
    00432
    00433     idleSlaves->removeRef(slave);
    00434 //       kdDebug(7006) << "scheduler: job started " << job << endl;
    00435
    00436     setupSlave(slave, job->url(), protocol, jobData->proxy, newSlave);
    00437     job->start(slave);
    00438     return true;
    00439 }
    00440
    00441 static Slave *searchIdleList(SlaveList *idleSlaves, const KURL &url, const QString &protocol, bool &exact)
    00442 {
    00443     QString host = url.host();
    00444     int port = url.port();
    00445     QString user = url.user();
    00446     exact = true;
    00447
    00448     for( Slave *slave = idleSlaves->first();
    00449          slave;
    00450          slave = idleSlaves->next())
    00451     {
    00452        if ((protocol == slave->slaveProtocol()) &&
    00453            (host == slave->host()) &&
    00454            (port == slave->port()) &&
    00455            (user == slave->user()))
    00456            return slave;
    00457     }
    00458
    00459     exact = false;
    00460
    00461     // Look for slightly matching slave
    00462     for( Slave *slave = idleSlaves->first();
    00463          slave;
    00464          slave = idleSlaves->next())
    00465     {
    00466        if (protocol == slave->slaveProtocol())
    00467           return slave;
    00468     }
    00469     return 0;
    00470 }
    00471
    00472 Slave *Scheduler::findIdleSlave(ProtocolInfo *, SimpleJob *job, bool &exact)
    00473 {
    00474     Slave *slave = 0;
    00475     JobData *jobData = extraJobData->find(job);
    00476 if (!jobData)
    00477 {
    00478     kdFatal(7006) << "BUG! findIdleSlave(): No extraJobData for job!" << endl;
    00479     return 0;
    00480 }
    00481     if (jobData->checkOnHold)
    00482     {
    00483        slave = Slave::holdSlave(jobData->protocol, job->url());
    00484        if (slave)
    00485           return slave;
    00486     }
    00487     if (slaveOnHold)
    00488     {
    00489        // Make sure that the job wants to do a GET or a POST, and with no offset
    00490        bool bCanReuse = (job->command() == CMD_GET);
    00491        KIO::TransferJob * tJob = dynamic_cast<KIO::TransferJob *>(job);
    00492        if ( tJob )
    00493        {
    00494           bCanReuse = (job->command() == CMD_GET || job->command() == CMD_SPECIAL);
    00495           if ( bCanReuse )
    00496           {
    00497             KIO::MetaData outgoing = tJob->outgoingMetaData();
    00498             QString resume = (!outgoing.contains("resume")) ? QString::null : outgoing["resume"];
    00499             kdDebug(7006) << "Resume metadata is '" << resume << "'" << endl;
    00500             bCanReuse = (resume.isEmpty() || resume == "0");
    00501           }
    00502        }
    00503 //       kdDebug(7006) << "bCanReuse = " << bCanReuse << endl;
    00504        if (bCanReuse)
    00505        {
    00506           if (job->url() == urlOnHold)
    00507           {
    00508              kdDebug(7006) << "HOLD: Reusing held slave for " << urlOnHold.prettyURL() << endl;
    00509              slave = slaveOnHold;
    00510           }
    00511           else
    00512           {
    00513              kdDebug(7006) << "HOLD: Discarding held slave (" << urlOnHold.prettyURL() << ")" << endl;
    00514              slaveOnHold->kill();
    00515           }
    00516           slaveOnHold = 0;
    00517           urlOnHold = KURL();
    00518        }
    00519        if (slave)
    00520           return slave;
    00521     }
    00522
    00523     return searchIdleList(idleSlaves, job->url(), jobData->protocol, exact);
    00524 }
    00525
    00526 Slave *Scheduler::createSlave(ProtocolInfo *protInfo, SimpleJob *job, const KURL &url)
    00527 {
    00528    int error;
    00529    QString errortext;
    00530    Slave *slave = Slave::createSlave(protInfo->protocol, url, error, errortext);
    00531    if (slave)
    00532    {
    00533       slaveList->append(slave);
    00534       idleSlaves->append(slave);
    00535       connect(slave, SIGNAL(slaveDied(KIO::Slave *)),
    00536                 SLOT(slotSlaveDied(KIO::Slave *)));
    00537       connect(slave, SIGNAL(slaveStatus(pid_t,const QCString &,const QString &, bool)),
    00538                 SLOT(slotSlaveStatus(pid_t,const QCString &, const QString &, bool)));
    00539
    00540       connect(slave,SIGNAL(authorizationKey(const QCString&, const QCString&, bool)),
    00541               sessionData,SLOT(slotAuthData(const QCString&, const QCString&, bool)));
    00542       connect(slave,SIGNAL(delAuthorization(const QCString&)), sessionData,
    00543               SLOT(slotDelAuthData(const QCString&)));
    00544    }
    00545    else
    00546    {
    00547       kdError() << "ERROR " << error << ": couldn't create slave : "
    00548                 << errortext << endl;
    00549       if (job)
    00550       {
    00551          protInfo->joblist.removeRef(job);
    00552          extraJobData->remove(job);
    00553          job->slotError( error, errortext );
    00554       }
    00555    }
    00556    return slave;
    00557 }
    00558
    00559 void Scheduler::slotSlaveStatus(pid_t, const QCString &, const QString &, bool)
    00560 {
    00561 }
    00562
    00563 void Scheduler::_jobFinished(SimpleJob *job, Slave *slave)
    00564 {
    00565     JobData *jobData = extraJobData->take(job);
    00566 if (!jobData)
    00567 {
    00568     kdFatal(7006) << "BUG! _jobFinished(): No extraJobData for job!" << endl;
    00569     return;
    00570 }
    00571     ProtocolInfo *protInfo = protInfoDict->get(jobData->protocol);
    00572     delete jobData;
    00573     slave->disconnect(job);
    00574     protInfo->activeSlaves.removeRef(slave);
    00575     if (slave->isAlive())
    00576     {
    00577        JobList *list = coSlaves.find(slave);
    00578        if (list)
    00579        {
    00580           assert(slave->isConnected());
    00581           assert(!coIdleSlaves->contains(slave));
    00582           coIdleSlaves->append(slave);
    00583           if (!list->isEmpty())
    00584              coSlaveTimer.start(0, true);
    00585           return;
    00586        }
    00587        else
    00588        {
    00589           assert(!slave->isConnected());
    00590           idleSlaves->append(slave);
    00591           slave->setIdle();
    00592           _scheduleCleanup();
    00593 //          slave->connection()->send( CMD_SLAVE_STATUS );
    00594        }
    00595     }
    00596     if (protInfo->joblist.count())
    00597     {
    00598        slaveTimer.start(0, true);
    00599     }
    00600 }
    00601
    00602 void Scheduler::slotSlaveDied(KIO::Slave *slave)
    00603 {
    00604     assert(!slave->isAlive());
    00605     ProtocolInfo *protInfo = protInfoDict->get(slave->slaveProtocol());
    00606     protInfo->activeSlaves.removeRef(slave);
    00607     if (slave == slaveOnHold)
    00608     {
    00609        slaveOnHold = 0;
    00610        urlOnHold = KURL();
    00611     }
    00612     idleSlaves->removeRef(slave);
    00613     JobList *list = coSlaves.find(slave);
    00614     if (list)
    00615     {
    00616        // coSlave dies, kill jobs waiting in queue
    00617        disconnectSlave(slave);
    00618     }
    00619
    00620     if (!slaveList->removeRef(slave))
    00621        kdDebug(7006) << "Scheduler: BUG!! Slave died, but is NOT in slaveList!!!\n" << endl;
    00622     slave->deref(); // Delete slave
    00623 }
    00624
    00625 void Scheduler::slotCleanIdleSlaves()
    00626 {
    00627     for(Slave *slave = idleSlaves->first();slave;)
    00628     {
    00629         if (slave->idleTime() >= MAX_SLAVE_IDLE)
    00630         {
    00631            // kdDebug(7006) << "Removing idle slave: " << slave->slaveProtocol() << " " << slave->host() << endl;
    00632            Slave *removeSlave = slave;
    00633            slave = idleSlaves->next();
    00634            idleSlaves->removeRef(removeSlave);
    00635            slaveList->removeRef(removeSlave);
    00636            removeSlave->connection()->close();
    00637            removeSlave->deref();
    00638         }
    00639         else
    00640         {
    00641             slave = idleSlaves->next();
    00642         }
    00643     }
    00644     _scheduleCleanup();
    00645 }
    00646
    00647 void Scheduler::_scheduleCleanup()
    00648 {
    00649     if (idleSlaves->count())
    00650     {
    00651         if (!cleanupTimer.isActive())
    00652             cleanupTimer.start( MAX_SLAVE_IDLE*1000, true );
    00653     }
    00654 }
    00655
    00656 void Scheduler::_putSlaveOnHold(KIO::SimpleJob *job, const KURL &url)
    00657 {
    00658     Slave *slave = job->slave();
    00659     slave->disconnect(job);
    00660
    00661     if (slaveOnHold)
    00662     {
    00663         slaveOnHold->kill();
    00664     }
    00665     slaveOnHold = slave;
    00666     urlOnHold = url;
    00667     slaveOnHold->suspend();
    00668 }
    00669
    00670 void Scheduler::_publishSlaveOnHold()
    00671 {
    00672     if (!slaveOnHold)
    00673        return;
    00674
    00675     slaveOnHold->hold(urlOnHold);
    00676 }
    00677
    00678 void Scheduler::_removeSlaveOnHold()
    00679 {
    00680     if (slaveOnHold)
    00681     {
    00682         slaveOnHold->kill();
    00683     }
    00684     slaveOnHold = 0;
    00685     urlOnHold = KURL();
    00686 }
    00687
    00688 Slave *
    00689 Scheduler::_getConnectedSlave(const KURL &url, const KIO::MetaData &config )
    00690 {
    00691     QString proxy;
    00692     QString protocol = KProtocolManager::slaveProtocol(url, proxy);
    00693     bool dummy;
    00694     Slave *slave = searchIdleList(idleSlaves, url, protocol, dummy);
    00695     if (!slave)
    00696     {
    00697        ProtocolInfo *protInfo = protInfoDict->get(protocol);
    00698        slave = createSlave(protInfo, 0, url);
    00699     }
    00700     if (!slave)
    00701        return 0; // Error
    00702     idleSlaves->removeRef(slave);
    00703
    00704     setupSlave(slave, url, protocol, proxy, true, &config);
    00705
    00706     slave->connection()->send( CMD_CONNECT );
    00707     connect(slave, SIGNAL(connected()),
    00708                 SLOT(slotSlaveConnected()));
    00709     connect(slave, SIGNAL(error(int, const QString &)),
    00710                 SLOT(slotSlaveError(int, const QString &)));
    00711
    00712     coSlaves.insert(slave, new QPtrList<SimpleJob>());
    00713 //    kdDebug(7006) << "_getConnectedSlave( " << slave << ")" << endl;
    00714     return slave;
    00715 }
    00716
    00717 void
    00718 Scheduler::slotScheduleCoSlave()
    00719 {
    00720     Slave *nextSlave;
    00721     for(Slave *slave = coIdleSlaves->first();
    00722         slave;
    00723         slave = nextSlave)
    00724     {
    00725         nextSlave = coIdleSlaves->next();
    00726         JobList *list = coSlaves.find(slave);
    00727         assert(list);
    00728         if (list && !list->isEmpty())
    00729         {
    00730            SimpleJob *job = list->take(0);
    00731            coIdleSlaves->removeRef(slave);
    00732 //           kdDebug(7006) << "scheduler: job started " << job << endl;
    00733
    00734            assert(!coIdleSlaves->contains(slave));
    00735
    00736            KURL url =job->url();
    00737            QString host = url.host();
    00738            int port = url.port();
    00739
    00740            if (slave->host() == "<reset>")
    00741            {
    00742               QString user = url.user();
    00743               QString passwd = url.pass();
    00744
    00745               MetaData configData = slaveConfig->configData(url.protocol(), url.host());
    00746               slave->setConfig(configData);
    00747               slave->setProtocol(url.protocol());
    00748               slave->setHost(host, port, user, passwd);
    00749            }
    00750
    00751            assert(slave->protocol() == url.protocol());
    00752            assert(slave->host() == host);
    00753            assert(slave->port() == port);
    00754            job->start(slave);
    00755         }
    00756     }
    00757 }
    00758
    00759 void
    00760 Scheduler::slotSlaveConnected()
    00761 {
    00762     Slave *slave = (Slave *)sender();
    00763 //    kdDebug(7006) << "slotSlaveConnected( " << slave << ")" << endl;
    00764     slave->setConnected(true);
    00765     disconnect(slave, SIGNAL(connected()),
    00766                this, SLOT(slotSlaveConnected()));
    00767     emit slaveConnected(slave);
    00768     assert(!coIdleSlaves->contains(slave));
    00769     coIdleSlaves->append(slave);
    00770     coSlaveTimer.start(0, true);
    00771 }
    00772
    00773 void
    00774 Scheduler::slotSlaveError(int errorNr, const QString &errorMsg)
    00775 {
    00776     Slave *slave = (Slave *)sender();
    00777     if (!slave->isConnected() || (coIdleSlaves->find(slave) != -1))
    00778     {
    00779        // Only forward to application if slave is idle or still connecting.
    00780        emit slaveError(slave, errorNr, errorMsg);
    00781     }
    00782 }
    00783
    00784 bool
    00785 Scheduler::_assignJobToSlave(KIO::Slave *slave, SimpleJob *job)
    00786 {
    00787 //    kdDebug(7006) << "_assignJobToSlave( " << job << ", " << slave << ")" << endl;
    00788     QString dummy;
    00789     if ((slave->slaveProtocol() != KProtocolManager::slaveProtocol( job->url(), dummy ))
    00790         ||
    00791         (!newJobs.removeRef(job)))
    00792     {
    00793         kdDebug(7006) << "_assignJobToSlave(): ERROR, nonmatching or unknown job." << endl;
    00794         job->kill();
    00795         return false;
    00796     }
    00797
    00798     JobList *list = coSlaves.find(slave);
    00799     assert(list);
    00800     if (!list)
    00801     {
    00802         kdDebug(7006) << "_assignJobToSlave(): ERROR, unknown slave." << endl;
    00803         job->kill();
    00804         return false;
    00805     }
    00806
    00807     assert(list->contains(job) == 0);
    00808     list->append(job);
    00809     coSlaveTimer.start(0, true); // Start job on timer event
    00810
    00811     return true;
    00812 }
    00813
    00814 bool
    00815 Scheduler::_disconnectSlave(KIO::Slave *slave)
    00816 {
    00817 //    kdDebug(7006) << "_disconnectSlave( " << slave << ")" << endl;
    00818     JobList *list = coSlaves.take(slave);
    00819     assert(list);
    00820     if (!list)
    00821        return false;
    00822     // Kill jobs still in queue.
    00823     while(!list->isEmpty())
    00824     {
    00825        Job *job = list->take(0);
    00826        job->kill();
    00827     }
    00828     delete list;
    00829     coIdleSlaves->removeRef(slave);
    00830     assert(!coIdleSlaves->contains(slave));
    00831     disconnect(slave, SIGNAL(connected()),
    00832                this, SLOT(slotSlaveConnected()));
    00833     disconnect(slave, SIGNAL(error(int, const QString &)),
    00834                this, SLOT(slotSlaveError(int, const QString &)));
    00835     if (slave->isAlive())
    00836     {
    00837        idleSlaves->append(slave);
    00838        slave->connection()->send( CMD_DISCONNECT );
    00839        slave->setIdle();
    00840        slave->setConnected(false);
    00841        _scheduleCleanup();
    00842     }
    00843     return true;
    00844 }
    00845
    00846 void
    00847 Scheduler::_checkSlaveOnHold(bool b)
    00848 {
    00849     checkOnHold = b;
    00850 }
    00851
    00852 void
    00853 Scheduler::_registerWindow(QWidget *wid)
    00854 {
    00855    if (!wid)
    00856       return;
    00857
    00858    QObject *obj = static_cast<QObject *>(wid);
    00859    if (!m_windowList.contains(obj))
    00860    {
    00861       // We must store the window Id because by the time
    00862       // the destroyed signal is emitted we can no longer
    00863       // access QWidget::winId() (already destructed)
    00864       long windowId = wid->winId();
    00865       m_windowList.insert(obj, windowId);
    00866       connect(wid, SIGNAL(destroyed(QObject *)),
    00867               this, SLOT(slotUnregisterWindow(QObject*)));
    00868       QByteArray params;
    00869       QDataStream stream(params, IO_WriteOnly);
    00870       stream << windowId;
    00871       if( !kapp->dcopClient()->send( "kded", "kded",
    00872                     "registerWindowId(long int)", params ) )
    00873       kdDebug(7006) << "Could not register window with kded!" << endl;
    00874    }
    00875 }
    00876
    00877 void
    00878 Scheduler::slotUnregisterWindow(QObject *obj)
    00879 {
    00880    if (!obj)
    00881       return;
    00882
    00883    QMap<QObject *, long>::Iterator it = m_windowList.find(obj);
    00884    if (it == m_windowList.end())
    00885       return;
    00886    long windowId = it.data();
    00887    if (kapp)
    00888    {
    00889       QByteArray params;
    00890       QDataStream stream(params, IO_WriteOnly);
    00891       stream << windowId;
    00892       kapp->dcopClient()->send( "kded", "kded",
    00893                     "unregisterWindowId(long int)", params );
    00894    }
    00895 }
    00896
    00897 Scheduler* Scheduler::self() {
    00898     if ( !instance ) {
    00899         instance = new Scheduler;
    00900     }
    00901     return instance;
    00902 }
    00903
    00904 void Scheduler::virtual_hook( int id, void* data )
    00905 { DCOPObject::virtual_hook( id, data ); }
    00906
    00907
    00908
    00909 #include "scheduler.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:14:37 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001