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.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 10 18:55:29 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003