Initial Commit - Lesson 31 (Commit #1)
This commit is contained in:
172
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/benchmarks/tbb/observer_proxy.h
vendored
Normal file
172
Plugins/GameLiftServerSDK/ThirdParty/concurrentqueue/benchmarks/tbb/observer_proxy.h
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
Copyright 2005-2014 Intel Corporation. All Rights Reserved.
|
||||
|
||||
This file is part of Threading Building Blocks. Threading Building Blocks is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation. Threading Building Blocks is
|
||||
distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details. You should have received a copy of
|
||||
the GNU General Public License along with Threading Building Blocks; if not, write to the
|
||||
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
As a special exception, you may use this file as part of a free software library without
|
||||
restriction. Specifically, if other files instantiate templates or use macros or inline
|
||||
functions from this file, or you compile this file and link it with other files to produce
|
||||
an executable, this file does not by itself cause the resulting executable to be covered
|
||||
by the GNU General Public License. This exception does not however invalidate any other
|
||||
reasons why the executable file might be covered by the GNU General Public License.
|
||||
*/
|
||||
|
||||
#ifndef _TBB_observer_proxy_H
|
||||
#define _TBB_observer_proxy_H
|
||||
|
||||
#if __TBB_SCHEDULER_OBSERVER
|
||||
|
||||
#include "scheduler_common.h" // to include task.h
|
||||
#include "tbb/task_scheduler_observer.h"
|
||||
#include "tbb/spin_rw_mutex.h"
|
||||
#include "tbb/aligned_space.h"
|
||||
|
||||
namespace tbb {
|
||||
namespace internal {
|
||||
|
||||
class observer_list {
|
||||
friend class arena;
|
||||
|
||||
// Mutex is wrapped with aligned_space to shut up warnings when its destructor
|
||||
// is called while threads are still using it.
|
||||
typedef aligned_space<spin_rw_mutex> my_mutex_type;
|
||||
|
||||
//! Pointer to the head of this list.
|
||||
observer_proxy* my_head;
|
||||
|
||||
//! Pointer to the tail of this list.
|
||||
observer_proxy* my_tail;
|
||||
|
||||
//! Mutex protecting this list.
|
||||
my_mutex_type my_mutex;
|
||||
|
||||
//! Back-pointer to the arena this list belongs to.
|
||||
arena* my_arena;
|
||||
|
||||
//! Decrement refcount of the proxy p if there are other outstanding references.
|
||||
/** In case of success sets p to NULL. Must be invoked from under the list lock. **/
|
||||
inline static void remove_ref_fast( observer_proxy*& p );
|
||||
|
||||
//! Implements notify_entry_observers functionality.
|
||||
void do_notify_entry_observers( observer_proxy*& last, bool worker );
|
||||
|
||||
//! Implements notify_exit_observers functionality.
|
||||
void do_notify_exit_observers( observer_proxy* last, bool worker );
|
||||
|
||||
public:
|
||||
observer_list () : my_head(NULL), my_tail(NULL) {}
|
||||
|
||||
//! Removes and destroys all observer proxies from the list.
|
||||
/** Cannot be used concurrently with other methods. **/
|
||||
void clear ();
|
||||
|
||||
//! Add observer proxy to the tail of the list.
|
||||
void insert ( observer_proxy* p );
|
||||
|
||||
//! Remove observer proxy from the list.
|
||||
void remove ( observer_proxy* p );
|
||||
|
||||
//! Decrement refcount of the proxy and destroy it if necessary.
|
||||
/** When refcount reaches zero removes the proxy from the list and destructs it. **/
|
||||
void remove_ref( observer_proxy* p );
|
||||
|
||||
//! Type of the scoped lock for the reader-writer mutex associated with the list.
|
||||
typedef spin_rw_mutex::scoped_lock scoped_lock;
|
||||
|
||||
//! Accessor to the reader-writer mutex associated with the list.
|
||||
spin_rw_mutex& mutex () { return my_mutex.begin()[0]; }
|
||||
|
||||
bool empty () const { return my_head == NULL; }
|
||||
|
||||
//! Call entry notifications on observers added after last was notified.
|
||||
/** Updates last to become the last notified observer proxy (in the global list)
|
||||
or leaves it to be NULL. The proxy has its refcount incremented. **/
|
||||
inline void notify_entry_observers( observer_proxy*& last, bool worker );
|
||||
|
||||
//! Call exit notifications on last and observers added before it.
|
||||
inline void notify_exit_observers( observer_proxy*& last, bool worker );
|
||||
|
||||
//! Call may_sleep callbacks to ask for permission for a worker thread to leave market
|
||||
bool ask_permission_to_leave();
|
||||
}; // class observer_list
|
||||
|
||||
//! Wrapper for an observer object
|
||||
/** To maintain shared lists of observers the scheduler first wraps each observer
|
||||
object into a proxy so that a list item remained valid even after the corresponding
|
||||
proxy object is destroyed by the user code. **/
|
||||
class observer_proxy {
|
||||
friend class task_scheduler_observer_v3;
|
||||
friend class observer_list;
|
||||
//! Reference count used for garbage collection.
|
||||
/** 1 for reference from my task_scheduler_observer.
|
||||
1 for each task dispatcher's last observer pointer.
|
||||
No accounting for neighbors in the shared list. */
|
||||
atomic<int> my_ref_count;
|
||||
//! Reference to the list this observer belongs to.
|
||||
observer_list* my_list;
|
||||
//! Pointer to next observer in the list specified by my_head.
|
||||
/** NULL for the last item in the list. **/
|
||||
observer_proxy* my_next;
|
||||
//! Pointer to the previous observer in the list specified by my_head.
|
||||
/** For the head of the list points to the last item. **/
|
||||
observer_proxy* my_prev;
|
||||
//! Associated observer
|
||||
task_scheduler_observer_v3* my_observer;
|
||||
//! Version
|
||||
char my_version;
|
||||
|
||||
interface6::task_scheduler_observer* get_v6_observer();
|
||||
bool is_global(); //TODO: move them back inline when un-CPF'ing
|
||||
|
||||
//! Constructs proxy for the given observer and adds it to the specified list.
|
||||
observer_proxy( task_scheduler_observer_v3& );
|
||||
|
||||
#if TBB_USE_ASSERT
|
||||
~observer_proxy();
|
||||
#endif /* TBB_USE_ASSERT */
|
||||
|
||||
//! Shut up the warning
|
||||
observer_proxy& operator = ( const observer_proxy& );
|
||||
}; // class observer_proxy
|
||||
|
||||
inline void observer_list::remove_ref_fast( observer_proxy*& p ) {
|
||||
if( p->my_observer ) {
|
||||
// Can decrement refcount quickly, as it cannot drop to zero while under the lock.
|
||||
int r = --p->my_ref_count;
|
||||
__TBB_ASSERT_EX( r, NULL );
|
||||
p = NULL;
|
||||
} else {
|
||||
// Use slow form of refcount decrementing, after the lock is released.
|
||||
}
|
||||
}
|
||||
|
||||
inline void observer_list::notify_entry_observers( observer_proxy*& last, bool worker ) {
|
||||
if ( last == my_tail )
|
||||
return;
|
||||
do_notify_entry_observers( last, worker );
|
||||
}
|
||||
|
||||
inline void observer_list::notify_exit_observers( observer_proxy*& last, bool worker ) {
|
||||
if ( !last )
|
||||
return;
|
||||
__TBB_ASSERT(is_alive((uintptr_t)last), NULL);
|
||||
do_notify_exit_observers( last, worker );
|
||||
__TBB_ASSERT(last, NULL);
|
||||
poison_value(last);
|
||||
}
|
||||
|
||||
extern padded<observer_list> the_global_observer_list;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace tbb
|
||||
|
||||
#endif /* __TBB_SCHEDULER_OBSERVER */
|
||||
|
||||
#endif /* _TBB_observer_proxy_H */
|
||||
Reference in New Issue
Block a user