00001 // -*- C++ -*- 00002 00003 //============================================================================= 00004 /** 00005 * @file Task.h 00006 * 00007 * $Id: Task.h 80826 2008-03-04 14:51:23Z wotte $ 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 @a n_threads of 00123 * control, all running at the @a priority level (see below) with the 00124 * same @a 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 * @a 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 @a force_active is true. Note that if 00130 * @a force_active is true and there are already threads spawned in 00131 * this <Task>, the @a grp_id parameter is ignored and the @a grp_id 00132 * of any newly activated thread(s) will inherit the existing 00133 * @a 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 @a 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 @a task allows you to associate the newly spawned 00163 * threads with an instance of ACE_Task_Base. If @a task == 0, then 00164 * the new threads are associated automatically with @c this 00165 * ACE_Task_Base. Setting the @a 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 @a task value must therefore be manipulated thru 00169 * ACE_Thread_Manager directly. 00170 * 00171 * If @a 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 @a stack_size != 0 it is assumed to be an array of 00174 * @a n values indicating how big each of the corresponding @a stacks 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 const char* thr_name[] = 0); 00190 00191 /** 00192 * Block until there are no more threads running in this task. 00193 * This method will not wait for either detached or daemon threads; 00194 * the threads must have been spawned with the @c THR_JOINABLE flag. 00195 * Upon successful completion, the threads have been joined, so further 00196 * attempts to join with any of the waited-for threads will fail. 00197 * 00198 * @retval 0 Success. 00199 * @retval -1 Failure (consult errno for further information). 00200 */ 00201 virtual int wait (void); 00202 00203 // = Suspend/resume a Task. 00204 00205 // Note that these methods are not portable and should be avoided 00206 // since they are inherently error-prone to use. They are only here 00207 // for (the rare) applications that know how to use them correctly. 00208 /// Suspend a task. 00209 virtual int suspend (void); 00210 /// Resume a suspended task. 00211 virtual int resume (void); 00212 00213 /// Get the current group id. 00214 int grp_id (void) const; 00215 00216 /// Set the current group id. 00217 void grp_id (int); 00218 00219 /// Get the thread manager associated with this Task. 00220 ACE_Thread_Manager *thr_mgr (void) const; 00221 00222 /// Set the thread manager associated with this Task. 00223 void thr_mgr (ACE_Thread_Manager *); 00224 00225 /// True if queue is a reader, else false. 00226 int is_reader (void) const; 00227 00228 /// True if queue is a writer, else false. 00229 int is_writer (void) const; 00230 00231 /** 00232 * Returns the number of threads currently running within a task. 00233 * If we're a passive object this value is 0, else it's greater than 00234 * 0. 00235 */ 00236 size_t thr_count (void) const; 00237 00238 /** 00239 * Returns the thread ID of the thread whose exit caused this object's 00240 * thread count to be decremented to 0. 00241 * 00242 * When a thread spawned in the context of this object (using activate()) 00243 * returns from its svc() method ACE calls the close() hook. Before it does 00244 * so, it decrements the number of active threads. If the number of threads 00245 * is decremented to 0, the thread ID of the current thread is stored for 00246 * access by this method. If the returned thread ID matches the calling 00247 * thread's ID, the calling thread knows that there are no other threads 00248 * still active in the ACE_Task. 00249 * 00250 * @retval ACE_thread_t of the last thread to close. 0 if the last thread 00251 * is not yet known; for example, if no threads are active, or if 00252 * multiple threads are active. 00253 */ 00254 ACE_thread_t last_thread (void) const; 00255 00256 /// Routine that runs the service routine as a daemon thread. 00257 static ACE_THR_FUNC_RETURN svc_run (void *); 00258 00259 /// Cleanup hook that is called when a thread exits to gracefully 00260 /// shutdown an ACE_Task. 00261 static void cleanup (void *object, void *params); 00262 00263 protected: 00264 /** 00265 * Count of the number of threads running within the task. If this 00266 * value is greater than 0 then we're an active object and the value 00267 * of <thr_count_> is the number of active threads at this instant. 00268 * If the value == 0, then we're a passive object. 00269 */ 00270 size_t thr_count_; 00271 00272 /// Multi-threading manager. 00273 ACE_Thread_Manager *thr_mgr_; 00274 00275 /// ACE_Task flags. 00276 u_long flags_; 00277 00278 /// This maintains the group id of the Task. 00279 int grp_id_; 00280 00281 #if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) 00282 /// Protect the state of a Task during concurrent operations, but 00283 /// only if we're configured as MT safe... 00284 ACE_Thread_Mutex lock_; 00285 #endif /* ACE_MT_SAFE */ 00286 00287 /// Holds the thread ID of the last thread to exit svc() in this object. 00288 ACE_thread_t last_thread_id_; 00289 00290 private: 00291 00292 // = Disallow these operations. 00293 ACE_Task_Base &operator= (const ACE_Task_Base &); 00294 ACE_Task_Base (const ACE_Task_Base &); 00295 }; 00296 00297 ACE_END_VERSIONED_NAMESPACE_DECL 00298 00299 #if defined (__ACE_INLINE__) 00300 #include "ace/Task.inl" 00301 #endif /* __ACE_INLINE__ */ 00302 00303 // Include the ACE_Task templates classes at this point. 00304 #include "ace/Task_T.h" 00305 00306 #include /**/ "ace/post.h" 00307 #endif /* ACE_TASK_H */