kio Library: scheduler.cpp Source File (kio Library)

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

# scheduler.cpp

    00001 /* This file is part of the KDE libraries
    00002    Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
    00003                       Waldo Bastian <bastian@kde.org>
    00004
    00005    This library is free software; you can redistribute it and/or
    00006    modify it under the terms of the GNU Library General Public
    00007    License version 2 as published by the Free Software Foundation.
    00008
    00009    This library is distributed in the hope that it will be useful,
    00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00012    Library General Public License for more details.
    00013
    00014    You should have received a copy of the GNU Library General Public License
    00015    along with this library; see the file COPYING.LIB.  If not, write to
    00016    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00017    Boston, MA 02111-1307, USA.
    00018 */
    00019
    00020 #include "kio/sessiondata.h"
    00021 #include "kio/slaveconfig.h"
    00022 #include "kio/scheduler.h"
    00023 #include "kio/authinfo.h"
    00024 #include "kio/slave.h"
    00025 #include <qptrlist.h>
    00026 #include <qdict.h>
    00027
    00028 #include <dcopclient.h>
    00029
    00030 #include <kdebug.h>
    00031 #include <kglobal.h>
    00032 #include <kprotocolmanager.h>
    00033 #include <kprotocolinfo.h>
    00034 #include <assert.h>
    00035 #include <kstaticdeleter.h>
    00036 #include <kdesu/client.h>
    00037
    00038
    00039 // Slaves may be idle for MAX_SLAVE_IDLE time before they are being returned
    00040 // to the system wide slave pool. (3 minutes)
    00041 #define MAX_SLAVE_IDLE (3*60)
    00042
    00043 using namespace KIO;
    00044
    00045 template class QDict<KIO::Scheduler::ProtocolInfo>;
    00046
    00047 Scheduler *Scheduler::instance = 0;
    00048
    00049 class KIO::SlaveList: public QPtrList<Slave>
    00050 {
    00051    public:
    00052       SlaveList() { }
    00053 };
    00054
    00055 //
    00056 // There are two kinds of protocol:
    00057 // (1) The protocol of the url
    00058 // (2) The actual protocol that the io-slave uses.
    00059 //
    00060 // These two often match, but not necasserily. Most notably, they don't
    00061 // match when doing ftp via a proxy.
    00062 // In that case (1) is ftp, but (2) is http.
    00063 //
    00064 // JobData::protocol stores (2) while Job::url().protocol() returns (1).
    00065 // The ProtocolInfoDict is indexed with (2).
    00066 //
    00067 // We schedule slaves based on (2) but tell the slave about (1) via
    00068 // Slave::setProtocol().
    00069
    00070 class KIO::Scheduler::JobData
    00071 {
    00072 public:
    00073     JobData() : checkOnHold(false) { }
    00074
    00075 public:
    00076     QString protocol;
    00077     QString proxy;
    00078     bool checkOnHold;
    00079 };
    00080
    00081 class KIO::Scheduler::ExtraJobData: public QPtrDict<KIO::Scheduler::JobData>
    00082 {
    00083 public:
    00084     ExtraJobData() { setAutoDelete(true); }
    00085 };
    00086
    00087 class KIO::Scheduler::ProtocolInfo
    00088 {
    00089 public:
    00090     ProtocolInfo() : maxSlaves(1), skipCount(0)
    00091     {
    00092        joblist.setAutoDelete(false);
    00093     }
    00094
    00095     QPtrList<SimpleJob> joblist;
    00096     SlaveList activeSlaves;
    00097     int maxSlaves;
    00098     int skipCount;
    00099     QString protocol;
    00100 };
    00101
    00102 class KIO::Scheduler::ProtocolInfoDict : public QDict<KIO::Scheduler::ProtocolInfo>
    00103 {
    00104   public:
    00105     ProtocolInfoDict() { }
    00106
    00107     KIO::Scheduler::ProtocolInfo *get( const QString &protocol);
    00108 };
    00109
    00110 KIO::Scheduler::ProtocolInfo *
    00111 KIO::Scheduler::ProtocolInfoDict::get(const QString &protocol)
    00112 {
    00113     ProtocolInfo *info = find(protocol);
    00114     if (!info)
    00115     {
    00116         info = new ProtocolInfo;
    00117         info->protocol = protocol;
    00118         info->maxSlaves = KProtocolInfo::maxSlaves( protocol );
    00119
    00120         insert(protocol, info);
    00121     }
    00122     return info;
    00123 }
    00124
    00125
    00126 Scheduler::Scheduler()
    00127           : 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"

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:24:07 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003