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           : DCOPObject( "KIO::Scheduler" ),
00128            QObject(kapp, "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->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 #ifndef NDEBUG
00212     if (newJobs.count() > 150)
00213     kdDebug() << "WARNING - KIO::Scheduler got more than 150 jobs! This shows a misuse in your app (yes, a job is a QObject)." << endl;
00214 #endif
00215 }
00216 
00217 void Scheduler::_scheduleJob(SimpleJob *job) {
00218     newJobs.removeRef(job);
00219     JobData *jobData = extraJobData->find(job);
00220     if (!jobData)
00221 {
00222     kdFatal(7006) << "BUG! _ScheduleJob(): No extraJobData for job!" << endl;
00223     return;
00224 }
00225     QString protocol = jobData->protocol;
00226 //    kdDebug(7006) << "Scheduler::_scheduleJob protocol=" << protocol << endl;
00227     ProtocolInfo *protInfo = protInfoDict->get(protocol);
00228     protInfo->joblist.append(job);
00229     
00230     slaveTimer.start(0, true);
00231 }
00232 
00233 void Scheduler::_cancelJob(SimpleJob *job) {
00234 //    kdDebug(7006) << "Scheduler: canceling job " << job << endl;
00235     Slave *slave = job->slave();
00236     if ( !slave  )
00237     {
00238         // was not yet running (don't call this on a finished job!)
00239         JobData *jobData = extraJobData->find(job);
00240         if (!jobData)
00241            return; // I said: "Don't call this on a finished job!"
00242 
00243         newJobs.removeRef(job);
00244         ProtocolInfo *protInfo = protInfoDict->get(jobData->protocol);
00245         protInfo->joblist.removeRef(job);
00246 
00247         // Search all slaves to see if job is in the queue of a coSlave
00248         slave = slaveList->first();
00249         for(; slave; slave = slaveList->next())
00250         {
00251            JobList *list = coSlaves.find(slave);
00252            if (list && list->removeRef(job))
00253               break; // Job was found and removed.
00254                      // Fall through to kill the slave as well!
00255         }
00256         if (!slave)
00257         {
00258            extraJobData->remove(job);
00259            return; // Job was not yet running and not in a coSlave queue.
00260         }
00261     }
00262     kdDebug(7006) << "Scheduler: killing slave " << slave->slave_pid() << endl;
00263     slave->kill();
00264     _jobFinished( job, slave );
00265     slotSlaveDied( slave);
00266 }
00267 
00268 void Scheduler::startStep()
00269 {
00270     while(newJobs.count())
00271     {
00272        (void) startJobDirect();
00273     }
00274     QDictIterator<KIO::Scheduler::ProtocolInfo> it(*protInfoDict);
00275     while(it.current())
00276     {
00277        if (startJobScheduled(it.current())) return;
00278        ++it;
00279     }
00280 }
00281 
00282 void Scheduler::setupSlave(KIO::Slave *slave, const KURL &url, const QString &protocol, const QString &proxy , bool newSlave, const KIO::MetaData *config)
00283 {
00284     QString host = url.host();
00285     int port = url.port();
00286     QString user = url.user();
00287     QString passwd = url.pass();
00288 
00289     if ((newSlave) ||
00290         (slave->host() != host) ||
00291         (slave->port() != port) ||
00292         (slave->user() != user) ||
00293         (slave->passwd() != passwd))
00294     {
00295         MetaData configData = slaveConfig->configData(protocol, host);
00296         sessionData->configDataFor( configData, protocol, host );
00297        
00298         configData["UseProxy"] = proxy; 
00299 
00300         QString autoLogin = configData["EnableAutoLogin"].lower();
00301         if ( autoLogin == "true" )
00302         {
00303             NetRC::AutoLogin l;
00304             l.login = user;
00305             bool usern = (protocol == "ftp");
00306             if ( NetRC::self()->lookup( url, l, usern) )
00307             {
00308                 configData["autoLoginUser"] = l.login;
00309                 configData["autoLoginPass"] = l.password;
00310                 if ( usern )
00311                 {
00312                     QString macdef;
00313                     QMap<QString, QStringList>::ConstIterator it = l.macdef.begin();
00314                     for ( ; it != l.macdef.end(); ++it )
00315                         macdef += it.key() + '\\' + it.data().join( "\\" ) + '\n';
00316                     configData["autoLoginMacro"] = macdef;
00317                 }
00318             }
00319         }
00320         if (config)
00321            configData += *config;
00322         slave->setConfig(configData);
00323         slave->setProtocol(url.protocol());
00324         slave->setHost(host, port, user, passwd);
00325     }
00326 }
00327 
00328 bool Scheduler::startJobScheduled(ProtocolInfo *protInfo)
00329 {
00330     if (protInfo->joblist.isEmpty())
00331        return false;
00332 
00333 //       kdDebug(7006) << "Scheduling job" << endl;
00334     debug_info();
00335     bool newSlave = false;
00336 
00337     SimpleJob *job = 0;
00338     Slave *slave = 0;
00339 
00340     if (protInfo->skipCount > 2)
00341     {
00342        bool dummy;
00343        // Prevent starvation. We skip the first entry in the queue at most
00344        // 2 times in a row. The
00345        protInfo->skipCount = 0;
00346        job = protInfo->joblist.at(0);
00347        slave = findIdleSlave(protInfo, job, dummy );
00348     }
00349     else
00350     {
00351        bool exact=false;
00352        SimpleJob *firstJob = 0;
00353        Slave *firstSlave = 0;
00354        for(uint i = 0; (i < protInfo->joblist.count()) && (i < 10); i++)
00355        {
00356           job = protInfo->joblist.at(i);
00357           slave = findIdleSlave(protInfo, job, exact);
00358           if (!firstSlave)
00359           {
00360              firstJob = job;
00361              firstSlave = slave;
00362           }
00363           if (!slave) break;
00364           if (exact) break;
00365        }
00366 
00367        if (!exact)
00368        {
00369          slave = firstSlave;
00370          job = firstJob;
00371        }
00372        if (job == firstJob)
00373          protInfo->skipCount = 0;
00374        else
00375          protInfo->skipCount++;
00376     }
00377 
00378     if (!slave)
00379     {
00380        if ( protInfo->maxSlaves > static_cast<int>(protInfo->activeSlaves.count()) )
00381        {
00382           newSlave = true;
00383           slave = createSlave(protInfo, job, job->url());
00384           if (!slave)
00385              slaveTimer.start(0, true);
00386        }
00387     }
00388 
00389     if (!slave)
00390     {
00391 //          kdDebug(7006) << "No slaves available" << endl;
00392 //          kdDebug(7006) << " -- active: " << protInfo->activeSlaves.count() << endl;
00393        return false;
00394     }
00395 
00396     protInfo->activeSlaves.append(slave);
00397     idleSlaves->removeRef(slave);
00398     protInfo->joblist.removeRef(job);
00399 //       kdDebug(7006) << "scheduler: job started " << job << endl;
00400 
00401     
00402     JobData *jobData = extraJobData->find(job);
00403     setupSlave(slave, job->url(), jobData->protocol, jobData->proxy, newSlave);
00404     job->start(slave);
00405 
00406     slaveTimer.start(0, true);
00407     return true;
00408 }
00409 
00410 bool Scheduler::startJobDirect()
00411 {
00412     debug_info();
00413     SimpleJob *job = newJobs.take(0);
00414     JobData *jobData = extraJobData->find(job);
00415 if (!jobData)
00416 {
00417         kdFatal(7006) << "BUG! startjobDirect(): No extraJobData for job!"
00418                       << endl;
00419     return false;
00420 }
00421     QString protocol = jobData->protocol;
00422     ProtocolInfo *protInfo = protInfoDict->get(protocol);
00423 
00424     bool newSlave = false;
00425     bool dummy;
00426 
00427     // Look for matching slave
00428     Slave *slave = findIdleSlave(protInfo, job, dummy);
00429 
00430     if (!slave)
00431     {
00432        newSlave = true;
00433        slave = createSlave(protInfo, job, job->url());
00434     }
00435 
00436     if (!slave)
00437        return false;
00438 
00439     idleSlaves->removeRef(slave);
00440 //       kdDebug(7006) << "scheduler: job started " << job << endl;
00441 
00442     setupSlave(slave, job->url(), protocol, jobData->proxy, newSlave);
00443     job->start(slave);
00444     return true;
00445 }
00446 
00447 static Slave *searchIdleList(SlaveList *idleSlaves, const KURL &url, const QString &protocol, bool &exact)
00448 {
00449     QString host = url.host();
00450     int port = url.port();
00451     QString user = url.user();
00452     exact = true;
00453 
00454     for( Slave *slave = idleSlaves->first();
00455          slave;
00456          slave = idleSlaves->next())
00457     {
00458        if ((protocol == slave->slaveProtocol()) &&
00459            (host == slave->host()) &&
00460            (port == slave->port()) &&
00461            (user == slave->user()))
00462            return slave;
00463     }
00464 
00465     exact = false;
00466 
00467     // Look for slightly matching slave
00468     for( Slave *slave = idleSlaves->first();
00469          slave;
00470          slave = idleSlaves->next())
00471     {
00472        if (protocol == slave->slaveProtocol())
00473           return slave;
00474     }
00475     return 0;
00476 }
00477 
00478 Slave *Scheduler::findIdleSlave(ProtocolInfo *, SimpleJob *job, bool &exact)
00479 {
00480     Slave *slave = 0;
00481     JobData *jobData = extraJobData->find(job);
00482 if (!jobData)
00483 {
00484     kdFatal(7006) << "BUG! findIdleSlave(): No extraJobData for job!" << endl;
00485     return 0;
00486 }
00487     if (jobData->checkOnHold)
00488     {
00489        slave = Slave::holdSlave(jobData->protocol, job->url());
00490        if (slave)
00491           return slave;
00492     }
00493     if (slaveOnHold)
00494     {
00495        // Make sure that the job wants to do a GET or a POST, and with no offset
00496        bool bCanReuse = (job->command() == CMD_GET);
00497        KIO::TransferJob * tJob = dynamic_cast<KIO::TransferJob *>(job);
00498        if ( tJob )
00499        {
00500           bCanReuse = (job->command() == CMD_GET || job->command() == CMD_SPECIAL);
00501           if ( bCanReuse )
00502           {
00503             KIO::MetaData outgoing = tJob->outgoingMetaData();
00504             QString resume = (!outgoing.contains("resume")) ? QString::null : outgoing["resume"];
00505             kdDebug(7006) << "Resume metadata is '" << resume << "'" << endl;
00506             bCanReuse = (resume.isEmpty() || resume == "0");
00507           }
00508        }
00509 //       kdDebug(7006) << "bCanReuse = " << bCanReuse << endl;
00510        if (bCanReuse)
00511        {
00512           if (job->url() == urlOnHold)
00513           {
00514              kdDebug(7006) << "HOLD: Reusing held slave for " << urlOnHold.prettyURL() << endl;
00515              slave = slaveOnHold;
00516           }
00517           else
00518           {
00519              kdDebug(7006) << "HOLD: Discarding held slave (" << urlOnHold.prettyURL() << ")" << endl;
00520              slaveOnHold->kill();
00521           }
00522           slaveOnHold = 0;
00523           urlOnHold = KURL();
00524        }
00525        if (slave)
00526           return slave;
00527     }
00528 
00529     return searchIdleList(idleSlaves, job->url(), jobData->protocol, exact);
00530 }
00531 
00532 Slave *Scheduler::createSlave(ProtocolInfo *protInfo, SimpleJob *job, const KURL &url)
00533 {
00534    int error;
00535    QString errortext;
00536    Slave *slave = Slave::createSlave(protInfo->protocol, url, error, errortext);
00537    if (slave)
00538    {
00539       slaveList->append(slave);
00540       idleSlaves->append(slave);
00541       connect(slave, SIGNAL(slaveDied(KIO::Slave *)),
00542                 SLOT(slotSlaveDied(KIO::Slave *)));
00543       connect(slave, SIGNAL(slaveStatus(pid_t,const QCString &,const QString &, bool)),
00544                 SLOT(slotSlaveStatus(pid_t,const QCString &, const QString &, bool)));
00545 
00546       connect(slave,SIGNAL(authorizationKey(const QCString&, const QCString&, bool)),
00547               sessionData,SLOT(slotAuthData(const QCString&, const QCString&, bool)));
00548       connect(slave,SIGNAL(delAuthorization(const QCString&)), sessionData,
00549               SLOT(slotDelAuthData(const QCString&)));
00550    }
00551    else
00552    {
00553       kdError() << "ERROR " << error << ": couldn't create slave : "
00554                 << errortext << endl;
00555       if (job)
00556       {
00557          protInfo->joblist.removeRef(job);
00558          extraJobData->remove(job);
00559          job->slotError( error, errortext );
00560       }
00561    }
00562    return slave;
00563 }
00564 
00565 void Scheduler::slotSlaveStatus(pid_t, const QCString &, const QString &, bool) 
00566 {
00567 }
00568 
00569 void Scheduler::_jobFinished(SimpleJob *job, Slave *slave)
00570 {
00571     JobData *jobData = extraJobData->take(job);
00572 if (!jobData)
00573 {
00574     kdFatal(7006) << "BUG! _jobFinished(): No extraJobData for job!" << endl;
00575     return;
00576 }
00577     ProtocolInfo *protInfo = protInfoDict->get(jobData->protocol);
00578     delete jobData;
00579     slave->disconnect(job);
00580     protInfo->activeSlaves.removeRef(slave);
00581     if (slave->isAlive())
00582     {
00583        JobList *list = coSlaves.find(slave);
00584        if (list)
00585        {
00586           assert(slave->isConnected());
00587           assert(!coIdleSlaves->contains(slave));
00588           coIdleSlaves->append(slave);
00589           if (!list->isEmpty())
00590              coSlaveTimer.start(0, true);
00591           return;
00592        }
00593        else
00594        {
00595           assert(!slave->isConnected());
00596           idleSlaves->append(slave);
00597           slave->setIdle();
00598           _scheduleCleanup();
00599 //          slave->send( CMD_SLAVE_STATUS );
00600        }
00601     }
00602     if (protInfo->joblist.count())
00603     {
00604        slaveTimer.start(0, true);
00605     }
00606 }
00607 
00608 void Scheduler::slotSlaveDied(KIO::Slave *slave)
00609 {
00610     assert(!slave->isAlive());
00611     ProtocolInfo *protInfo = protInfoDict->get(slave->slaveProtocol());
00612     protInfo->activeSlaves.removeRef(slave);
00613     if (slave == slaveOnHold)
00614     {
00615        slaveOnHold = 0;
00616        urlOnHold = KURL();
00617     }
00618     idleSlaves->removeRef(slave);
00619     JobList *list = coSlaves.find(slave);
00620     if (list)
00621     {
00622        // coSlave dies, kill jobs waiting in queue
00623        disconnectSlave(slave);
00624     }
00625 
00626     if (!slaveList->removeRef(slave))
00627        kdDebug(7006) << "Scheduler: BUG!! Slave died, but is NOT in slaveList!!!\n" << endl;
00628     slave->deref(); // Delete slave
00629 }
00630 
00631 void Scheduler::slotCleanIdleSlaves()
00632 {
00633     for(Slave *slave = idleSlaves->first();slave;)
00634     {
00635         if (slave->idleTime() >= MAX_SLAVE_IDLE)
00636         {
00637            // kdDebug(7006) << "Removing idle slave: " << slave->slaveProtocol() << " " << slave->host() << endl;
00638            Slave *removeSlave = slave;
00639            slave = idleSlaves->next();
00640            idleSlaves->removeRef(removeSlave);
00641            slaveList->removeRef(removeSlave);
00642            removeSlave->connection()->close();
00643            removeSlave->deref();
00644         }
00645         else
00646         {
00647             slave = idleSlaves->next();
00648         }
00649     }
00650     _scheduleCleanup();
00651 }
00652 
00653 void Scheduler::_scheduleCleanup()
00654 {
00655     if (idleSlaves->count())
00656     {
00657         if (!cleanupTimer.isActive())
00658             cleanupTimer.start( MAX_SLAVE_IDLE*1000, true );
00659     }
00660 }
00661 
00662 void Scheduler::_putSlaveOnHold(KIO::SimpleJob *job, const KURL &url)
00663 {
00664     Slave *slave = job->slave();
00665     slave->disconnect(job);
00666 
00667     if (slaveOnHold)
00668     {
00669         slaveOnHold->kill();
00670     }
00671     slaveOnHold = slave;
00672     urlOnHold = url;
00673     slaveOnHold->suspend();
00674 }
00675 
00676 void Scheduler::_publishSlaveOnHold()
00677 {
00678     if (!slaveOnHold)
00679        return;
00680 
00681     slaveOnHold->hold(urlOnHold);
00682 }
00683 
00684 void Scheduler::_removeSlaveOnHold()
00685 {
00686     if (slaveOnHold)
00687     {
00688         slaveOnHold->kill();
00689     }
00690     slaveOnHold = 0;
00691     urlOnHold = KURL();
00692 }
00693 
00694 Slave *
00695 Scheduler::_getConnectedSlave(const KURL &url, const KIO::MetaData &config )
00696 {
00697     QString proxy;
00698     QString protocol = KProtocolManager::slaveProtocol(url, proxy);
00699     bool dummy;
00700     Slave *slave = searchIdleList(idleSlaves, url, protocol, dummy);
00701     if (!slave)
00702     {
00703        ProtocolInfo *protInfo = protInfoDict->get(protocol);
00704        slave = createSlave(protInfo, 0, url);
00705     }
00706     if (!slave)
00707        return 0; // Error
00708     idleSlaves->removeRef(slave);
00709 
00710     setupSlave(slave, url, protocol, proxy, true, &config);
00711 
00712     slave->send( CMD_CONNECT );
00713     connect(slave, SIGNAL(connected()),
00714                 SLOT(slotSlaveConnected()));
00715     connect(slave, SIGNAL(error(int, const QString &)),
00716                 SLOT(slotSlaveError(int, const QString &)));
00717 
00718     coSlaves.insert(slave, new QPtrList<SimpleJob>());
00719 //    kdDebug(7006) << "_getConnectedSlave( " << slave << ")" << endl;
00720     return slave;
00721 }
00722 
00723 void
00724 Scheduler::slotScheduleCoSlave()
00725 {
00726     Slave *nextSlave;
00727     for(Slave *slave = coIdleSlaves->first();
00728         slave;
00729         slave = nextSlave)
00730     {
00731         nextSlave = coIdleSlaves->next();
00732         JobList *list = coSlaves.find(slave);
00733         assert(list);
00734         if (list && !list->isEmpty())
00735         {
00736            SimpleJob *job = list->take(0);
00737            coIdleSlaves->removeRef(slave);
00738 //           kdDebug(7006) << "scheduler: job started " << job << endl;
00739 
00740            assert(!coIdleSlaves->contains(slave));
00741 
00742            KURL url =job->url();
00743            QString host = url.host();
00744            int port = url.port();
00745 
00746            if (slave->host() == "<reset>")
00747            {
00748               QString user = url.user();
00749               QString passwd = url.pass();
00750 
00751               MetaData configData = slaveConfig->configData(url.protocol(), url.host());
00752               slave->setConfig(configData);
00753               slave->setProtocol(url.protocol());
00754               slave->setHost(host, port, user, passwd);
00755            }
00756 
00757            assert(slave->protocol() == url.protocol());
00758            assert(slave->host() == host);
00759            assert(slave->port() == port);
00760            job->start(slave);
00761         }
00762     }
00763 }
00764 
00765 void
00766 Scheduler::slotSlaveConnected()
00767 {
00768     Slave *slave = (Slave *)sender();
00769 //    kdDebug(7006) << "slotSlaveConnected( " << slave << ")" << endl;
00770     slave->setConnected(true);
00771     disconnect(slave, SIGNAL(connected()),
00772                this, SLOT(slotSlaveConnected()));
00773     emit slaveConnected(slave);
00774     assert(!coIdleSlaves->contains(slave));
00775     coIdleSlaves->append(slave);
00776     coSlaveTimer.start(0, true);
00777 }
00778 
00779 void
00780 Scheduler::slotSlaveError(int errorNr, const QString &errorMsg)
00781 {
00782     Slave *slave = (Slave *)sender();
00783     if (!slave->isConnected() || (coIdleSlaves->find(slave) != -1))
00784     {
00785        // Only forward to application if slave is idle or still connecting.
00786        emit slaveError(slave, errorNr, errorMsg);
00787     }
00788 }
00789 
00790 bool
00791 Scheduler::_assignJobToSlave(KIO::Slave *slave, SimpleJob *job)
00792 {
00793 //    kdDebug(7006) << "_assignJobToSlave( " << job << ", " << slave << ")" << endl;
00794     QString dummy;
00795     if ((slave->slaveProtocol() != KProtocolManager::slaveProtocol( job->url(), dummy ))
00796         ||
00797         (!newJobs.removeRef(job)))
00798     {
00799         kdDebug(7006) << "_assignJobToSlave(): ERROR, nonmatching or unknown job." << endl;
00800         job->kill();
00801         return false;
00802     }
00803 
00804     JobList *list = coSlaves.find(slave);
00805     assert(list);
00806     if (!list)
00807     {
00808         kdDebug(7006) << "_assignJobToSlave(): ERROR, unknown slave." << endl;
00809         job->kill();
00810         return false;
00811     }
00812 
00813     assert(list->contains(job) == 0);
00814     list->append(job);
00815     coSlaveTimer.start(0, true); // Start job on timer event
00816 
00817     return true;
00818 }
00819 
00820 bool
00821 Scheduler::_disconnectSlave(KIO::Slave *slave)
00822 {
00823 //    kdDebug(7006) << "_disconnectSlave( " << slave << ")" << endl;
00824     JobList *list = coSlaves.take(slave);
00825     assert(list);
00826     if (!list)
00827        return false;
00828     // Kill jobs still in queue.
00829     while(!list->isEmpty())
00830     {
00831        Job *job = list->take(0);
00832        job->kill();
00833     }
00834     delete list;
00835     coIdleSlaves->removeRef(slave);
00836     assert(!coIdleSlaves->contains(slave));
00837     disconnect(slave, SIGNAL(connected()),
00838                this, SLOT(slotSlaveConnected()));
00839     disconnect(slave, SIGNAL(error(int, const QString &)),
00840                this, SLOT(slotSlaveError(int, const QString &)));
00841     if (slave->isAlive())
00842     {
00843        idleSlaves->append(slave);
00844        slave->send( CMD_DISCONNECT );
00845        slave->setIdle();
00846        slave->setConnected(false);
00847        _scheduleCleanup();
00848     }
00849     return true;
00850 }
00851 
00852 void 
00853 Scheduler::_checkSlaveOnHold(bool b)
00854 {
00855     checkOnHold = b;
00856 }
00857 
00858 void
00859 Scheduler::_registerWindow(QWidget *wid)
00860 {
00861    if (!wid)
00862       return;
00863 
00864    QObject *obj = static_cast<QObject *>(wid);
00865    if (!m_windowList.contains(obj))
00866    {
00867       // We must store the window Id because by the time
00868       // the destroyed signal is emitted we can no longer
00869       // access QWidget::winId() (already destructed)
00870       long windowId = wid->winId();
00871       m_windowList.insert(obj, windowId);
00872       connect(wid, SIGNAL(destroyed(QObject *)),
00873               this, SLOT(slotUnregisterWindow(QObject*)));
00874       QByteArray params;
00875       QDataStream stream(params, IO_WriteOnly);
00876       stream << windowId;
00877       if( !kapp->dcopClient()->send( "kded", "kded",
00878                     "registerWindowId(long int)", params ) )
00879       kdDebug(7006) << "Could not register window with kded!" << endl;
00880    }
00881 }
00882 
00883 void
00884 Scheduler::slotUnregisterWindow(QObject *obj)
00885 {
00886    if (!obj)
00887       return;
00888 
00889    QMap<QObject *, long>::Iterator it = m_windowList.find(obj);
00890    if (it == m_windowList.end())
00891       return;
00892    long windowId = it.data();
00893    disconnect( it.key(), SIGNAL(destroyed(QObject *)),
00894               this, SLOT(slotUnregisterWindow(QObject*)));
00895    m_windowList.remove( it );
00896    if (kapp)
00897    {
00898       QByteArray params;
00899       QDataStream stream(params, IO_WriteOnly);
00900       stream << windowId;
00901       kapp->dcopClient()->send( "kded", "kded",
00902                     "unregisterWindowId(long int)", params );
00903    }
00904 }
00905 
00906 Scheduler* Scheduler::self() {
00907     if ( !instance ) {
00908         instance = new Scheduler;
00909     }
00910     return instance;
00911 }
00912 
00913 void Scheduler::virtual_hook( int id, void* data )
00914 { DCOPObject::virtual_hook( id, data ); }
00915 
00916 
00917 
00918 #include "scheduler.moc"
KDE Logo
This file is part of the documentation for kio Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 14 09:17:14 2006 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003