Home ⌂Doc Index ◂Up ▴
Intel(R) Threading Building Blocks Doxygen Documentation  version 4.2.3
condition_variable.cpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2005-2020 Intel Corporation
3 
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16 
17 #include "tbb/tbb_config.h"
18 #include "tbb/compat/condition_variable"
19 #include "tbb/atomic.h"
20 #include "tbb_misc.h"
21 #include "dynamic_link.h"
22 #include "itt_notify.h"
23 
24 namespace tbb {
25 
26 namespace internal {
27 
28 //condition_variable
29 #if _WIN32||_WIN64
30 using tbb::interface5::internal::condition_variable_using_event;
31 
32 static atomic<do_once_state> condvar_api_state;
33 
34 void WINAPI init_condvar_using_event( condition_variable_using_event* cv_event )
35 {
36  // TODO: For Metro port, we can always use the API for condition variables, without dynamic_link etc.
37  cv_event->event = CreateEventEx(NULL, NULL, 0x1 /*CREATE_EVENT_MANUAL_RESET*/, EVENT_ALL_ACCESS );
38  InitializeCriticalSectionEx( &cv_event->mutex, 4000, 0 );
39  cv_event->n_waiters = 0;
40  cv_event->release_count = 0;
41  cv_event->epoch = 0;
42 }
43 
44 BOOL WINAPI sleep_condition_variable_cs_using_event( condition_variable_using_event* cv_event, LPCRITICAL_SECTION cs, DWORD dwMilliseconds )
45 {
46  EnterCriticalSection( &cv_event->mutex );
47  ++cv_event->n_waiters;
48  unsigned my_generation = cv_event->epoch;
49  LeaveCriticalSection( &cv_event->mutex );
50  LeaveCriticalSection( cs );
51  for (;;) {
52  // should come here at least once
53  DWORD rc = WaitForSingleObjectEx( cv_event->event, dwMilliseconds, FALSE );
54  EnterCriticalSection( &cv_event->mutex );
55  if( rc!=WAIT_OBJECT_0 ) {
56  --cv_event->n_waiters;
57  LeaveCriticalSection( &cv_event->mutex );
58  if( rc==WAIT_TIMEOUT ) {
59  SetLastError( WAIT_TIMEOUT );
60  EnterCriticalSection( cs );
61  }
62  return false;
63  }
64  __TBB_ASSERT( rc==WAIT_OBJECT_0, NULL );
65  if( cv_event->release_count>0 && cv_event->epoch!=my_generation )
66  break;
67  LeaveCriticalSection( &cv_event->mutex );
68  }
69 
70  // still in the critical section
71  --cv_event->n_waiters;
72  int count = --cv_event->release_count;
73  LeaveCriticalSection( &cv_event->mutex );
74 
75  if( count==0 ) {
76  __TBB_ASSERT( cv_event->event, "Premature destruction of condition variable?" );
77  ResetEvent( cv_event->event );
78  }
79  EnterCriticalSection( cs );
80  return true;
81 }
82 
83 void WINAPI wake_condition_variable_using_event( condition_variable_using_event* cv_event )
84 {
85  EnterCriticalSection( &cv_event->mutex );
86  if( cv_event->n_waiters>cv_event->release_count ) {
87  SetEvent( cv_event->event ); // Signal the manual-reset event.
88  ++cv_event->release_count;
89  ++cv_event->epoch;
90  }
91  LeaveCriticalSection( &cv_event->mutex );
92 }
93 
94 void WINAPI wake_all_condition_variable_using_event( condition_variable_using_event* cv_event )
95 {
96  EnterCriticalSection( &cv_event->mutex );
97  if( cv_event->n_waiters>0 ) {
98  SetEvent( cv_event->event );
99  cv_event->release_count = cv_event->n_waiters;
100  ++cv_event->epoch;
101  }
102  LeaveCriticalSection( &cv_event->mutex );
103 }
104 
105 void WINAPI destroy_condvar_using_event( condition_variable_using_event* cv_event )
106 {
107  HANDLE my_event = cv_event->event;
108  EnterCriticalSection( &cv_event->mutex );
109  // NULL is an invalid HANDLE value
110  cv_event->event = NULL;
111  if( cv_event->n_waiters>0 ) {
112  LeaveCriticalSection( &cv_event->mutex );
113  spin_wait_until_eq( cv_event->n_waiters, 0 );
114  // make sure the last thread completes its access to cv
115  EnterCriticalSection( &cv_event->mutex );
116  }
117  LeaveCriticalSection( &cv_event->mutex );
118  CloseHandle( my_event );
119 }
120 
121 void WINAPI destroy_condvar_noop( CONDITION_VARIABLE* /*cv*/ ) { /*no op*/ }
122 
123 static void (WINAPI *__TBB_init_condvar)( PCONDITION_VARIABLE ) = (void (WINAPI *)(PCONDITION_VARIABLE))&init_condvar_using_event;
124 static BOOL (WINAPI *__TBB_condvar_wait)( PCONDITION_VARIABLE, LPCRITICAL_SECTION, DWORD ) = (BOOL (WINAPI *)(PCONDITION_VARIABLE,LPCRITICAL_SECTION, DWORD))&sleep_condition_variable_cs_using_event;
125 static void (WINAPI *__TBB_condvar_notify_one)( PCONDITION_VARIABLE ) = (void (WINAPI *)(PCONDITION_VARIABLE))&wake_condition_variable_using_event;
126 static void (WINAPI *__TBB_condvar_notify_all)( PCONDITION_VARIABLE ) = (void (WINAPI *)(PCONDITION_VARIABLE))&wake_all_condition_variable_using_event;
127 static void (WINAPI *__TBB_destroy_condvar)( PCONDITION_VARIABLE ) = (void (WINAPI *)(PCONDITION_VARIABLE))&destroy_condvar_using_event;
128 
130 static const dynamic_link_descriptor CondVarLinkTable[] = {
131  DLD(InitializeConditionVariable, __TBB_init_condvar),
132  DLD(SleepConditionVariableCS, __TBB_condvar_wait),
133  DLD(WakeConditionVariable, __TBB_condvar_notify_one),
134  DLD(WakeAllConditionVariable, __TBB_condvar_notify_all)
135 };
136 
137 void init_condvar_module()
138 {
139  __TBB_ASSERT( (uintptr_t)__TBB_init_condvar==(uintptr_t)&init_condvar_using_event, NULL );
140 #if __TBB_WIN8UI_SUPPORT
141  // We expect condition variables to be always available for Windows* store applications,
142  // so there is no need to check presence and use alternative implementation.
143  __TBB_init_condvar = (void (WINAPI *)(PCONDITION_VARIABLE))&InitializeConditionVariable;
144  __TBB_condvar_wait = (BOOL(WINAPI *)(PCONDITION_VARIABLE, LPCRITICAL_SECTION, DWORD))&SleepConditionVariableCS;
145  __TBB_condvar_notify_one = (void (WINAPI *)(PCONDITION_VARIABLE))&WakeConditionVariable;
146  __TBB_condvar_notify_all = (void (WINAPI *)(PCONDITION_VARIABLE))&WakeAllConditionVariable;
147  __TBB_destroy_condvar = (void (WINAPI *)(PCONDITION_VARIABLE))&destroy_condvar_noop;
148 #else
149  if (dynamic_link("Kernel32.dll", CondVarLinkTable, 4))
150  __TBB_destroy_condvar = (void (WINAPI *)(PCONDITION_VARIABLE))&destroy_condvar_noop;
151 #endif
152 }
153 #endif /* _WIN32||_WIN64 */
154 
155 } // namespace internal
156 
157 #if _WIN32||_WIN64
158 
159 namespace interface5 {
160 namespace internal {
161 
162 using tbb::internal::condvar_api_state;
163 using tbb::internal::__TBB_init_condvar;
164 using tbb::internal::__TBB_condvar_wait;
165 using tbb::internal::__TBB_condvar_notify_one;
166 using tbb::internal::__TBB_condvar_notify_all;
167 using tbb::internal::__TBB_destroy_condvar;
168 using tbb::internal::init_condvar_module;
169 
170 void internal_initialize_condition_variable( condvar_impl_t& cv )
171 {
172  atomic_do_once( &init_condvar_module, condvar_api_state );
173  __TBB_init_condvar( &cv.cv_native );
174 }
175 
176 void internal_destroy_condition_variable( condvar_impl_t& cv )
177 {
178  __TBB_destroy_condvar( &cv.cv_native );
179 }
180 
181 void internal_condition_variable_notify_one( condvar_impl_t& cv )
182 {
183  __TBB_condvar_notify_one ( &cv.cv_native );
184 }
185 
186 void internal_condition_variable_notify_all( condvar_impl_t& cv )
187 {
188  __TBB_condvar_notify_all( &cv.cv_native );
189 }
190 
191 bool internal_condition_variable_wait( condvar_impl_t& cv, mutex* mtx, const tick_count::interval_t* i )
192 {
193  DWORD duration = i ? DWORD((i->seconds()*1000)) : INFINITE;
194  mtx->set_state( mutex::INITIALIZED );
195  BOOL res = __TBB_condvar_wait( &cv.cv_native, mtx->native_handle(), duration );
196  mtx->set_state( mutex::HELD );
197  return res?true:false;
198 }
199 
200 } // namespace internal
201 } // nameespace interface5
202 
203 #endif /* _WIN32||_WIN64 */
204 
205 } // namespace tbb
Association between a handler name and location of pointer to it.
Definition: dynamic_link.h:60
void spin_wait_until_eq(const volatile T &location, const U value)
Spin UNTIL the value of the variable is equal to a given value.
Definition: tbb_machine.h:399
void atomic_do_once(const F &initializer, atomic< do_once_state > &state)
One-time initialization function.
Definition: tbb_misc.h:213
OPEN_INTERNAL_NAMESPACE bool dynamic_link(const char *, const dynamic_link_descriptor *, size_t, dynamic_link_handle *handle, int)
#define __TBB_ASSERT(predicate, comment)
No-op version of __TBB_ASSERT.
Definition: tbb_stddef.h:165
void const char const char int ITT_FORMAT __itt_group_sync x void const char ITT_FORMAT __itt_group_sync s void ITT_FORMAT __itt_group_sync p void ITT_FORMAT p void ITT_FORMAT p no args __itt_suppress_mode_t unsigned int void size_t ITT_FORMAT d void ITT_FORMAT p void ITT_FORMAT p __itt_model_site __itt_model_site_instance ITT_FORMAT p __itt_model_task __itt_model_task_instance ITT_FORMAT p void ITT_FORMAT p void ITT_FORMAT p void size_t ITT_FORMAT d void ITT_FORMAT p const wchar_t ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s const char ITT_FORMAT s no args void ITT_FORMAT p size_t count
#define DLD(s, h)
The helper to construct dynamic_link_descriptor structure.
Definition: dynamic_link.h:56
The graph class.

Copyright © 2005-2020 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.