aggregator.h

00001 /*
00002     Copyright 2005-2012 Intel Corporation.  All Rights Reserved.
00003 
00004     The source code contained or described herein and all documents related
00005     to the source code ("Material") are owned by Intel Corporation or its
00006     suppliers or licensors.  Title to the Material remains with Intel
00007     Corporation or its suppliers and licensors.  The Material is protected
00008     by worldwide copyright laws and treaty provisions.  No part of the
00009     Material may be used, copied, reproduced, modified, published, uploaded,
00010     posted, transmitted, distributed, or disclosed in any way without
00011     Intel's prior express written permission.
00012 
00013     No license under any patent, copyright, trade secret or other
00014     intellectual property right is granted to or conferred upon you by
00015     disclosure or delivery of the Materials, either expressly, by
00016     implication, inducement, estoppel or otherwise.  Any license under such
00017     intellectual property rights must be express and approved by Intel in
00018     writing.
00019 */
00020 
00021 #ifndef __TBB__aggregator_H
00022 #define __TBB__aggregator_H
00023 
00024 #if !TBB_PREVIEW_AGGREGATOR
00025 #error Set TBB_PREVIEW_AGGREGATOR before including aggregator.h
00026 #endif
00027 
00028 #include "atomic.h"
00029 #include "tbb_profiling.h"
00030 
00031 namespace tbb {
00032 namespace interface6 {
00033 
00034 using namespace tbb::internal;
00035 
00036 class aggregator_operation {
00037     template<typename handler_type> friend class aggregator_ext;
00038     uintptr_t status;
00039     aggregator_operation* my_next;
00040 public:
00041     enum aggregator_operation_status { agg_waiting=0, agg_finished };
00042     aggregator_operation() : status(agg_waiting), my_next(NULL) {}
00044     void start() { call_itt_notify(acquired, &status); }
00046 
00047     void finish() { itt_store_word_with_release(status, uintptr_t(agg_finished)); }
00048     aggregator_operation* next() { return itt_hide_load_word(my_next);}
00049     void set_next(aggregator_operation* n) { itt_hide_store_word(my_next, n); }
00050 };
00051 
00052 namespace internal {
00053 
00054 class basic_operation_base : public aggregator_operation {
00055     friend class basic_handler;
00056     virtual void apply_body() = 0;
00057 public:
00058     basic_operation_base() : aggregator_operation() {}
00059     virtual ~basic_operation_base() {}
00060 };
00061 
00062 template<typename Body>
00063 class basic_operation : public basic_operation_base, no_assign {
00064     const Body& my_body;
00065     /*override*/ void apply_body() { my_body(); }
00066 public:
00067     basic_operation(const Body& b) : basic_operation_base(), my_body(b) {}
00068 };
00069 
00070 class basic_handler {
00071 public:
00072     basic_handler() {}
00073     void operator()(aggregator_operation* op_list) const { 
00074         while (op_list) {
00075             // ITT note: &(op_list->status) tag is used to cover accesses to the operation data.
00076             // The executing thread "acquires" the tag (see start()) and then performs
00077             // the associated operation w/o triggering a race condition diagnostics.
00078             // A thread that created the operation is waiting for its status (see execute_impl()),
00079             // so when this thread is done with the operation, it will "release" the tag 
00080             // and update the status (see finish()) to give control back to the waiting thread.
00081             basic_operation_base& request = static_cast<basic_operation_base&>(*op_list);
00082             // IMPORTANT: need to advance op_list to op_list->next() before calling request.finish()
00083             op_list = op_list->next();
00084             request.start();
00085             request.apply_body();
00086             request.finish();
00087         }
00088     }
00089 };
00090 
00091 } // namespace internal
00092 
00094 
00096 template <typename handler_type>
00097 class aggregator_ext : tbb::internal::no_copy {
00098 public:
00099     aggregator_ext(const handler_type& h) : handler_busy(0), handle_operations(h) { mailbox = NULL; }
00100 
00102 
00103     void process(aggregator_operation *op) { execute_impl(*op); }
00104 
00105  protected:
00108     void execute_impl(aggregator_operation& op) {
00109         aggregator_operation* res;
00110 
00111         // ITT note: &(op.status) tag is used to cover accesses to this operation. This
00112         // thread has created the operation, and now releases it so that the handler
00113         // thread may handle the associated operation w/o triggering a race condition;
00114         // thus this tag will be acquired just before the operation is handled in the
00115         // handle_operations functor.
00116         call_itt_notify(releasing, &(op.status));
00117         // insert the operation in the queue
00118         do {
00119             // ITT may flag the following line as a race; it is a false positive:
00120             // This is an atomic read; we don't provide itt_hide_load_word for atomics
00121             op.my_next = res = mailbox; // NOT A RACE 
00122         } while (mailbox.compare_and_swap(&op, res) != res);
00123         if (!res) { // first in the list; handle the operations
00124             // ITT note: &mailbox tag covers access to the handler_busy flag, which this
00125             // waiting handler thread will try to set before entering handle_operations.
00126             call_itt_notify(acquired, &mailbox);
00127             start_handle_operations();
00128             __TBB_ASSERT(op.status, NULL);
00129         }
00130         else { // not first; wait for op to be ready
00131             call_itt_notify(prepare, &(op.status));
00132             spin_wait_while_eq(op.status, uintptr_t(aggregator_operation::agg_waiting));
00133             itt_load_word_with_acquire(op.status);
00134         }
00135     }
00136 
00137 
00138  private:
00140     atomic<aggregator_operation *> mailbox;
00141 
00143 
00144     uintptr_t handler_busy;
00145 
00146     handler_type handle_operations;
00147 
00149     void start_handle_operations() {
00150         aggregator_operation *pending_operations;
00151 
00152         // ITT note: &handler_busy tag covers access to mailbox as it is passed
00153         // between active and waiting handlers.  Below, the waiting handler waits until
00154         // the active handler releases, and the waiting handler acquires &handler_busy as
00155         // it becomes the active_handler. The release point is at the end of this
00156         // function, when all operations in mailbox have been handled by the
00157         // owner of this aggregator.
00158         call_itt_notify(prepare, &handler_busy);
00159         // get handler_busy: only one thread can possibly spin here at a time
00160         spin_wait_until_eq(handler_busy, uintptr_t(0));
00161         call_itt_notify(acquired, &handler_busy);
00162         // acquire fence not necessary here due to causality rule and surrounding atomics
00163         __TBB_store_with_release(handler_busy, uintptr_t(1));
00164 
00165         // ITT note: &mailbox tag covers access to the handler_busy flag itself. 
00166         // Capturing the state of the mailbox signifies that handler_busy has been 
00167         // set and a new active handler will now process that list's operations.
00168         call_itt_notify(releasing, &mailbox);
00169         // grab pending_operations
00170         pending_operations = mailbox.fetch_and_store(NULL);
00171 
00172         // handle all the operations
00173         handle_operations(pending_operations);
00174 
00175         // release the handler
00176         itt_store_word_with_release(handler_busy, uintptr_t(0));
00177     }
00178 };
00179 
00181 class aggregator : private aggregator_ext<internal::basic_handler> {
00182 public:
00183     aggregator() : aggregator_ext<internal::basic_handler>(internal::basic_handler()) {}
00185 
00187     template<typename Body>
00188     void execute(const Body& b) {
00189         internal::basic_operation<Body> op(b);
00190         this->execute_impl(op);
00191     }
00192 };
00193 
00194 } // namespace interface6
00195 
00196 using interface6::aggregator;
00197 using interface6::aggregator_ext;
00198 using interface6::aggregator_operation;
00199 
00200 } // namespace tbb
00201 
00202 #endif  // __TBB__aggregator_H

Copyright © 2005-2012 Intel Corporation. All Rights Reserved.

Intel, Pentium, Intel Xeon, Itanium, Intel XScale and VTune are registered trademarks or trademarks of Intel Corporation or its subsidiaries in the United States and other countries.

* Other names and brands may be claimed as the property of others.