Intel(R) Threading Building Blocks Doxygen Documentation version 4.2.3
Loading...
Searching...
No Matches
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
24namespace tbb {
25
26namespace internal {
27
28//condition_variable
29#if _WIN32||_WIN64
30using tbb::interface5::internal::condition_variable_using_event;
31
32static atomic<do_once_state> condvar_api_state;
33
34void 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
44BOOL 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
83void 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
94void 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
105void 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
121void WINAPI destroy_condvar_noop( CONDITION_VARIABLE* /*cv*/ ) { /*no op*/ }
122
123static void (WINAPI *__TBB_init_condvar)( PCONDITION_VARIABLE ) = (void (WINAPI *)(PCONDITION_VARIABLE))&init_condvar_using_event;
124static BOOL (WINAPI *__TBB_condvar_wait)( PCONDITION_VARIABLE, LPCRITICAL_SECTION, DWORD ) = (BOOL (WINAPI *)(PCONDITION_VARIABLE,LPCRITICAL_SECTION, DWORD))&sleep_condition_variable_cs_using_event;
125static void (WINAPI *__TBB_condvar_notify_one)( PCONDITION_VARIABLE ) = (void (WINAPI *)(PCONDITION_VARIABLE))&wake_condition_variable_using_event;
126static void (WINAPI *__TBB_condvar_notify_all)( PCONDITION_VARIABLE ) = (void (WINAPI *)(PCONDITION_VARIABLE))&wake_all_condition_variable_using_event;
127static void (WINAPI *__TBB_destroy_condvar)( PCONDITION_VARIABLE ) = (void (WINAPI *)(PCONDITION_VARIABLE))&destroy_condvar_using_event;
128
130static 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
137void 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
159namespace interface5 {
160namespace internal {
161
162using tbb::internal::condvar_api_state;
163using tbb::internal::__TBB_init_condvar;
164using tbb::internal::__TBB_condvar_wait;
165using tbb::internal::__TBB_condvar_notify_one;
166using tbb::internal::__TBB_condvar_notify_all;
167using tbb::internal::__TBB_destroy_condvar;
168using tbb::internal::init_condvar_module;
169
170void 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
176void internal_destroy_condition_variable( condvar_impl_t& cv )
177{
178 __TBB_destroy_condvar( &cv.cv_native );
179}
180
181void internal_condition_variable_notify_one( condvar_impl_t& cv )
182{
183 __TBB_condvar_notify_one ( &cv.cv_native );
184}
185
186void internal_condition_variable_notify_all( condvar_impl_t& cv )
187{
188 __TBB_condvar_notify_all( &cv.cv_native );
189}
190
191bool 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
#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
OPEN_INTERNAL_NAMESPACE bool dynamic_link(const char *, const dynamic_link_descriptor *, size_t, dynamic_link_handle *handle, int)
#define DLD(s, h)
The helper to construct dynamic_link_descriptor structure.
Definition: dynamic_link.h:56
The graph class.
void atomic_do_once(const F &initializer, atomic< do_once_state > &state)
One-time initialization function.
Definition: tbb_misc.h:213
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
Association between a handler name and location of pointer to it.
Definition: dynamic_link.h:60

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.