PFUNC 1.0
pfunc/pfunc.hpp
Go to the documentation of this file.
00001 #ifndef PFUNC_HPP
00002 #define PFUNC_HPP
00003 
00015 #include <pfunc/pfunc_common.h>
00016 #include <pfunc/exception.hpp>
00017 #include <pfunc/mutex.hpp>
00018 #include <pfunc/event.hpp>
00019 #include <pfunc/thread.hpp>
00020 #include <pfunc/trampolines.hpp>
00021 #include <pfunc/group.hpp>
00022 #include <pfunc/attribute.hpp>
00023 #include <pfunc/task.hpp>
00024 #include <pfunc/taskmgr.hpp>
00025 #include <pfunc/generator.hpp>
00026 
00027 namespace pfunc {
00028 
00029   /* Convenience */
00030   using detail::group;
00031 
00036   template <typename Attribute>
00037   static inline void attr_priority_set (Attribute& attr, 
00038                                  const typename Attribute::priority_type& pri) {
00039     attr.set_priority (pri);
00040   }
00041 
00046   template <typename Attribute>
00047   static inline void attr_priority_get (const Attribute& attr, 
00048                                  typename Attribute::priority_type& pri) {
00049     pri = attr.get_priority ();
00050   }
00051 
00056   template <typename Attribute>
00057   static inline void attr_qnum_set (Attribute& attr, 
00058                              const typename Attribute::qnum_type& qnum) {
00059     attr.set_queue_number (qnum);
00060   }
00061 
00066   template <typename Attribute>
00067   static inline void attr_qnum_get (const Attribute& attr, 
00068                              typename Attribute::qnum_type& qnum) {
00069     qnum = attr.get_queue_number ();
00070   }
00071 
00076   template <typename Attribute>
00077   static inline void attr_num_waiters_set (Attribute& attr, 
00078                         const typename Attribute::num_waiters_type& nwait) {
00079     attr.set_num_waiters (nwait);
00080   }
00081 
00086   template <typename Attribute>
00087   static inline void attr_num_waiters_get (const Attribute& attr,
00088                               typename Attribute::num_waiters_type& nwait) {
00089     nwait = attr.get_num_waiters ();
00090   }
00091 
00096   template <typename Attribute>
00097   static inline void attr_nested_set (Attribute& attr, 
00098                              const typename Attribute::nested_type& nested) {
00099     attr.set_nested (nested);
00100   }
00101 
00106   template <typename Attribute>
00107   static inline void attr_nested_get (const Attribute& attr, 
00108                                typename Attribute::nested_type& nested) {
00109     nested = attr.get_nested ();
00110   }
00111 
00116   template <typename Attribute>
00117   static inline void attr_level_set (Attribute& attr, 
00118                              const typename Attribute::level_type& level) {
00119     attr.set_level (level);
00120   }
00121 
00126   template <typename Attribute>
00127   static inline void attr_level_get (Attribute& attr, 
00128                              typename Attribute::level_type& level) {
00129     level = attr.get_level ();
00130   }
00131 
00136   template <typename Attribute>
00137   static inline void attr_grouped_set (Attribute& attr, 
00138                             const typename Attribute::grouped_type& grouped) {
00139     attr.set_grouped (grouped);
00140   }
00141 
00146   template <typename Attribute>
00147   static inline void attr_grouped_get (const Attribute& attr,
00148                                 typename Attribute::grouped_type& grouped) {
00149     grouped= attr.get_grouped ();
00150   }
00155   static inline void group_id_set (group& grp, 
00156                                    const unsigned int& id) {
00157     grp.set_id (id);
00158   }
00159 
00164   static inline void group_id_get (const group& grp, 
00165                                    unsigned int& id) {
00166     id = grp.get_id ();
00167   }
00168 
00173   static inline void group_size_set (group& grp, 
00174                                      const unsigned int& size) {
00175     grp.set_size (size);
00176   }
00177 
00182   static inline void group_size_get (const group& grp,
00183                                      unsigned int& size) {
00184     size = grp.get_size ();
00185   }
00186 
00191   static inline void group_barrier_set (group& grp, 
00192                                         const unsigned int& barr) {
00193     grp.set_barrier (barr);
00194   }
00195 
00200   static inline void group_barrier_get (const group& grp,
00201                                         unsigned int& barr) {
00202     barr = grp.get_barrier ();
00203   }
00204 
00205 /****************************************************************************
00206  * All the above functions make use of the taskmanager as a parameter. As 
00207  * a result, we have two versions of these functions. A global version that
00208  * uses as default task manager object and the (preferred) version that uses
00209  * a user supplied task manager object. Users are allowed to mix and match the
00210  * two calls, as long as they are consistent. That is, if you spawned a task
00211  * using the global task manager, please also wait on the task using the 
00212  * global task manager 
00213  ***************************************************************************/
00214 
00215  /**************************************************************************
00216   * Here are the local versions of the functions that use task manager 
00217   *************************************************************************/
00218 
00223   template <typename TaskManager>
00224   static inline unsigned int thread_id (const TaskManager& tmanager) {
00225     unsigned int id;
00226 
00227     PFUNC_START_TRY_BLOCK()              
00228     id = const_cast<TaskManager&>(tmanager).current_thread_id (); 
00229     PFUNC_END_TRY_BLOCK()
00230     PFUNC_CXX_CATCH_AND_RETHROW()
00231 
00232     return id;
00233   }
00234 
00239   template <typename TaskManager>
00240   static inline void group_rank (const TaskManager& tmanager,
00241                                  unsigned int& rank) {
00242     PFUNC_START_TRY_BLOCK()                                                 
00243     rank = const_cast<TaskManager&>(tmanager).current_task_group_rank ();
00244     PFUNC_END_TRY_BLOCK()
00245     PFUNC_CXX_CATCH_AND_RETHROW()
00246   }
00247 
00252   template <typename TaskManager>
00253   static inline void group_size (const TaskManager& tmanager,
00254                                  unsigned int& size) {
00255     PFUNC_START_TRY_BLOCK()                                                   
00256     size = const_cast<TaskManager&>(tmanager).current_task_group_size ();
00257     PFUNC_END_TRY_BLOCK()
00258     PFUNC_CXX_CATCH_AND_RETHROW()
00259   }
00260 
00265   template <typename TaskManager, typename TaskType>
00266   static inline void wait (TaskManager& tmanager, TaskType* task)  {
00267     PFUNC_START_TRY_BLOCK()                                                   
00268     task->wait (tmanager);
00269     PFUNC_END_TRY_BLOCK()
00270     PFUNC_CXX_CATCH_AND_RETHROW()
00271   }
00272 
00277   template <typename TaskManager, typename TaskType>
00278   static inline void wait (TaskManager& tmanager, TaskType& task)  {
00279     PFUNC_START_TRY_BLOCK()                                                   
00280     task.wait (tmanager);
00281     PFUNC_END_TRY_BLOCK()
00282     PFUNC_CXX_CATCH_AND_RETHROW()
00283   }
00284 
00295   template <typename TaskManager, typename ForwardIterator>
00296   static inline void wait_any (TaskManager& tmanager,
00297                         ForwardIterator first, 
00298                         ForwardIterator last,
00299                         int* completion_arr)  {
00300     PFUNC_START_TRY_BLOCK()                                                  
00301     unsigned int loop_count = 1;
00302     while (!pfunc_test_all (tmanager, first, last, completion_arr)) {
00311 #if PFUNC_LINUX == 1 
00312       pthread_yield();
00313 #elif PFUNC_DARWIN == 1
00314       pthread_yield_np();
00315 #elif PFUNC_WINDOWS == 1
00316       SwitchToThread();
00317 #elif PFUNC_AIX == 1 && PFUNC_HAVE_SCHED_H
00318       sched_yield();
00319 #else
00320 
00321 #endif
00322       loop_count = 1;
00323     }
00324     PFUNC_END_TRY_BLOCK()
00325     PFUNC_CXX_CATCH_AND_RETHROW()
00326  }
00327 
00335   template <typename TaskManager, typename ForwardIterator>
00336   static inline void wait_all (TaskManager& tmanager, 
00337                         ForwardIterator first, 
00338                         ForwardIterator last)  {
00339     PFUNC_START_TRY_BLOCK()                                                  
00340     while (first != last) wait (tmanager, *first++);
00341     PFUNC_END_TRY_BLOCK()
00342     PFUNC_CXX_CATCH_AND_RETHROW()
00343   }
00344 
00352  template <typename TaskManager, typename TaskType>
00353  static inline bool test (TaskManager& tmanager, TaskType& task)  {
00354    bool return_value = false;
00355 
00356    PFUNC_START_TRY_BLOCK()                                                  
00357    return_value = task.test (tmanager);
00358    PFUNC_END_TRY_BLOCK()
00359    PFUNC_CXX_CATCH_AND_RETHROW()
00360 
00361    return return_value;
00362  }
00363 
00372   template <typename TaskManager, typename ForwardIterator>
00373   static inline bool test_all (TaskManager& tmanager, 
00374                         ForwardIterator first, 
00375                         ForwardIterator last,
00376                         int* completion_arr)  {
00377     bool return_value = false;
00378 
00379    PFUNC_START_TRY_BLOCK()                                                  
00380     int i = 0;
00381     while (first != last) 
00382       completion_arr[i] = return_value = test (tmanager, *first++);
00383    PFUNC_END_TRY_BLOCK()
00384    PFUNC_CXX_CATCH_AND_RETHROW()
00385 
00386     return return_value;
00387   }
00388 
00397   template <typename TaskManager>
00398   static inline void barrier (TaskManager& tmanager)  {
00399     PFUNC_START_TRY_BLOCK()                                                  
00400     return tmanager.current_task_group_barrier ();
00401     PFUNC_END_TRY_BLOCK()
00402     PFUNC_CXX_CATCH_AND_RETHROW()
00403   }
00404 
00416   template <typename TaskManager>
00417   static inline void spawn (TaskManager& tmanager,
00418                             typename TaskManager::task& task,
00419                             const typename TaskManager::attribute& attr,
00420                             group& grp,
00421                             typename TaskManager::functor& func)  {
00422     PFUNC_START_TRY_BLOCK()                                                  
00423     tmanager.spawn_task (task, attr, grp, func);
00424     PFUNC_END_TRY_BLOCK()
00425     PFUNC_CXX_CATCH_AND_RETHROW()
00426   }
00427 
00437   template <typename TaskManager>
00438   static inline void spawn (TaskManager& tmanager,
00439                             typename TaskManager::task& task,
00440                             typename TaskManager::functor& func)  {
00441     PFUNC_START_TRY_BLOCK()                                                  
00442     tmanager.spawn_task (task, func);
00443     PFUNC_END_TRY_BLOCK()
00444     PFUNC_CXX_CATCH_AND_RETHROW()
00445   }
00446 
00457   template <typename TaskManager>
00458   static inline void spawn (TaskManager& tmanager,
00459                             typename TaskManager::task& task,
00460                             const typename TaskManager::attribute& attr,
00461                             typename TaskManager::functor& func)  {
00462     PFUNC_START_TRY_BLOCK()                                                  
00463     tmanager.spawn_task (task, attr, func);
00464     PFUNC_END_TRY_BLOCK()
00465     PFUNC_CXX_CATCH_AND_RETHROW()
00466   }
00467 
00468   /*
00469    * Set the maximum number of attempts before yielding for the specified 
00470    * task manager.
00471    *
00472    * \param [out] tmanager The task manager in question.
00473    * \param [out] attempts Contains the value of max attempts.
00474    */
00475   template <typename TaskManager>
00476   static inline void taskmgr_max_attempts_set (TaskManager& tmanager,
00477                                                const unsigned int& attempts) {
00478     PFUNC_START_TRY_BLOCK()
00479     tmanager.set_max_attempts (attempts);
00480     PFUNC_END_TRY_BLOCK()
00481     PFUNC_CXX_CATCH_AND_RETHROW()
00482   }
00483 
00484   /*
00485    * Get the maximum number of attempts before yielding for the specified 
00486    * task manager.
00487    *
00488    * \param [out] tmanager The task manager in question.
00489    * \param [out] attempts Contains the value of max attempts.
00490    */
00491   template <typename TaskManager>
00492   static inline void taskmgr_max_attempts_get (TaskManager& tmanager,
00493                                                unsigned int& attempts) {
00494     PFUNC_START_TRY_BLOCK()
00495     attempts = tmanager.get_max_attempts ();
00496     PFUNC_END_TRY_BLOCK()
00497     PFUNC_CXX_CATCH_AND_RETHROW()
00498   }
00499 
00500   /*
00501    * @param[in] taskmgr The task manager.
00502    * @param[out] num_queues The number of task queues in the global task
00503    * manager.
00504    */
00505   template <typename TaskMgr>
00506   static inline void get_num_queues (const TaskMgr& tmanager, 
00507                                      unsigned int& num_queues) {
00508     PFUNC_START_TRY_BLOCK()
00509     num_queues = tmanager.get_num_queues ();
00510     PFUNC_END_TRY_BLOCK()
00511     PFUNC_CXX_CATCH_AND_RETHROW()
00512   }
00513 
00514   /*
00515    * @param[in] taskmgr The task manager.
00516    * @param[out] num_threads The total number of threads in the global task
00517    * manager.
00518    */
00519   template <typename TaskMgr>
00520   static inline void get_num_threads (const TaskMgr& tmanager, 
00521                                       unsigned int& num_threads) {
00522     PFUNC_START_TRY_BLOCK()
00523     num_threads = tmanager.get_num_threads ();
00524     PFUNC_END_TRY_BLOCK()
00525     PFUNC_CXX_CATCH_AND_RETHROW()
00526   }
00527 
00528  /**************************************************************************
00529   * Here are the global versions of the functions that use task manager 
00530   * All these are under the 'global' namespace to avoid confusion.
00531   *************************************************************************/
00532 namespace global {
00533 
00535  detail::taskmgr_virtual_base* global_tmanager = NULL;
00536 
00552   template <typename TaskManager>
00553   void init (TaskManager& tmanager)  {
00554     global_tmanager = &tmanager;
00555   }
00556 
00561   void clear ()  { 
00562     global_tmanager = NULL; 
00563   } 
00564 
00568   static inline unsigned int thread_id ()  {
00569     unsigned int id;
00570     
00571     PFUNC_START_TRY_BLOCK()
00572     id = pfunc::thread_id (*global_tmanager);
00573     PFUNC_END_TRY_BLOCK()
00574     PFUNC_CXX_CATCH_AND_RETHROW()
00575 
00576     return id;
00577   }
00578 
00582   static inline void group_rank (unsigned int& rank) {
00583     PFUNC_START_TRY_BLOCK()
00584     return pfunc::group_rank (*global_tmanager, rank); 
00585     PFUNC_END_TRY_BLOCK()
00586     PFUNC_CXX_CATCH_AND_RETHROW()
00587   }
00588 
00592   static inline void group_size (unsigned int& size) {
00593     PFUNC_START_TRY_BLOCK()
00594     return pfunc::group_size (*global_tmanager, size); 
00595     PFUNC_END_TRY_BLOCK()
00596     PFUNC_CXX_CATCH_AND_RETHROW()
00597   }
00598 
00602   template <typename TaskType>
00603   static inline void wait (TaskType& task)  {
00604     PFUNC_START_TRY_BLOCK()
00605     return pfunc::wait (*global_tmanager, task);
00606     PFUNC_END_TRY_BLOCK()
00607     PFUNC_CXX_CATCH_AND_RETHROW()
00608   }
00609 
00619   template <typename ForwardIterator>
00620   static inline void wait_any (ForwardIterator first, 
00621                                ForwardIterator last,
00622                                int* completion_arr)  {
00623     PFUNC_START_TRY_BLOCK()
00624     return pfunc::wait_any (*global_tmanager, first, last, completion_arr);
00625     PFUNC_END_TRY_BLOCK()
00626     PFUNC_CXX_CATCH_AND_RETHROW()
00627   }
00628 
00635   template <typename ForwardIterator>
00636   static inline void wait_all (ForwardIterator first, 
00637                                ForwardIterator last)  {
00638     PFUNC_START_TRY_BLOCK()
00639     return pfunc::wait_all (*global_tmanager, first, last);
00640     PFUNC_END_TRY_BLOCK()
00641     PFUNC_CXX_CATCH_AND_RETHROW()
00642   }
00643 
00650   template <typename TaskType>
00651   static inline bool test (TaskType& task)  {
00652     bool ret_val;
00653     
00654     PFUNC_START_TRY_BLOCK()
00655     ret_val = pfunc::test (*global_tmanager, task);
00656     PFUNC_END_TRY_BLOCK()
00657     PFUNC_CXX_CATCH_AND_RETHROW()
00658     
00659     return ret_val;
00660  }
00661 
00669   template <typename ForwardIterator>
00670   static inline bool test_all (ForwardIterator first, 
00671                                ForwardIterator last,
00672                                int* completion_arr)  {
00673     bool ret_val;
00674 
00675     PFUNC_START_TRY_BLOCK()
00676     ret_val = pfunc::test_all (*global_tmanager, first, last, completion_arr);
00677     PFUNC_END_TRY_BLOCK()
00678     PFUNC_CXX_CATCH_AND_RETHROW()
00679 
00680     return ret_val;
00681   }
00682 
00687   static inline void barrier ()  {
00688     PFUNC_START_TRY_BLOCK()
00689     return pfunc::barrier (*global_tmanager);
00690     PFUNC_END_TRY_BLOCK()
00691     PFUNC_CXX_CATCH_AND_RETHROW()
00692   }
00693 
00702   template <typename Task,
00703             typename Functor>
00704   static inline void spawn (Task& task, Functor& func)  {
00705     PFUNC_START_TRY_BLOCK()
00706     global_tmanager->spawn_task(reinterpret_cast<void*>(&task), 
00707                                 reinterpret_cast<void*>(&func));
00708     PFUNC_END_TRY_BLOCK()
00709     PFUNC_CXX_CATCH_AND_RETHROW()
00710   }
00711 
00721   template <typename Task, 
00722             typename Attribute,
00723             typename Functor>
00724   static inline void spawn (Task& task,
00725                             const Attribute& attr,
00726                             Functor& func)  {
00727     PFUNC_START_TRY_BLOCK()
00728     global_tmanager->spawn_task(reinterpret_cast<void*>(&task), 
00729                                 reinterpret_cast<void*>(
00730                                   &(const_cast<Attribute&>(attr))), 
00731                                 reinterpret_cast<void*>(&func));
00732     PFUNC_END_TRY_BLOCK()
00733     PFUNC_CXX_CATCH_AND_RETHROW()
00734   }
00735 
00746   template <typename Task, 
00747             typename Attribute,
00748             typename Functor>
00749   static inline void spawn (Task& task,
00750                             const Attribute& attr,
00751                             group& grp,
00752                             Functor& func)  {
00753     PFUNC_START_TRY_BLOCK()
00754     global_tmanager->spawn_task(reinterpret_cast<void*>(&task), 
00755                                 reinterpret_cast<void*>(
00756                                   &(const_cast<Attribute&>(attr))), 
00757                                 reinterpret_cast<void*>(&grp), 
00758                                 reinterpret_cast<void*>(&func));
00759     PFUNC_END_TRY_BLOCK()
00760     PFUNC_CXX_CATCH_AND_RETHROW()
00761   }
00762 
00763   /*
00764    * Get the maximum number of attempts before yielding for teh global runtime
00765    *
00766    * \param [out] attempts Contains the value of max attempts.
00767    */
00768   static inline void taskmgr_max_attempts_set (const unsigned int& attempts) {
00769     PFUNC_START_TRY_BLOCK()
00770     global_tmanager->set_max_attempts (attempts);
00771     PFUNC_END_TRY_BLOCK()
00772     PFUNC_CXX_CATCH_AND_RETHROW()
00773   }
00774 
00775   /*
00776    * Get the maximum number of attempts before yielding for teh global runtime
00777    *
00778    * \param [out] attempts Contains the value of max attempts.
00779    */
00780   static inline void taskmgr_max_attempts_get (unsigned int& attempts) {
00781     PFUNC_START_TRY_BLOCK()
00782     attempts = global_tmanager->get_max_attempts ();
00783     PFUNC_END_TRY_BLOCK()
00784     PFUNC_CXX_CATCH_AND_RETHROW()
00785   }
00786 
00787   /*
00788    * @param[out] num_queues The number of task queues in the global task
00789    * manager.
00790    */
00791   static inline void get_num_queues (unsigned int& num_queues) {
00792     PFUNC_START_TRY_BLOCK()
00793     num_queues = global_tmanager->get_num_queues ();
00794     PFUNC_END_TRY_BLOCK()
00795     PFUNC_CXX_CATCH_AND_RETHROW()
00796   }
00797 
00798   /*
00799    * @param[out] num_threads The total number of threads in the global task
00800    * manager.
00801    */
00802   static inline void get_num_threads (unsigned int& num_threads) {
00803     PFUNC_START_TRY_BLOCK()
00804     num_threads = global_tmanager->get_num_threads ();
00805     PFUNC_END_TRY_BLOCK()
00806     PFUNC_CXX_CATCH_AND_RETHROW()
00807   }
00808 } // namespace global 
00809 } // namespace pfunc
00810 #endif // PFUNC_HPP