/* * lftp - file transfer program * * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef SMTASK_H #define SMTASK_H #include "PollVec.h" #include "TimeDate.h" #include "Ref.h" #include "xarray.h" #include "xlist.h" #include "misc.h" #include "Error.h" #include class SMTask { virtual int Do() = 0; // all tasks list static xlist_head all_tasks; xlist all_tasks_node; // ready (not suspended) tasks list static xlist_head ready_tasks; xlist ready_tasks_node; // just created or resumed tasks static xlist_head new_tasks; xlist new_tasks_node; // deleted and going to be destroyed tasks static xlist_head deleted_tasks; xlist deleted_tasks_node; static PollVec block; enum { SMTASK_MAX_DEPTH=64 }; static SMTask *stack[SMTASK_MAX_DEPTH]; static int stack_ptr; bool suspended; bool suspended_slave; int running; int ref_count; bool deleting; int ScheduleThis(); static int ScheduleNew(); protected: enum { STALL=0, MOVED=1, // STALL|MOVED==MOVED. WANTDIE=2 // for AcceptSig }; // SuspendInternal and ResumeInternal usually suspend and resume slave tasks virtual void SuspendInternal() {} virtual void ResumeInternal(); virtual void PrepareToDie() {} // it is called from Delete no matter of running and ref_count bool Deleted() const { return deleting; } virtual ~SMTask(); public: static void Block(int fd,int mask) { block.AddFD(fd,mask); } static void TimeoutU(int us) { block.AddTimeoutU(us); } static void Timeout(int ms) { TimeoutU(1000*ms); } static void TimeoutS(int s) { TimeoutU(1000000*s); } static bool Ready(int fd,int mask) { return block.FDReady(fd,mask); } static void SetNotReady(int fd,int mask) { block.FDSetNotReady(fd,mask); } static TimeDate now; static void UpdateNow() { now.SetToCurrentTime(); } static void Schedule(); static int CollectGarbage(); static void Block(); static time_t last_block; void Suspend(); void Resume(); // SuspendSlave and ResumeSlave are used in SuspendInternal/ResumeInternal // to suspend/resume slave tasks void SuspendSlave(); void ResumeSlave(); bool IsSuspended() { return suspended|suspended_slave; } virtual const char *GetLogContext() { return 0; } static const char *GetCurrentLogContext() { return current->GetLogContext(); } SMTask(); void DeleteLater(); static void Delete(SMTask *); void IncRefCount() { ref_count++; } void DecRefCount() { if(ref_count>0) ref_count--; } static SMTask *_MakeRef(SMTask *task) { if(task) task->IncRefCount(); return task; } static void _DeleteRef(SMTask *task) { if(task) { task->DecRefCount(); Delete(task); } } static SMTask *_SetRef(SMTask *task,SMTask *new_task); template static T *MakeRef(T *task) { _MakeRef(task); return task; } static int Roll(SMTask *); int Roll() { return Roll(this); } static void RollAll(const TimeInterval &max_time); static SMTask *current; static void Enter(SMTask *task); static void Leave(SMTask *task); void Enter() { Enter(this); } void Leave() { Leave(this); } static int TaskCount(); static void PrintTasks(); static bool NonFatalError(int err); static bool TemporaryNetworkError(int err) { return temporary_network_error(err); } static Error *SysError(int e=errno) { return new Error(e,strerror(e),!NonFatalError(e)); } static void Cleanup(); }; class SMTaskInit : public SMTask { int Do(); public: SMTaskInit(); ~SMTaskInit(); }; template class SMTaskRef { SMTaskRef(const SMTaskRef&); // disable cloning void operator=(const SMTaskRef&); // and assignment protected: T *ptr; public: SMTaskRef() { ptr=0; } SMTaskRef(T *p) : ptr(SMTask::MakeRef(p)) {} ~SMTaskRef() { SMTask::_DeleteRef(ptr); ptr=0; } void operator=(T *p) { ptr=static_cast(SMTask::_SetRef(ptr,p)); } operator const T*() const { return ptr; } T *operator->() const { return ptr; } T *borrow() { if(ptr) ptr->DecRefCount(); return replace_value(ptr,(T*)0); } const T *get() const { return ptr; } T *get_non_const() const { return ptr; } template const SMTaskRef& Cast() const { void(static_cast(ptr)); return *(const SMTaskRef*)this; } static const SMTaskRef null; void _set(T *p) { ptr=p; } void _clear() { ptr=0; } void unset() { *this=0; } }; template class TaskRefArray : public _RefArray< T,SMTaskRef > { TaskRefArray& operator=(const TaskRefArray&); // make assignment fail TaskRefArray(const TaskRefArray&); // disable cloning public: TaskRefArray() : _RefArray< T,SMTaskRef >() {} }; #endif /* SMTASK_H */