00001 // -*- C++ -*- 00002 00003 //============================================================================= 00004 /** 00005 * @file Task.h 00006 * 00007 * $Id: Task.h 78460 2007-05-23 13:33:56Z johnnyw $ 00008 * 00009 * @author Douglas C. Schmidt <schmidt@cs.wustl.edu> 00010 */ 00011 //============================================================================= 00012 00013 #ifndef ACE_TASK_H 00014 #define ACE_TASK_H 00015 #include /**/ "ace/pre.h" 00016 00017 #include "ace/Service_Object.h" 00018 00019 #if !defined (ACE_LACKS_PRAGMA_ONCE) 00020 # pragma once 00021 #endif /* ACE_LACKS_PRAGMA_ONCE */ 00022 00023 #include "ace/Thread_Manager.h" 00024 00025 ACE_BEGIN_VERSIONED_NAMESPACE_DECL 00026 00027 /** 00028 * @class ACE_Task_Flags 00029 * 00030 * @brief These flags are used within the ACE_Task. 00031 * 00032 * These flags should be hidden within ACE_Task. Unfortunately, the 00033 * HP/UX C++ compiler can't grok this... Fortunately, there's no 00034 * code defined here, so we don't have to worry about multiple 00035 * definitions. 00036 */ 00037 namespace ACE_Task_Flags 00038 { 00039 enum 00040 { 00041 /// Identifies a Task as being the "reader" in a Module. 00042 ACE_READER = 01, 00043 /// Just flush data messages in the queue. 00044 ACE_FLUSHDATA = 02, 00045 /// Flush all messages in the Queue. 00046 ACE_FLUSHALL = 04, 00047 /// Flush read queue 00048 ACE_FLUSHR = 010, 00049 /// Flush write queue 00050 ACE_FLUSHW = 020, 00051 /// Flush both queues 00052 ACE_FLUSHRW = 030 00053 }; 00054 } 00055 00056 /** 00057 * @class ACE_Task_Base 00058 * 00059 * @brief Direct base class for the ACE_Task template. 00060 * 00061 * This class factors out the non-template code in order to 00062 * reduce template bloat, as well as to make it possible for the 00063 * ACE_Thread_Manager to store ACE_Task_Base *'s 00064 * polymorphically. 00065 */ 00066 class ACE_Export ACE_Task_Base : public ACE_Service_Object 00067 { 00068 public: 00069 // = Initialization and termination methods. 00070 /// Constructor. 00071 ACE_Task_Base (ACE_Thread_Manager * = 0); 00072 00073 /// Destructor. 00074 virtual ~ACE_Task_Base (void); 00075 00076 // = Initialization and termination hooks. 00077 00078 // These methods should be overridden by subclasses if you'd like to 00079 // provide <Task>-specific initialization and termination behavior. 00080 00081 /// Hook called to initialize a task and prepare it for execution. 00082 /// @a args can be used to pass arbitrary information into <open>. 00083 virtual int open (void *args = 0); 00084 00085 /** 00086 * Hook called from ACE_Thread_Exit when during thread exit and from 00087 * the default implementation of <module_closed>. In general, this 00088 * method shouldn't be called directly by an application, 00089 * particularly if the <Task> is running as an Active Object. 00090 * Instead, a special message should be passed into the <Task> via 00091 * the <put> method defined below, and the <svc> method should 00092 * interpret this as a flag to shut down the <Task>. 00093 */ 00094 virtual int close (u_long flags = 0); 00095 00096 /** 00097 * Hook called during <ACE_Module::close>. The default 00098 * implementation calls forwards the call to close(1). Please 00099 * notice the changed value of the default argument of <close>. 00100 * This allows tasks to differ between the call has been originated 00101 * from <ACE_Thread_Exit> or from <module_closed>. Be aware that 00102 * close(0) will be also called when a thread associated with the 00103 * ACE_Task instance exits. 00104 */ 00105 virtual int module_closed (void); 00106 00107 // = Immediate and deferred processing methods, respectively. 00108 00109 // These methods should be overridden by subclasses if you'd like to 00110 // provide <Task>-specific message processing behavior. 00111 00112 /// A hook method that can be used to pass a message to a 00113 /// task, where it can be processed immediately or queued for subsequent 00114 /// processing in the <svc> hook method. 00115 virtual int put (ACE_Message_Block *, ACE_Time_Value * = 0); 00116 00117 /// Run by a daemon thread to handle deferred processing. 00118 virtual int svc (void); 00119 00120 // = Active object activation method. 00121 /** 00122 * Turn the task into an active object, i.e., having <n_threads> of 00123 * control, all running at the <priority> level (see below) with the 00124 * same <grp_id>, all of which invoke <Task::svc>. Returns -1 if 00125 * failure occurs, returns 1 if Task is already an active object and 00126 * <force_active> is false (i.e., do *not* create a new thread in 00127 * this case), and returns 0 if Task was not already an active 00128 * object and a thread is created successfully or thread is an 00129 * active object and <force_active> is true. Note that if 00130 * <force_active> is true and there are already threads spawned in 00131 * this <Task>, the <grp_id> parameter is ignored and the <grp_id> 00132 * of any newly activated thread(s) will inherit the existing 00133 * <grp_id> of the existing thread(s) in the <Task>. 00134 * 00135 * The <{flags}> are a bitwise-OR of the following: 00136 * = BEGIN<INDENT> 00137 * THR_CANCEL_DISABLE, THR_CANCEL_ENABLE, THR_CANCEL_DEFERRED, 00138 * THR_CANCEL_ASYNCHRONOUS, THR_BOUND, THR_NEW_LWP, THR_DETACHED, 00139 * THR_SUSPENDED, THR_DAEMON, THR_JOINABLE, THR_SCHED_FIFO, 00140 * THR_SCHED_RR, THR_SCHED_DEFAULT, THR_EXPLICIT_SCHED, 00141 * THR_SCOPE_SYSTEM, THR_SCOPE_PROCESS 00142 * = END<INDENT> 00143 * If THR_SCHED_INHERIT is not desirable, applications should 00144 * specifically pass in THR_EXPLICIT_SCHED. 00145 * 00146 * 00147 * By default, or if <{priority}> is set to 00148 * ACE_DEFAULT_THREAD_PRIORITY, an "appropriate" priority value for 00149 * the given scheduling policy (specified in <{flags}>, e.g., 00150 * <THR_SCHED_DEFAULT>) is used. This value is calculated 00151 * dynamically, and is the median value between the minimum and 00152 * maximum priority values for the given policy. If an explicit 00153 * value is given, it is used. Note that actual priority values are 00154 * EXTREMEMLY implementation-dependent, and are probably best 00155 * avoided. 00156 * 00157 * If <thread_handles> != 0 it is assumed to be an array of @a n 00158 * thread_handles that will be assigned the values of the thread 00159 * handles being spawned. Returns -1 on failure (@c errno will 00160 * explain...), otherwise returns the group id of the threads. 00161 * 00162 * Assigning <task> allows you to associate the newly spawned 00163 * threads with an instance of ACE_Task_Base. If <task> == 0, then 00164 * the new threads are associated automatically with @c this 00165 * ACE_Task_Base. Setting the <task> argument to value other than 00166 * @c this makes the thread manipulating methods, such as wait(), 00167 * suspend(), resume(), useless. Threads spawned with user 00168 * specified <task> value must therefore be manipulated thru 00169 * ACE_Thread_Manager directly. 00170 * 00171 * If <stack> != 0 it is assumed to be an array of @a n pointers to 00172 * the base of the stacks to use for the threads being spawned. 00173 * Likewise, if <stack_size> != 0 it is assumed to be an array of 00174 * @a n values indicating how big each of the corresponding <stack>s 00175 * are. 00176 * 00177 * 00178 */ 00179 virtual int activate (long flags = THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, 00180 int n_threads = 1, 00181 int force_active = 0, 00182 long priority = ACE_DEFAULT_THREAD_PRIORITY, 00183 int grp_id = -1, 00184 ACE_Task_Base *task = 0, 00185 ACE_hthread_t thread_handles[] = 0, 00186 void *stack[] = 0, 00187 size_t stack_size[] = 0, 00188 ACE_thread_t thread_ids[] = 0); 00189 00190 /** 00191 * Block until there are no more threads running in this task. 00192 * This method will not wait for either detached or daemon threads; 00193 * the threads must have been spawned with the @c THR_JOINABLE flag. 00194 * Upon successful completion, the threads have been joined, so further 00195 * attempts to join with any of the waited-for threads will fail. 00196 * 00197 * @retval 0 Success. 00198 * @retval -1 Failure (consult errno for further information). 00199 */ 00200 virtual int wait (void); 00201 00202 // = Suspend/resume a Task. 00203 00204 // Note that these methods are not portable and should be avoided 00205 // since they are inherently error-prone to use. They are only here 00206 // for (the rare) applications that know how to use them correctly. 00207 /// Suspend a task. 00208 virtual int suspend (void); 00209 /// Resume a suspended task. 00210 virtual int resume (void); 00211 00212 /// Get the current group id. 00213 int grp_id (void) const; 00214 00215 /// Set the current group id. 00216 void grp_id (int); 00217 00218 /// Get the thread manager associated with this Task. 00219 ACE_Thread_Manager *thr_mgr (void) const; 00220 00221 /// Set the thread manager associated with this Task. 00222 void thr_mgr (ACE_Thread_Manager *); 00223 00224 /// True if queue is a reader, else false. 00225 int is_reader (void) const; 00226 00227 /// True if queue is a writer, else false. 00228 int is_writer (void) const; 00229 00230 /** 00231 * Returns the number of threads currently running within a task. 00232 * If we're a passive object this value is 0, else it's greater than 00233 * 0. 00234 */ 00235 size_t thr_count (void) const; 00236 00237 /** 00238 * Returns the thread ID of the thread whose exit caused this object's 00239 * thread count to be decremented to 0. 00240 * 00241 * When a thread spawned in the context of this object (using activate()) 00242 * returns from its svc() method ACE calls the close() hook. Before it does 00243 * so, it decrements the number of active threads. If the number of threads 00244 * is decremented to 0, the thread ID of the current thread is stored for 00245 * access by this method. If the returned thread ID matches the calling 00246 * thread's ID, the calling thread knows that there are no other threads 00247 * still active in the ACE_Task. 00248 * 00249 * @retval ACE_thread_t of the last thread to close. 0 if the last thread 00250 * is not yet known; for example, if no threads are active, or if 00251 * multiple threads are active. 00252 */ 00253 ACE_thread_t last_thread (void) const; 00254 00255 /// Routine that runs the service routine as a daemon thread. 00256 static ACE_THR_FUNC_RETURN svc_run (void *); 00257 00258 /// Cleanup hook that is called when a thread exits to gracefully 00259 /// shutdown an ACE_Task. 00260 static void cleanup (void *object, void *params); 00261 00262 protected: 00263 /** 00264 * Count of the number of threads running within the task. If this 00265 * value is greater than 0 then we're an active object and the value 00266 * of <thr_count_> is the number of active threads at this instant. 00267 * If the value == 0, then we're a passive object. 00268 */ 00269 size_t thr_count_; 00270 00271 /// Multi-threading manager. 00272 ACE_Thread_Manager *thr_mgr_; 00273 00274 /// ACE_Task flags. 00275 u_long flags_; 00276 00277 /// This maintains the group id of the Task. 00278 int grp_id_; 00279 00280 #if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) 00281 /// Protect the state of a Task during concurrent operations, but 00282 /// only if we're configured as MT safe... 00283 ACE_Thread_Mutex lock_; 00284 #endif /* ACE_MT_SAFE */ 00285 00286 /// Holds the thread ID of the last thread to exit svc() in this object. 00287 ACE_thread_t last_thread_id_; 00288 00289 private: 00290 00291 // = Disallow these operations. 00292 ACE_Task_Base &operator= (const ACE_Task_Base &); 00293 ACE_Task_Base (const ACE_Task_Base &); 00294 }; 00295 00296 ACE_END_VERSIONED_NAMESPACE_DECL 00297 00298 #if defined (__ACE_INLINE__) 00299 #include "ace/Task.inl" 00300 #endif /* __ACE_INLINE__ */ 00301 00302 // Include the ACE_Task templates classes at this point. 00303 #include "ace/Task_T.h" 00304 00305 #include /**/ "ace/post.h" 00306 #endif /* ACE_TASK_H */