kio Library API Documentation

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"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:15:33 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001