DUDS
Distributed Update of Data from Something
ChipSelectManager.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the DUDS project. It is subject to the BSD-style
3  * license terms in the LICENSE file found in the top-level directory of this
4  * distribution and at https://github.com/jjackowski/duds/blob/master/LICENSE.
5  * No part of DUDS, including this file, may be copied, modified, propagated,
6  * or distributed except according to the terms contained in the LICENSE file.
7  *
8  * Copyright (C) 2017 Jeff Jackowski
9  */
12 #include <duds/general/Errors.hpp>
13 
14 namespace duds { namespace hardware { namespace interface {
15 
16 ChipSelectManager::ChipSelectManager() : curacc(nullptr), cid(0), waiting(0) { }
17 
19 
21  // require exclusive access
22  std::unique_lock<std::mutex> lock(block);
23  // wait on current selection
24  while (curacc) {
25  selwait.wait(lock);
26  }
27  // set termination condition
28  cid = -1;
29  // clear waiting threads
30  selwait.notify_all();
31  // wait on threads
32  while (waiting) {
33  // this could throw an exception, but there seems to be no good
34  // response
35  selwait.wait(lock);
36  assert(waiting >= 0);
37  }
38 }
39 
41  if (ca == curacc) {
42  // deselect the chip
43  deselect();
44  // lose the access object; it should be destructing
45  curacc = nullptr;
46  // unblock one thread waiting on the chip, if any
47  selwait.notify_one();
48  } else {
49  // panic!
51  }
52 }
53 
55  std::lock_guard<std::mutex> lock(block);
56  if (!curacc) {
57  // bad request
59  }
60  // check for differnt ID
61  if (chipId != cid) {
62  // assure the new chip is valid
63  if (!validChip(chipId)) {
65  ChipSelectIdError(chipId));
66  }
67  // deselect the current chip
68  deselect();
69  // use the new chip
70  cid = chipId;
71  }
72 }
73 
74 void ChipSelectManager::baseAccess(std::unique_lock<std::mutex> &lock,
75 int chipId) {
76  if (!validChip(chipId)) {
78  ChipSelectIdError(chipId));
79  }
80  waiting++;
81  while (curacc) {
82  selwait.wait(lock);
83  }
84  waiting--;
85  // check termination condition
86  if (cid < 0) {
87  // no other threads waiting on access?
88  if (!waiting) {
89  // notify the destructing thread
90  selwait.notify_all();
91  }
93  }
94  // set the chip ID to access
95  cid = chipId;
96 }
97 
98 std::unique_ptr<ChipAccess> ChipSelectManager::access(int chipId) {
99  std::unique_lock<std::mutex> lock(block);
100  // obtain resources
101  baseAccess(lock, chipId);
102  // produce & return access object
103  return std::unique_ptr<ChipAccess>(
104  curacc = new ChipAccess(shared_from_this())
105  );
106 }
107 
108 void ChipSelectManager::access(ChipAccess &acc, int chipId) {
109  if (acc.manager) {
111  }
112  std::unique_lock<std::mutex> lock(block);
113  // obtain resources
114  baseAccess(lock, chipId);
115  // configure access object
116  acc.manager = shared_from_this();
117  curacc = &acc;
118 }
119 
120 std::unique_ptr<ChipAccess> ChipSelectManager::select(int chipId) {
121  std::unique_ptr<ChipAccess> ca = access(chipId);
122  select();
123  return ca;
124 }
125 
126 void ChipSelectManager::select(ChipAccess &acc, int chipId) {
127  access(acc, chipId);
128  select();
129 }
130 
131 } } }
void changeChip(int chipId)
Changes the chip in use while continuing to use an existing access object.
int waiting
A count of the threads waiting to access chips.
void retire(ChipAccess *ca)
Called by ChipAccess::~ChipAccess() to indicate that the access object is no longer in use...
ChipAccess * curacc
The currently in use access object, or nullptr.
A ChipAccess object was given to ChipSelectManager::access(ChipAccess &, int) that is already providi...
boost::error_info< struct Info_ChipId, int > ChipSelectIdError
The chip select ID relavent to the error.
An attempt was made to retire a ChipAccess object that was not the active access object for the manag...
virtual void deselect()=0
Deselects the chip identified by cid.
virtual void select()=0
Selects the chip identified by cid.
An error indicating an attempt to use an already destructed object.
Definition: Errors.hpp:85
std::mutex block
Used to synchonize access.
An object used to provide chip select control to a single user at a time.
Definition: ChipAccess.hpp:22
void baseAccess(std::unique_lock< std::mutex > &lock, int chipId)
Obtains the resources for providing an access object, but does not make an access object...
int cid
Selected chip ID, or -1 to terminate.
friend class ChipAccess
The access object calls select(), deselect(), and retire(ChipAccess *).
std::unique_ptr< ChipAccess > access(int chipId)
Acquires access to the requested chip and issues a ChipAccess object.
std::condition_variable selwait
Used to awaken threads waiting on a chip select.
Indicates an attempt to select a non-existant chip.
virtual bool validChip(int chipId) const noexcept=0
Returns true if chipId references a valid chip for this manager.
virtual ~ChipSelectManager()=0
Derived non-abstract classes must call shutdown() in thier destructor.
General errors.
#define DUDS_THROW_EXCEPTION(x)
Works like BOOST_THROW_EXCEPTION, but includes a stack trace if DUDS_ERRORS_VERBOSE is defined...
Definition: Errors.hpp:48
void shutdown()
Waits on a ChipAccess object if one is in use, then begins forcing any threads waiting on access to w...
std::shared_ptr< ChipSelectManager > manager
The manager to which this object is attached.
Definition: ChipAccess.hpp:34