blob: 84eb02cbbbccf624936b79268cec3dede9520dfa [file] [log] [blame]
brians343bc112013-02-10 01:53:46 +00001namespace aos {
2
3template <class T>
4bool ScopedMessagePtr<T>::Send() {
5 assert(msg_ != NULL);
6 msg_->SetTimeToNow();
7 assert(queue_ != NULL);
Brian Silverman08661c72013-09-01 17:24:38 -07008 bool return_value = queue_->WriteMessage(msg_, RawQueue::kOverride);
brians343bc112013-02-10 01:53:46 +00009 msg_ = NULL;
10 return return_value;
11}
12
13template <class T>
14bool ScopedMessagePtr<T>::SendBlocking() {
15 assert(msg_ != NULL);
16 msg_->SetTimeToNow();
17 assert(queue_ != NULL);
Brian Silverman08661c72013-09-01 17:24:38 -070018 bool return_value = queue_->WriteMessage(msg_, RawQueue::kBlock);
brians343bc112013-02-10 01:53:46 +000019 msg_ = NULL;
20 return return_value;
21}
22
23template <class T>
24void ScopedMessagePtr<T>::reset(T *msg) {
25 if (queue_ != NULL && msg_ != NULL) {
Brian Silverman078aee92013-11-12 22:17:05 -080026 queue_->FreeMessage(msg_);
brians343bc112013-02-10 01:53:46 +000027 }
28 msg_ = msg;
29}
30
31// A SafeScopedMessagePtr<> manages a message pointer.
32// It frees it properly when the ScopedMessagePtr<> goes out of scope or gets
33// sent. By design, there is no way to get the ScopedMessagePtr to release the
34// message pointer. When the message gets sent, it allocates a queue message,
35// copies the data into it, and then sends it. Copies copy the message.
36template <class T>
37class SafeScopedMessagePtr {
38 public:
39 // Returns a pointer to the message.
40 // This stays valid until Send or the destructor have been called.
41 T *get() { return msg_; }
42
43 T &operator*() {
44 T *msg = get();
45 assert(msg != NULL);
46 return *msg;
47 }
48
49 T *operator->() {
50 T *msg = get();
51 assert(msg != NULL);
52 return msg;
53 }
54
brians343bc112013-02-10 01:53:46 +000055 operator bool() {
56 return msg_ != NULL;
57 }
58
59 const T *get() const { return msg_; }
60
61 const T &operator*() const {
62 const T *msg = get();
63 assert(msg != NULL);
64 return *msg;
65 }
66
67 const T *operator->() const {
68 const T *msg = get();
69 assert(msg != NULL);
70 return msg;
71 }
brians343bc112013-02-10 01:53:46 +000072
73 // Sends the message and removes our reference to it.
74 // If the queue is full, over-rides the oldest message in it with our new
75 // message.
76 // Returns true on success, and false otherwise.
77 // The message will be freed.
78 bool Send() {
79 assert(msg_ != NULL);
80 assert(queue_ != NULL);
81 msg_->SetTimeToNow();
Brian Silverman08661c72013-09-01 17:24:38 -070082 T *shm_msg = static_cast<T *>(queue_->GetMessage());
brians343bc112013-02-10 01:53:46 +000083 if (shm_msg == NULL) {
84 return false;
85 }
86 *shm_msg = *msg_;
Brian Silverman08661c72013-09-01 17:24:38 -070087 bool return_value = queue_->WriteMessage(shm_msg, RawQueue::kOverride);
brians343bc112013-02-10 01:53:46 +000088 reset();
89 return return_value;
90 }
91
92 // Sends the message and removes our reference to it.
93 // If the queue is full, blocks until it is no longer full.
94 // Returns true on success, and false otherwise.
95 // Frees the message.
96 bool SendBlocking() {
97 assert(msg_ != NULL);
98 assert(queue_ != NULL);
99 msg_->SetTimeToNow();
Brian Silverman08661c72013-09-01 17:24:38 -0700100 T *shm_msg = static_cast<T *>(queue_->GetMessage());
brians343bc112013-02-10 01:53:46 +0000101 if (shm_msg == NULL) {
102 return false;
103 }
104 *shm_msg = *msg_;
Brian Silverman08661c72013-09-01 17:24:38 -0700105 bool return_value = queue_->WriteMessage(shm_msg, RawQueue::kBlock);
brians343bc112013-02-10 01:53:46 +0000106 reset();
107 return return_value;
108 }
109
110 // Frees the contained message.
111 ~SafeScopedMessagePtr() {
112 reset();
113 }
114
brians343bc112013-02-10 01:53:46 +0000115 // Implements a move constructor to take the message pointer from the
116 // temporary object to save work.
117 SafeScopedMessagePtr(SafeScopedMessagePtr<T> &&ptr)
118 : queue_(ptr.queue_),
119 msg_(ptr.msg_) {
120 ptr.msg_ = NULL;
121 }
brians343bc112013-02-10 01:53:46 +0000122
123 // Copy constructor actually copies the data.
124 SafeScopedMessagePtr(const SafeScopedMessagePtr<T> &ptr)
125 : queue_(ptr.queue_),
126 msg_(NULL) {
127 reset(new T(*ptr.get()));
128 }
brians343bc112013-02-10 01:53:46 +0000129 // Equal operator copies the data.
130 void operator=(const SafeScopedMessagePtr<T> &ptr) {
131 queue_ = ptr.queue_;
132 reset(new T(*ptr.get()));
133 }
brians343bc112013-02-10 01:53:46 +0000134
135 private:
136 // Provide access to private constructor.
137 friend class aos::Queue<typename std::remove_const<T>::type>;
138 friend class aos::SafeMessageBuilder<T>;
139
140 // Only Queue should be able to build a message pointer.
Brian Silverman08661c72013-09-01 17:24:38 -0700141 SafeScopedMessagePtr(RawQueue *queue)
brians343bc112013-02-10 01:53:46 +0000142 : queue_(queue), msg_(new T()) {}
143
144 // Sets the pointer to msg, freeing the old value if it was there.
145 // This is private because nobody should be able to get a pointer to a message
146 // that needs to be scoped without using the queue.
147 void reset(T *msg = NULL) {
148 if (msg_) {
149 delete msg_;
150 }
151 msg_ = msg;
152 }
153
154 // Sets the queue that owns this message.
Brian Silverman08661c72013-09-01 17:24:38 -0700155 void set_queue(RawQueue *queue) { queue_ = queue; }
brians343bc112013-02-10 01:53:46 +0000156
157 // The queue that the message is a part of.
Brian Silverman08661c72013-09-01 17:24:38 -0700158 RawQueue *queue_;
brians343bc112013-02-10 01:53:46 +0000159 // The message or NULL.
160 T *msg_;
161};
162
163template <class T>
164void Queue<T>::Init() {
165 if (queue_ == NULL) {
Brian Silverman08661c72013-09-01 17:24:38 -0700166 queue_ = RawQueue::Fetch(queue_name_, sizeof(T),
167 static_cast<int>(T::kHash),
168 T::kQueueLength);
brians343bc112013-02-10 01:53:46 +0000169 queue_msg_.set_queue(queue_);
170 }
171}
172
173template <class T>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800174void Queue<T>::Clear() {
Austin Schuhfa033692013-02-24 01:00:55 -0800175 if (queue_ != NULL) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800176 queue_msg_.reset();
177 queue_ = NULL;
178 queue_msg_.set_queue(NULL);
179 }
180}
181
182template <class T>
brians343bc112013-02-10 01:53:46 +0000183bool Queue<T>::FetchNext() {
184 Init();
Brian Silverman08661c72013-09-01 17:24:38 -0700185 // TODO(aschuh): Use RawQueue::ReadMessageIndex so that multiple readers
brians343bc112013-02-10 01:53:46 +0000186 // reading don't randomly get only part of the messages.
187 // Document here the tradoffs that are part of each method.
Brian Silverman08661c72013-09-01 17:24:38 -0700188 const T *msg = static_cast<const T *>(
189 queue_->ReadMessage(RawQueue::kNonBlock));
brians343bc112013-02-10 01:53:46 +0000190 // Only update the internal pointer if we got a new message.
191 if (msg != NULL) {
192 queue_msg_.reset(msg);
193 }
194 return msg != NULL;
195}
196
197template <class T>
198bool Queue<T>::FetchNextBlocking() {
199 Init();
Brian Silverman08661c72013-09-01 17:24:38 -0700200 const T *msg = static_cast<const T *>(queue_->ReadMessage(RawQueue::kBlock));
brians343bc112013-02-10 01:53:46 +0000201 queue_msg_.reset(msg);
202 assert (msg != NULL);
203 return true;
204}
205
206template <class T>
207bool Queue<T>::FetchLatest() {
208 Init();
Brian Silverman08661c72013-09-01 17:24:38 -0700209 const T *msg = static_cast<const T *>(queue_->ReadMessage(
210 RawQueue::kFromEnd | RawQueue::kNonBlock | RawQueue::kPeek));
brians343bc112013-02-10 01:53:46 +0000211 // Only update the internal pointer if we got a new message.
212 if (msg != NULL && msg != queue_msg_.get()) {
213 queue_msg_.reset(msg);
214 return true;
215 }
Brian Silverman08661c72013-09-01 17:24:38 -0700216 // The message has to get freed if we didn't use it (and RawQueue::FreeMessage
217 // is ok to call on NULL).
218 queue_->FreeMessage(msg);
brians343bc112013-02-10 01:53:46 +0000219 return false;
220}
221
222template <class T>
223SafeScopedMessagePtr<T> Queue<T>::SafeMakeMessage() {
224 Init();
225 SafeScopedMessagePtr<T> safe_msg(queue_);
226 safe_msg->Zero();
227 return safe_msg;
228}
229
230template <class T>
231ScopedMessagePtr<T> Queue<T>::MakeMessage() {
232 Init();
233 return ScopedMessagePtr<T>(queue_, MakeRawMessage());
234}
235
236template <class T>
237T *Queue<T>::MakeRawMessage() {
Brian Silverman08661c72013-09-01 17:24:38 -0700238 T *ret = static_cast<T *>(queue_->GetMessage());
brians35b15c42013-02-26 04:39:09 +0000239 assert(ret != NULL);
240 return ret;
brians343bc112013-02-10 01:53:46 +0000241}
242
243template <class T>
244aos::MessageBuilder<T> Queue<T>::MakeWithBuilder() {
245 Init();
246 return aos::MessageBuilder<T>(queue_, MakeRawMessage());
247}
248
249
250// This builder uses the safe message pointer so that it can be safely copied
Brian Silverman04fdc232014-02-12 14:51:11 -0800251// in places where it could be leaked.
brians343bc112013-02-10 01:53:46 +0000252template <class T>
253class SafeMessageBuilder {
254 public:
255 typedef T Message;
256 bool Send();
257};
258
259template <class T>
260aos::SafeMessageBuilder<T> Queue<T>::SafeMakeWithBuilder() {
261 Init();
262 return aos::SafeMessageBuilder<T>(queue_);
263}
264
265
266} // namespace aos