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