CUBRID Engine  latest
critical_section_tracker.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * critical_section_tracker.cpp - implementation for tracking and debugging critical sections usage
21  */
22 
24 
25 #include "resource_tracker.hpp"
26 
27 #include <iostream>
28 
29 namespace cubsync
30 {
32  //
34 
35  static void
36  cstrack_assert (bool cond)
37  {
39  }
40 
42  : m_enter_count (0)
43  , m_is_writer (false)
44  , m_is_demoted (false)
45  {
46  //
47  }
48 
50  : m_cstrack_array {}
51  , m_enabled (enable)
52  , m_start_count (0)
53  {
54  //
55  }
56 
57  void
59  {
60  if (!m_enabled || !is_started ())
61  {
62  return;
63  }
64 
66 
67  cstrack_entry &cs_entry = m_cstrack_array[cs_index];
68 
69  // is first enter?
70  if (cs_entry.m_enter_count == 0)
71  {
72  cstrack_assert (!cs_entry.m_is_writer && !cs_entry.m_is_demoted);
73  cs_entry.m_enter_count++;
74  return;
75  }
76  // is not first enter.
77  assert (cs_entry.m_enter_count < MAX_REENTERS);
78 
79  if (cs_entry.m_is_writer)
80  {
81  // already entered as writer
82  // this case is allowed. if I am a writer, I will not be blocked as readers
83  cs_entry.m_enter_count++;
84  }
85  else if (cs_entry.m_is_demoted)
86  {
87  // I am not entirely sure why we allow when lock is demoted.
88  cs_entry.m_enter_count++;
89  }
90  else
91  {
92  // re-enter is not accepted, since it may cause deadlocks.
93  cs_entry.m_enter_count++;
94  cstrack_assert (false);
95  }
96  }
97 
98  void
100  {
101  if (!m_enabled || !is_started ())
102  {
103  return;
104  }
105 
106  cstrack_entry &cs_entry = m_cstrack_array[cs_index];
107 
109 
110  // is first enter?
111  if (cs_entry.m_enter_count == 0)
112  {
113  cstrack_assert (!cs_entry.m_is_writer && !cs_entry.m_is_demoted);
114  cs_entry.m_is_writer = true;
115  cs_entry.m_enter_count++;
116  return;
117  }
118  // is not first enter.
119 
120  // re-enter is only accepted if it was already writer
121  cstrack_assert (cs_entry.m_is_writer);
122  cs_entry.m_enter_count++;
123  }
124 
125  void
127  {
128  if (!m_enabled || !is_started ())
129  {
130  return;
131  }
132 
133  cstrack_entry &cs_entry = m_cstrack_array[cs_index];
134 
135  // I must be reader
136  cstrack_assert (!cs_entry.m_is_writer);
137  cstrack_assert (cs_entry.m_enter_count == 1);
138 
139  cs_entry.m_is_writer = true;
140  cs_entry.m_is_demoted = false;
141  }
142 
143  void
145  {
146  if (!m_enabled || !is_started ())
147  {
148  return;
149  }
150 
151  cstrack_entry &cs_entry = m_cstrack_array[cs_index];
152 
153  // I must be writer
154  cstrack_assert (cs_entry.m_is_writer);
155  cstrack_assert (cs_entry.m_enter_count == 1);
156 
157  cs_entry.m_is_writer = false;
158  cs_entry.m_is_demoted = true;
159  }
160 
161  void
163  {
164  if (!m_enabled || !is_started ())
165  {
166  return;
167  }
168 
169  cstrack_entry &cs_entry = m_cstrack_array[cs_index];
170 
171  if (cs_entry.m_enter_count == 0)
172  {
173  cstrack_assert (false);
174  return;
175  }
176 
177  --cs_entry.m_enter_count;
178  if (cs_entry.m_enter_count == 0)
179  {
180  cs_entry.m_is_demoted = false;
181  cs_entry.m_is_writer = false;
182  }
183  }
184 
185  void
187  {
188  if (cs_index == CSECT_LOCATOR_SR_CLASSNAME_TABLE)
189  {
190  cstrack_assert (m_cstrack_array[CSECT_CT_OID_TABLE].m_enter_count == 0);
191  }
192  }
193 
194  bool
196  {
197  return m_start_count > 0;
198  }
199 
200  void
202  {
203  if (!m_enabled)
204  {
205  return;
206  }
207  m_start_count++;
208  }
209 
210  void
212  {
213  if (!m_enabled)
214  {
215  return;
216  }
217 
218  if (m_start_count == 0)
219  {
220  cstrack_assert (false);
221  }
222  else
223  {
224  m_start_count--;
225  }
226 
227  if (m_start_count == 0)
228  {
229  // check no critical section is entered
230  clear_all ();
231  }
232  }
233 
234  void
236  {
237  bool m_printed_header = false;
238  std::ostream &os = std::cerr;
239 
240  for (int cs_index = 0; cs_index < CRITICAL_SECTION_COUNT; cs_index++)
241  {
242  if (m_cstrack_array[cs_index].m_enter_count > 0)
243  {
244  if (!m_printed_header)
245  {
246  os << " +--- Critical Sections" << std::endl;
247  m_printed_header = true;
248  }
249  os << " +--- " << csect_name_at (cs_index) << std::endl;
250  os << " +--- enter count = " << m_cstrack_array[cs_index].m_enter_count << std::endl;
251  os << " +--- is writer = " << m_cstrack_array[cs_index].m_is_writer << std::endl;
252  os << " +--- is demoted = " << m_cstrack_array[cs_index].m_is_demoted << std::endl;
253 
254  cstrack_assert (false);
255  }
256  }
257  }
258 
259  void
261  {
262  check ();
263  for (int cs_index = 0; cs_index < CRITICAL_SECTION_COUNT; cs_index++)
264  {
265  // reset
266  m_cstrack_array[cs_index] = {};
267  }
268  m_start_count = 0;
269  }
270 } // namespace cubsync
bool m_is_demoted
cstrack_entry()
#define assert(x)
bool m_is_writer
static void cstrack_assert(bool cond)
static const int CRITICAL_SECTION_COUNT
void restrack_assert(bool cond)
cstrack_entry m_cstrack_array[CRITICAL_SECTION_COUNT]
std::uint8_t m_enter_count
const char * csect_name_at(int cs_index)