1 /*
2  * lftp - file transfer program
3  *
4  * Copyright (c) 1996-2016 by Alexander V. Lukyanov (lav@yars.free.net)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef SMTASK_H
21 #define SMTASK_H
22 
23 #include "PollVec.h"
24 #include "TimeDate.h"
25 #include "Ref.h"
26 #include "xarray.h"
27 #include "xlist.h"
28 #include "misc.h"
29 #include "Error.h"
30 #include <errno.h>
31 
32 class SMTask
33 {
34    virtual int Do() = 0;
35 
36    // all tasks list
37    static xlist_head<SMTask> all_tasks;
38    xlist<SMTask> all_tasks_node;
39 
40    // ready (not suspended) tasks list
41    static xlist_head<SMTask> ready_tasks;
42    xlist<SMTask> ready_tasks_node;
43 
44    // just created or resumed tasks
45    static xlist_head<SMTask> new_tasks;
46    xlist<SMTask> new_tasks_node;
47 
48    // deleted and going to be destroyed tasks
49    static xlist_head<SMTask> deleted_tasks;
50    xlist<SMTask> deleted_tasks_node;
51 
52    static PollVec block;
53    enum { SMTASK_MAX_DEPTH=64 };
54    static SMTask *stack[SMTASK_MAX_DEPTH];
55    static int stack_ptr;
56 
57    bool	 suspended;
58    bool	 suspended_slave;
59 
60    int	 running;
61    int	 ref_count;
62    bool	 deleting;
63 
64    int ScheduleThis();
65    static int ScheduleNew();
66 
67 protected:
68    enum
69    {
70       STALL=0,
71       MOVED=1,	  // STALL|MOVED==MOVED.
72       WANTDIE=2	  // for AcceptSig
73    };
74 
75    // SuspendInternal and ResumeInternal usually suspend and resume slave tasks
SuspendInternal()76    virtual void SuspendInternal() {}
77    virtual void ResumeInternal();
PrepareToDie()78    virtual void PrepareToDie() {}  // it is called from Delete no matter of running and ref_count
79 
Deleted()80    bool Deleted() const { return deleting; }
81    virtual ~SMTask();
82 
83 public:
Block(int fd,int mask)84    static void Block(int fd,int mask) { block.AddFD(fd,mask); }
TimeoutU(int us)85    static void TimeoutU(int us) { block.AddTimeoutU(us); }
Timeout(int ms)86    static void Timeout(int ms) { TimeoutU(1000*ms); }
TimeoutS(int s)87    static void TimeoutS(int s) { TimeoutU(1000000*s); }
Ready(int fd,int mask)88    static bool Ready(int fd,int mask) { return block.FDReady(fd,mask); }
SetNotReady(int fd,int mask)89    static void SetNotReady(int fd,int mask) { block.FDSetNotReady(fd,mask); }
90 
91    static TimeDate now;
UpdateNow()92    static void UpdateNow() { now.SetToCurrentTime(); }
93 
94    static void Schedule();
95    static int CollectGarbage();
96    static void Block();
97    static time_t last_block;
98 
99    void Suspend();
100    void Resume();
101 
102    // SuspendSlave and ResumeSlave are used in SuspendInternal/ResumeInternal
103    // to suspend/resume slave tasks
104    void SuspendSlave();
105    void ResumeSlave();
106 
IsSuspended()107    bool IsSuspended() { return suspended|suspended_slave; }
108 
GetLogContext()109    virtual const char *GetLogContext() { return 0; }
GetCurrentLogContext()110    static const char *GetCurrentLogContext() { return current->GetLogContext(); }
111 
112    SMTask();
113 
114    void DeleteLater();
115    static void Delete(SMTask *);
IncRefCount()116    void IncRefCount() { ref_count++; }
DecRefCount()117    void DecRefCount() { if(ref_count>0) ref_count--; }
_MakeRef(SMTask * task)118    static SMTask *_MakeRef(SMTask *task) { if(task) task->IncRefCount(); return task; }
_DeleteRef(SMTask * task)119    static void _DeleteRef(SMTask *task)  { if(task) { task->DecRefCount(); Delete(task); } }
120    static SMTask *_SetRef(SMTask *task,SMTask *new_task);
MakeRef(T * task)121    template<typename T> static T *MakeRef(T *task) { _MakeRef(task); return task; }
122    static int Roll(SMTask *);
Roll()123    int Roll() { return Roll(this); }
124    static void RollAll(const TimeInterval &max_time);
125 
126    static SMTask *current;
127 
128    static void Enter(SMTask *task);
129    static void Leave(SMTask *task);
Enter()130    void Enter() { Enter(this); }
Leave()131    void Leave() { Leave(this); }
132 
133    static int TaskCount();
134    static void PrintTasks();
135    static bool NonFatalError(int err);
TemporaryNetworkError(int err)136    static bool TemporaryNetworkError(int err) { return temporary_network_error(err); }
137    static Error *SysError(int e=errno) { return new Error(e,strerror(e),!NonFatalError(e)); }
138 
139    static void Cleanup();
140 };
141 
142 class SMTaskInit : public SMTask
143 {
144    int Do();
145 public:
146    SMTaskInit();
147    ~SMTaskInit();
148 };
149 
150 template<class T> class SMTaskRef
151 {
152    SMTaskRef<T>(const SMTaskRef<T>&);  // disable cloning
153    void operator=(const SMTaskRef<T>&);   // and assignment
154 
155 protected:
156    T *ptr;
157 
158 public:
SMTaskRef()159    SMTaskRef() { ptr=0; }
ptr(SMTask::MakeRef (p))160    SMTaskRef<T>(T *p) : ptr(SMTask::MakeRef(p)) {}
161    ~SMTaskRef<T>() { SMTask::_DeleteRef(ptr); ptr=0; }
162    void operator=(T *p) { ptr=static_cast<T*>(SMTask::_SetRef(ptr,p)); }
163    operator const T*() const { return ptr; }
164    T *operator->() const { return ptr; }
borrow()165    T *borrow() { if(ptr) ptr->DecRefCount(); return replace_value(ptr,(T*)0); }
get()166    const T *get() const { return ptr; }
get_non_const()167    T *get_non_const() const { return ptr; }
168 
Cast()169    template<class C> const SMTaskRef<C>& Cast() const
170       { void(static_cast<C*>(ptr)); return *(const SMTaskRef<C>*)this; }
171 
172    static const SMTaskRef<T> null;
173 
_set(T * p)174    void _set(T *p) { ptr=p; }
_clear()175    void _clear() { ptr=0; }
unset()176    void unset() { *this=0; }
177 };
178 
179 template<typename T>
180 class TaskRefArray : public _RefArray< T,SMTaskRef<T> > {
181    TaskRefArray& operator=(const TaskRefArray&); // make assignment fail
182    TaskRefArray(const TaskRefArray&);	       // disable cloning
183 public:
TaskRefArray()184    TaskRefArray() : _RefArray< T,SMTaskRef<T> >() {}
185 };
186 
187 #endif /* SMTASK_H */
188