Panda3D
|
00001 // Filename: asyncTaskChain.h 00002 // Created by: drose (23Aug06) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #ifndef ASYNCTASKCHAIN_H 00016 #define ASYNCTASKCHAIN_H 00017 00018 #include "pandabase.h" 00019 00020 #include "asyncTask.h" 00021 #include "asyncTaskCollection.h" 00022 #include "typedReferenceCount.h" 00023 #include "thread.h" 00024 #include "conditionVarFull.h" 00025 #include "pvector.h" 00026 #include "pdeque.h" 00027 #include "pStatCollector.h" 00028 #include "clockObject.h" 00029 00030 class AsyncTaskManager; 00031 00032 //////////////////////////////////////////////////////////////////// 00033 // Class : AsyncTaskChain 00034 // Description : The AsyncTaskChain is a subset of the 00035 // AsyncTaskManager. Each chain maintains a separate 00036 // list of tasks, and will execute them with its own set 00037 // of threads. Each chain may thereby operate 00038 // independently of the other chains. 00039 // 00040 // The AsyncTaskChain will spawn a specified number of 00041 // threads (possibly 0) to serve the tasks. If there 00042 // are no threads, you must call poll() from time to 00043 // time to serve the tasks in the main thread. Normally 00044 // this is done by calling AsyncTaskManager::poll(). 00045 // 00046 // Each task will run exactly once each epoch. Beyond 00047 // that, the tasks' sort and priority values control the 00048 // order in which they are run: tasks are run in 00049 // increasing order by sort value, and within the same 00050 // sort value, they are run roughly in decreasing order 00051 // by priority value, with some exceptions for 00052 // parallelism. Tasks with different sort values are 00053 // never run in parallel together, but tasks with 00054 // different priority values might be (if there is more 00055 // than one thread). 00056 //////////////////////////////////////////////////////////////////// 00057 class EXPCL_PANDA_EVENT AsyncTaskChain : public TypedReferenceCount, public Namable { 00058 public: 00059 AsyncTaskChain(AsyncTaskManager *manager, const string &name); 00060 ~AsyncTaskChain(); 00061 00062 PUBLISHED: 00063 void set_tick_clock(bool tick_clock); 00064 bool get_tick_clock() const; 00065 00066 BLOCKING void set_num_threads(int num_threads); 00067 int get_num_threads() const; 00068 int get_num_running_threads() const; 00069 00070 BLOCKING void set_thread_priority(ThreadPriority priority); 00071 ThreadPriority get_thread_priority() const; 00072 00073 void set_frame_budget(double frame_budget); 00074 double get_frame_budget() const; 00075 00076 void set_frame_sync(bool frame_sync); 00077 bool get_frame_sync() const; 00078 00079 void set_timeslice_priority(bool timeslice_priority); 00080 bool get_timeslice_priority() const; 00081 00082 BLOCKING void stop_threads(); 00083 void start_threads(); 00084 INLINE bool is_started() const; 00085 00086 bool has_task(AsyncTask *task) const; 00087 00088 BLOCKING void wait_for_tasks(); 00089 00090 int get_num_tasks() const; 00091 AsyncTaskCollection get_tasks() const; 00092 AsyncTaskCollection get_active_tasks() const; 00093 AsyncTaskCollection get_sleeping_tasks() const; 00094 00095 void poll(); 00096 double get_next_wake_time() const; 00097 00098 virtual void output(ostream &out) const; 00099 virtual void write(ostream &out, int indent_level = 0) const; 00100 00101 protected: 00102 class AsyncTaskChainThread; 00103 typedef pvector< PT(AsyncTask) > TaskHeap; 00104 00105 void do_add(AsyncTask *task); 00106 bool do_remove(AsyncTask *task); 00107 void do_wait_for_tasks(); 00108 void do_cleanup(); 00109 00110 bool do_has_task(AsyncTask *task) const; 00111 int find_task_on_heap(const TaskHeap &heap, AsyncTask *task) const; 00112 00113 void service_one_task(AsyncTaskChainThread *thread); 00114 void cleanup_task(AsyncTask *task, bool upon_death, bool clean_exit); 00115 bool finish_sort_group(); 00116 void filter_timeslice_priority(); 00117 void do_stop_threads(); 00118 void do_start_threads(); 00119 AsyncTaskCollection do_get_active_tasks() const; 00120 AsyncTaskCollection do_get_sleeping_tasks() const; 00121 void do_poll(); 00122 void cleanup_pickup_mode(); 00123 INLINE double do_get_next_wake_time() const; 00124 static INLINE double get_wake_time(AsyncTask *task); 00125 void do_output(ostream &out) const; 00126 void do_write(ostream &out, int indent_level) const; 00127 00128 void write_task_line(ostream &out, int indent_level, AsyncTask *task, double now) const; 00129 00130 protected: 00131 class AsyncTaskChainThread : public Thread { 00132 public: 00133 AsyncTaskChainThread(const string &name, AsyncTaskChain *chain); 00134 virtual void thread_main(); 00135 00136 AsyncTaskChain *_chain; 00137 AsyncTask *_servicing; 00138 }; 00139 00140 class AsyncTaskSortWakeTime { 00141 public: 00142 bool operator () (AsyncTask *a, AsyncTask *b) const { 00143 return AsyncTaskChain::get_wake_time(a) > AsyncTaskChain::get_wake_time(b); 00144 } 00145 }; 00146 00147 class AsyncTaskSortPriority { 00148 public: 00149 bool operator () (AsyncTask *a, AsyncTask *b) const { 00150 if (a->get_sort() != b->get_sort()) { 00151 return a->get_sort() > b->get_sort(); 00152 } 00153 if (a->get_priority() != b->get_priority()) { 00154 return a->get_priority() < b->get_priority(); 00155 } 00156 return a->get_start_time() > b->get_start_time(); 00157 } 00158 }; 00159 00160 typedef pvector< PT(AsyncTaskChainThread) > Threads; 00161 00162 AsyncTaskManager *_manager; 00163 00164 ConditionVarFull _cvar; // signaled when one of the task heaps, _state, or _current_sort changes, or a task finishes. 00165 00166 enum State { 00167 S_initial, // no threads yet 00168 S_started, // threads have been started 00169 S_interrupted, // task returned DS_interrupt, requested from sub-thread. 00170 S_shutdown // waiting for thread shutdown, requested from main thread 00171 }; 00172 00173 bool _tick_clock; 00174 bool _timeslice_priority; 00175 int _num_threads; 00176 ThreadPriority _thread_priority; 00177 Threads _threads; 00178 double _frame_budget; 00179 bool _frame_sync; 00180 int _num_busy_threads; 00181 int _num_tasks; 00182 TaskHeap _active; 00183 TaskHeap _this_active; 00184 TaskHeap _next_active; 00185 TaskHeap _sleeping; 00186 State _state; 00187 int _current_sort; 00188 bool _pickup_mode; 00189 bool _needs_cleanup; 00190 00191 int _current_frame; 00192 double _time_in_frame; 00193 bool _block_till_next_frame; 00194 00195 static PStatCollector _task_pcollector; 00196 static PStatCollector _wait_pcollector; 00197 00198 public: 00199 static TypeHandle get_class_type() { 00200 return _type_handle; 00201 } 00202 static void init_type() { 00203 TypedReferenceCount::init_type(); 00204 register_type(_type_handle, "AsyncTaskChain", 00205 TypedReferenceCount::get_class_type()); 00206 } 00207 virtual TypeHandle get_type() const { 00208 return get_class_type(); 00209 } 00210 virtual TypeHandle force_init_type() {init_type(); return get_class_type();} 00211 00212 private: 00213 static TypeHandle _type_handle; 00214 00215 friend class AsyncTaskChainThread; 00216 friend class AsyncTask; 00217 friend class AsyncTaskManager; 00218 friend class AsyncTaskSortWakeTime; 00219 }; 00220 00221 INLINE ostream &operator << (ostream &out, const AsyncTaskChain &chain) { 00222 chain.output(out); 00223 return out; 00224 }; 00225 00226 #include "asyncTaskChain.I" 00227 00228 #endif