You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdelibs/tdeio/tdeio/scheduler.h

365 lines
13 KiB

// -*- c++ -*-
/* This file is part of the KDE libraries
Copyright (C) 2000 Stephan Kulow <coolo@kde.org>
Waldo Bastian <bastian@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef _tdeio_scheduler_h
#define _tdeio_scheduler_h
#include "tdeio/job.h"
#include "tdeio/jobclasses.h"
#include <tqtimer.h>
#include <tqptrdict.h>
#include <tqmap.h>
#include <dcopobject.h>
namespace TDEIO {
class Slave;
class SlaveList;
class SlaveConfig;
class SessionData;
/**
* The TDEIO::Scheduler manages io-slaves for the application.
* It also queues jobs and assigns the job to a slave when one
* becomes available.
*
* There are 3 possible ways for a job to get a slave:
*
* <h3>1. Direct</h3>
* This is the default. When you create a job the
* TDEIO::Scheduler will be notified and will find either an existing
* slave that is idle or it will create a new slave for the job.
*
* Example:
* \code
* TransferJob *job = TDEIO::get(KURL("http://www.kde.org"));
* \endcode
*
*
* <h3>2. Scheduled</h3>
* If you create a lot of jobs, you might want not want to have a
* slave for each job. If you schedule a job, a maximum number
* of slaves will be created. When more jobs arrive, they will be
* queued. When a slave is finished with a job, it will be assigned
* a job from the queue.
*
* Example:
* \code
* TransferJob *job = TDEIO::get(KURL("http://www.kde.org"));
* TDEIO::Scheduler::scheduleJob(job);
* \endcode
*
* <h3>3. Connection Oriented</h3>
* For some operations it is important that multiple jobs use
* the same connection. This can only be ensured if all these jobs
* use the same slave.
*
* You can ask the scheduler to open a slave for connection oriented
* operations. You can then use the scheduler to assign jobs to this
* slave. The jobs will be queued and the slave will handle these jobs
* one after the other.
*
* Example:
* \code
* Slave *slave = TDEIO::Scheduler::getConnectedSlave(
* KURL("pop3://bastian:password@mail.kde.org"));
* TransferJob *job1 = TDEIO::get(
* KURL("pop3://bastian:password@mail.kde.org/msg1"));
* TDEIO::Scheduler::assignJobToSlave(slave, job1);
* TransferJob *job2 = TDEIO::get(
* KURL("pop3://bastian:password@mail.kde.org/msg2"));
* TDEIO::Scheduler::assignJobToSlave(slave, job2);
* TransferJob *job3 = TDEIO::get(
* KURL("pop3://bastian:password@mail.kde.org/msg3"));
* TDEIO::Scheduler::assignJobToSlave(slave, job3);
*
* // ... Wait for jobs to finish...
*
* TDEIO::Scheduler::disconnectSlave(slave);
* \endcode
*
* Note that you need to explicitly disconnect the slave when the
* connection goes down, so your error handler should contain:
* \code
* if (error == TDEIO::ERR_CONNECTION_BROKEN)
* TDEIO::Scheduler::disconnectSlave(slave);
* \endcode
*
* @see TDEIO::Slave
* @see TDEIO::Job
**/
class TDEIO_EXPORT Scheduler : public TQObject, virtual public DCOPObject {
Q_OBJECT
public:
typedef TQPtrList<SimpleJob> JobList;
// InfoDict needs Info, so we can't declare it private
class ProtocolInfo;
class JobData;
~Scheduler();
/**
* Register @p job with the scheduler.
* The default is to create a new slave for the job if no slave
* is available. This can be changed by calling scheduleJob.
* @param job the job to register
*/
static void doJob(SimpleJob *job)
{ self()->_doJob(job); }
/**
* Calling ths function makes that @p job gets scheduled for later
* execution, if multiple jobs are registered it might wait for
* other jobs to finish.
* @param job the job to schedule
*/
static void scheduleJob(SimpleJob *job)
{ self()->_scheduleJob(job); }
/**
* Stop the execution of a job.
* @param job the job to cancel
*/
static void cancelJob(SimpleJob *job)
{ self()->_cancelJob(job); }
/**
* Called when a job is done.
* @param job the finished job
* @param slave the slave that executed the @p job
*/
static void jobFinished(TDEIO::SimpleJob *job, TDEIO::Slave *slave)
{ self()->_jobFinished(job, slave); }
/**
* Puts a slave on notice. A next job may reuse this slave if it
* requests the same URL.
*
* A job can be put on hold after it has emit'ed its mimetype.
* Based on the mimetype, the program can give control to another
* component in the same process which can then resume the job
* by simply asking for the same URL again.
* @param job the job that should be stopped
* @param url the URL that is handled by the @p url
*/
static void putSlaveOnHold(TDEIO::SimpleJob *job, const KURL &url)
{ self()->_putSlaveOnHold(job, url); }
/**
* Removes any slave that might have been put on hold. If a slave
* was put on hold it will be killed.
*/
static void removeSlaveOnHold()
{ self()->_removeSlaveOnHold(); }
/**
* Send the slave that was put on hold back to TDELauncher. This
* allows another process to take over the slave and resume the job
* that was started.
*/
static void publishSlaveOnHold()
{ self()->_publishSlaveOnHold(); }
/**
* Requests a slave for use in connection-oriented mode.
*
* @param url This defines the username,password,host & port to
* connect with.
* @param config Configuration data for the slave.
*
* @return A pointer to a connected slave or 0 if an error occurred.
* @see assignJobToSlave()
* @see disconnectSlave()
*/
static TDEIO::Slave *getConnectedSlave(const KURL &url, const TDEIO::MetaData &config = MetaData() )
{ return self()->_getConnectedSlave(url, config); }
/*
* Uses @p slave to do @p job.
* This function should be called immediately after creating a Job.
*
* @param slave The slave to use. The slave must have been obtained
* with a call to getConnectedSlave and must not
* be currently assigned to any other job.
* @param job The job to do.
*
* @return true is successful, false otherwise.
*
* @see getConnectedSlave()
* @see disconnectSlave()
* @see slaveConnected()
* @see slaveError()
*/
static bool assignJobToSlave(TDEIO::Slave *slave, TDEIO::SimpleJob *job)
{ return self()->_assignJobToSlave(slave, job); }
/*
* Disconnects @p slave.
*
* @param slave The slave to disconnect. The slave must have been
* obtained with a call to getConnectedSlave
* and must not be assigned to any job.
*
* @return true is successful, false otherwise.
*
* @see getConnectedSlave
* @see assignJobToSlave
*/
static bool disconnectSlave(TDEIO::Slave *slave)
{ return self()->_disconnectSlave(slave); }
/**
* Send the slave that was put on hold back to TDELauncher. This
* allows another process to take over the slave and resume the job
* the that was started.
* Register the mainwindow @p wid with the TDEIO subsystem
* Do not call this, it is called automatically from
* void TDEIO::Job::setWindow(TQWidget*).
* @param wid the window to register
* @since 3.1
*/
static void registerWindow(TQWidget *wid)
{ self()->_registerWindow(wid); }
/**
* @internal
* Unregisters the window registered by registerWindow().
*/
static void unregisterWindow(TQObject *wid)
{ self()->slotUnregisterWindow(wid); }
/**
* Function to connect signals emitted by the scheduler.
*
* @see slaveConnected()
* @see slaveError()
*/
static bool connect( const char *signal, const TQObject *receiver,
const char *member)
{ return TQObject::connect(self(), signal, receiver, member); }
static bool connect( const TQObject* sender, const char* signal,
const TQObject* receiver, const char* member )
{ return TQObject::connect(sender, signal, receiver, member); }
static bool disconnect( const TQObject* sender, const char* signal,
const TQObject* receiver, const char* member )
{ return TQObject::disconnect(sender, signal, receiver, member); }
bool connect( const TQObject *sender, const char *signal,
const char *member )
{ return TQObject::connect(sender, signal, member); }
/**
* When true, the next job will check whether TDELauncher has a slave
* on hold that is suitable for the job.
* @param b true when TDELauncher has a job on hold
*/
static void checkSlaveOnHold(bool b) { self()->_checkSlaveOnHold(b); }
void debug_info();
virtual bool process(const TQCString &fun, const TQByteArray &data,
TQCString& replyType, TQByteArray &replyData);
virtual QCStringList functions();
public slots:
void slotSlaveDied(TDEIO::Slave *slave);
void slotSlaveStatus(pid_t pid, const TQCString &protocol,
const TQString &host, bool connected);
signals:
void slaveConnected(TDEIO::Slave *slave);
void slaveError(TDEIO::Slave *slave, int error, const TQString &errorMsg);
protected:
void setupSlave(TDEIO::Slave *slave, const KURL &url, const TQString &protocol, const TQString &proxy , bool newSlave, const TDEIO::MetaData *config=0);
bool startJobScheduled(ProtocolInfo *protInfo);
bool startJobDirect();
Scheduler();
protected slots:
void startStep();
void slotCleanIdleSlaves();
void slotSlaveConnected();
void slotSlaveError(int error, const TQString &errorMsg);
void slotScheduleCoSlave();
/// @since 3.1
void slotUnregisterWindow(TQObject *);
private:
class ProtocolInfoDict;
class ExtraJobData;
Scheduler(const Scheduler&);
static Scheduler *self();
static Scheduler *instance;
void _doJob(SimpleJob *job);
void _scheduleJob(SimpleJob *job);
void _cancelJob(SimpleJob *job);
void _jobFinished(TDEIO::SimpleJob *job, TDEIO::Slave *slave);
void _scheduleCleanup();
void _putSlaveOnHold(TDEIO::SimpleJob *job, const KURL &url);
void _removeSlaveOnHold();
Slave *_getConnectedSlave(const KURL &url, const TDEIO::MetaData &metaData );
bool _assignJobToSlave(TDEIO::Slave *slave, TDEIO::SimpleJob *job);
bool _disconnectSlave(TDEIO::Slave *slave);
void _checkSlaveOnHold(bool b);
void _publishSlaveOnHold();
void _registerWindow(TQWidget *wid);
Slave *findIdleSlave(ProtocolInfo *protInfo, SimpleJob *job, bool &exact);
Slave *createSlave(ProtocolInfo *protInfo, SimpleJob *job, const KURL &url);
TQTimer slaveTimer;
TQTimer coSlaveTimer;
TQTimer cleanupTimer;
bool busy;
SlaveList *slaveList;
SlaveList *idleSlaves;
SlaveList *coIdleSlaves;
ProtocolInfoDict *protInfoDict;
Slave *slaveOnHold;
KURL urlOnHold;
JobList newJobs;
TQPtrDict<JobList> coSlaves;
ExtraJobData *extraJobData;
SlaveConfig *slaveConfig;
SessionData *sessionData;
bool checkOnHold;
TQMap<TQObject *,WId> m_windowList;
protected:
virtual void virtual_hook( int id, void* data );
private:
class SchedulerPrivate* d;
};
}
#endif