- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

# aggregator.h

    00001 /*
    00002     Copyright 2005-2012 Intel Corporation.  All Rights Reserved.
    00003
    00004     This file is part of Threading Building Blocks.
    00005
    00006     Threading Building Blocks is free software; you can redistribute it
    00007     and/or modify it under the terms of the GNU General Public License
    00008     version 2 as published by the Free Software Foundation.
    00009
    00010     Threading Building Blocks is distributed in the hope that it will be
    00011     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
    00012     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00013     GNU General Public License for more details.
    00014
    00015     You should have received a copy of the GNU General Public License
    00016     along with Threading Building Blocks; if not, write to the Free Software
    00017     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    00018
    00019     As a special exception, you may use this file as part of a free software
    00020     library without restriction.  Specifically, if other files instantiate
    00021     templates or use macros or inline functions from this file, or you compile
    00022     this file and link it with other files to produce an executable, this
    00023     file does not by itself cause the resulting executable to be covered by
    00024     the GNU General Public License.  This exception does not however
    00025     invalidate any other reasons why the executable file might be covered by
    00026     the GNU General Public License.
    00027 */
    00028
    00029 #ifndef __TBB__aggregator_H
    00030 #define __TBB__aggregator_H
    00031
    00032 #if !TBB_PREVIEW_AGGREGATOR
    00033 #error Set TBB_PREVIEW_AGGREGATOR before including aggregator.h
    00034 #endif
    00035
    00036 #include "atomic.h"
    00037 #include "tbb_profiling.h"
    00038
    00039 namespace tbb {
    00040 namespace interface6 {
    00041
    00042 using namespace tbb::internal;
    00043
    00044 class aggregator_operation {
    00045     template<typename handler_type> friend class aggregator_ext;
    00046     uintptr_t status;
    00047     aggregator_operation* my_next;
    00048 public:
    00049     enum aggregator_operation_status { agg_waiting=0, agg_finished };
    00050     aggregator_operation() : status(agg_waiting), my_next(NULL) {}
    00052     void start() { call_itt_notify(acquired, &status); }
    00054
    00055     void finish() { itt_store_word_with_release(status, uintptr_t(agg_finished)); }
    00056     aggregator_operation* next() { return itt_hide_load_word(my_next);}
    00057     void set_next(aggregator_operation* n) { itt_hide_store_word(my_next, n); }
    00058 };
    00059
    00060 namespace internal {
    00061
    00062 class basic_operation_base : public aggregator_operation {
    00063     friend class basic_handler;
    00064     virtual void apply_body() = 0;
    00065 public:
    00066     basic_operation_base() : aggregator_operation() {}
    00067     virtual ~basic_operation_base() {}
    00068 };
    00069
    00070 template<typename Body>
    00071 class basic_operation : public basic_operation_base, no_assign {
    00072     const Body& my_body;
    00073     /*override*/ void apply_body() { my_body(); }
    00074 public:
    00075     basic_operation(const Body& b) : basic_operation_base(), my_body(b) {}
    00076 };
    00077
    00078 class basic_handler {
    00079 public:
    00080     basic_handler() {}
    00081     void operator()(aggregator_operation* op_list) const {
    00082         while (op_list) {
    00083             // ITT note: &(op_list->status) tag is used to cover accesses to the operation data.
    00084             // The executing thread "acquires" the tag (see start()) and then performs
    00085             // the associated operation w/o triggering a race condition diagnostics.
    00086             // A thread that created the operation is waiting for its status (see execute_impl()),
    00087             // so when this thread is done with the operation, it will "release" the tag
    00088             // and update the status (see finish()) to give control back to the waiting thread.
    00089             basic_operation_base& request = static_cast<basic_operation_base&>(*op_list);
    00090             // IMPORTANT: need to advance op_list to op_list->next() before calling request.finish()
    00091             op_list = op_list->next();
    00092             request.start();
    00093             request.apply_body();
    00094             request.finish();
    00095         }
    00096     }
    00097 };
    00098
    00099 } // namespace internal
    00100
    00102
    00104 template <typename handler_type>
    00105 class aggregator_ext : tbb::internal::no_copy {
    00106 public:
    00107     aggregator_ext(const handler_type& h) : handler_busy(0), handle_operations(h) { mailbox = NULL; }
    00108
    00110
    00111     void process(aggregator_operation *op) { execute_impl(*op); }
    00112
    00113  protected:
    00116     void execute_impl(aggregator_operation& op) {
    00117         aggregator_operation* res;
    00118
    00119         // ITT note: &(op.status) tag is used to cover accesses to this operation. This
    00120         // thread has created the operation, and now releases it so that the handler
    00121         // thread may handle the associated operation w/o triggering a race condition;
    00122         // thus this tag will be acquired just before the operation is handled in the
    00123         // handle_operations functor.
    00124         call_itt_notify(releasing, &(op.status));
    00125         // insert the operation in the queue
    00126         do {
    00127             // ITT may flag the following line as a race; it is a false positive:
    00128             // This is an atomic read; we don't provide itt_hide_load_word for atomics
    00129             op.my_next = res = mailbox; // NOT A RACE
    00130         } while (mailbox.compare_and_swap(&op, res) != res);
    00131         if (!res) { // first in the list; handle the operations
    00132             // ITT note: &mailbox tag covers access to the handler_busy flag, which this
    00133             // waiting handler thread will try to set before entering handle_operations.
    00134             call_itt_notify(acquired, &mailbox);
    00135             start_handle_operations();
    00136             __TBB_ASSERT(op.status, NULL);
    00137         }
    00138         else { // not first; wait for op to be ready
    00139             call_itt_notify(prepare, &(op.status));
    00140             spin_wait_while_eq(op.status, uintptr_t(aggregator_operation::agg_waiting));
    00141             itt_load_word_with_acquire(op.status);
    00142         }
    00143     }
    00144
    00145
    00146  private:
    00148     atomic<aggregator_operation *> mailbox;
    00149
    00151
    00152     uintptr_t handler_busy;
    00153
    00154     handler_type handle_operations;
    00155
    00157     void start_handle_operations() {
    00158         aggregator_operation *pending_operations;
    00159
    00160         // ITT note: &handler_busy tag covers access to mailbox as it is passed
    00161         // between active and waiting handlers.  Below, the waiting handler waits until
    00162         // the active handler releases, and the waiting handler acquires &handler_busy as
    00163         // it becomes the active_handler. The release point is at the end of this
    00164         // function, when all operations in mailbox have been handled by the
    00165         // owner of this aggregator.
    00166         call_itt_notify(prepare, &handler_busy);
    00167         // get handler_busy: only one thread can possibly spin here at a time
    00168         spin_wait_until_eq(handler_busy, uintptr_t(0));
    00169         call_itt_notify(acquired, &handler_busy);
    00170         // acquire fence not necessary here due to causality rule and surrounding atomics
    00171         __TBB_store_with_release(handler_busy, uintptr_t(1));
    00172
    00173         // ITT note: &mailbox tag covers access to the handler_busy flag itself.
    00174         // Capturing the state of the mailbox signifies that handler_busy has been
    00175         // set and a new active handler will now process that list's operations.
    00176         call_itt_notify(releasing, &mailbox);
    00177         // grab pending_operations
    00178         pending_operations = mailbox.fetch_and_store(NULL);
    00179
    00180         // handle all the operations
    00181         handle_operations(pending_operations);
    00182
    00183         // release the handler
    00184         itt_store_word_with_release(handler_busy, uintptr_t(0));
    00185     }
    00186 };
    00187
    00189 class aggregator : private aggregator_ext<internal::basic_handler> {
    00190 public:
    00191     aggregator() : aggregator_ext<internal::basic_handler>(internal::basic_handler()) {}
    00193
    00195     template<typename Body>
    00196     void execute(const Body& b) {
    00197         internal::basic_operation<Body> op(b);
    00198         this->execute_impl(op);
    00199     }
    00200 };
    00201
    00202 } // namespace interface6
    00203
    00204 using interface6::aggregator;
    00205 using interface6::aggregator_ext;
    00206 using interface6::aggregator_operation;
    00207
    00208 } // namespace tbb
    00209
    00210 #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.