OSVR Framework (Internal Development Docs)  0.6-1962-g59773924
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
AsyncAccessControl.cpp
Go to the documentation of this file.
1 
11 // Copyright 2014 Sensics, Inc.
12 //
13 // Licensed under the Apache License, Version 2.0 (the "License");
14 // you may not use this file except in compliance with the License.
15 // You may obtain a copy of the License at
16 //
17 // http://www.apache.org/licenses/LICENSE-2.0
18 //
19 // Unless required by applicable law or agreed to in writing, software
20 // distributed under the License is distributed on an "AS IS" BASIS,
21 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 // See the License for the specific language governing permissions and
23 // limitations under the License.
24 
25 // Internal Includes
26 #include "AsyncAccessControl.h"
27 #include <osvr/Util/Verbosity.h>
28 
29 // Library/third-party includes
30 #include <boost/assert.hpp>
31 
32 // Standard includes
33 #include <stdexcept>
34 
35 namespace osvr {
36 namespace connection {
37 
38  using boost::defer_lock;
40  : m_lock(aac.m_mut, defer_lock), m_lockDone(aac.m_mutDone, defer_lock),
41  m_calledRequest(false), m_nested(false), m_control(aac),
42  m_sharedRts(aac.m_rts), m_sharedDone(aac.m_done),
43  m_mainMessage(aac.m_mainMessage),
44  m_condMainThread(aac.m_condMainThread),
45  m_condAsyncThread(aac.m_condAsyncThread) {}
46 
48  BOOST_ASSERT_MSG(m_lock.owns_lock() == m_lockDone.owns_lock(),
49  "We should own either both locks or neither.");
50  if (m_lock.owns_lock() && m_lockDone.owns_lock()) {
51  m_sharedRts = false;
52  m_sharedDone = true;
53  m_control.m_currentRequestThread.reset();
54  m_lock.unlock();
55  m_lockDone.unlock();
56  m_condMainThread.notify_one();
57  }
58  }
60  BOOST_ASSERT_MSG(m_calledRequest == false,
61  "Can only try to request once "
62  "on a single RequestToSend "
63  "object lifetime");
64  {
65  m_lock.lock();
66  if (m_sharedRts &&
67  m_control.m_currentRequestThread ==
68  boost::this_thread::get_id()) {
71  m_nested = true;
72  m_lock.unlock();
73  return true;
74  }
75 
76  BOOST_ASSERT_MSG(m_sharedRts == false,
77  "Shouldn't happen - inconsistent "
78  "state. Can't get in a request when "
79  "already in one.");
80  m_sharedRts = true;
81  m_sharedDone = false;
82  m_calledRequest = true;
84  {
85  m_lockDone.lock();
86  m_sharedDone = false;
87  while (m_mainMessage == AsyncAccessControl::MTM_WAIT) {
88  m_condAsyncThread.wait(
89  m_lock); // In here we unlock the mutex
90  // until we are notified.
91  }
92  // The mutex is locked again here, until the destructor.
93 
94  // Get the return value.
95  auto ret =
96  (m_mainMessage == AsyncAccessControl::MTM_CLEAR_TO_SEND);
97  if (ret) {
98  BOOST_ASSERT_MSG(
99  !m_control.m_currentRequestThread.is_initialized(),
100  "Shouldn't be anyone in except us!");
101  m_control.m_currentRequestThread =
102  boost::this_thread::get_id();
103  }
104  return ret;
105  }
106  }
107  }
108 
110  : m_rts(false), m_done(false), m_mainMessage(MTM_WAIT) {}
111 
112  bool AsyncAccessControl::mainThreadCTS() {
113  MainLockType lock(m_mut);
114  return m_handleRTS(lock, MTM_CLEAR_TO_SEND);
115  }
116 
118  MainLockType lock(m_mut);
119  return m_handleRTS(lock, MTM_DENY_SEND);
120  }
121 
123  MainLockType lock(m_mut);
124  bool handled = m_handleRTS(lock, MTM_DENY_SEND, MTM_DENY_SEND);
125  if (!handled) {
126  BOOST_ASSERT_MSG(lock.owns_lock(),
127  "if m_handleRTS returns false, "
128  "we're supposed to still own the "
129  "lock!");
130  // Even if we didn't have any RTS at the time, we still want to set
131  // the state to DENY
132  m_mainMessage = MTM_DENY_SEND;
133  }
134  return handled;
135  }
136 
137  bool
138  AsyncAccessControl::m_handleRTS(MainLockType &lock,
139  MainThreadMessages response,
140  MainThreadMessages postCompletionState) {
141  if (!lock.owns_lock() || (lock.mutex() != &m_mut)) {
142  throw std::logic_error(
143  "m_handleRTS requires its caller to pass a lock "
144  "owning the main mutex!");
145  }
146  if (!m_rts) {
147  return false; // No RTS to handle, so didn't handle a RTS
148  }
149 
150  // In here, then, there must be an RTS.
151  m_mainMessage = response;
152  lock.unlock(); // Unlock to let the requestor through.
153  m_condAsyncThread.notify_one();
154  {
155  DoneLockType finishedLock(m_mutDone);
156  while (!m_done) {
157  // Wait for the request to complete.
158  m_condMainThread.wait(finishedLock);
159  }
160  // Restore wait message (or deny message if denying permanently.)
161  m_mainMessage = postCompletionState;
162  return true; // handled an RTS, passed-in lock now unlocked.
163  }
164  }
165 
166 } // namespace connection
167 } // namespace osvr
bool mainThreadDenyPermanently()
Permanently deny present and future requests.
bool mainThreadDeny()
Check for waiting async thread, and deny it permission to send if found.
Internal class handling the synchronization of an asynchronous thread wishing to communicate that has...
bool request()
Issues a blocking request to send.
RequestToSend(AsyncAccessControl &aac)
Creates an RAII object to manage the request to send - note that it does not immediately request to s...
Internal, configured header file for verbosity macros.