blob: 98091cf17d18f23b01e37a049cd9ef9e13b8f456 [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 const T *msg = static_cast<const T *>(
Austin Schuh287d98e2014-03-09 00:41:55 -0800186 queue_->ReadMessageIndex(RawQueue::kNonBlock, &index_));
brians343bc112013-02-10 01:53:46 +0000187 // Only update the internal pointer if we got a new message.
188 if (msg != NULL) {
189 queue_msg_.reset(msg);
190 }
191 return msg != NULL;
192}
193
194template <class T>
195bool Queue<T>::FetchNextBlocking() {
196 Init();
Austin Schuh287d98e2014-03-09 00:41:55 -0800197 const T *msg = static_cast<const T *>(queue_->ReadMessageIndex(RawQueue::kBlock, &index_));
brians343bc112013-02-10 01:53:46 +0000198 queue_msg_.reset(msg);
199 assert (msg != NULL);
200 return true;
201}
202
203template <class T>
204bool Queue<T>::FetchLatest() {
205 Init();
Austin Schuh287d98e2014-03-09 00:41:55 -0800206 const T *msg = static_cast<const T *>(queue_->ReadMessageIndex(
207 RawQueue::kFromEnd | RawQueue::kNonBlock, &index_));
brians343bc112013-02-10 01:53:46 +0000208 // Only update the internal pointer if we got a new message.
209 if (msg != NULL && msg != queue_msg_.get()) {
210 queue_msg_.reset(msg);
211 return true;
212 }
Brian Silverman08661c72013-09-01 17:24:38 -0700213 // The message has to get freed if we didn't use it (and RawQueue::FreeMessage
214 // is ok to call on NULL).
215 queue_->FreeMessage(msg);
brians343bc112013-02-10 01:53:46 +0000216 return false;
217}
218
219template <class T>
220SafeScopedMessagePtr<T> Queue<T>::SafeMakeMessage() {
221 Init();
222 SafeScopedMessagePtr<T> safe_msg(queue_);
223 safe_msg->Zero();
224 return safe_msg;
225}
226
227template <class T>
228ScopedMessagePtr<T> Queue<T>::MakeMessage() {
229 Init();
230 return ScopedMessagePtr<T>(queue_, MakeRawMessage());
231}
232
233template <class T>
234T *Queue<T>::MakeRawMessage() {
Brian Silverman08661c72013-09-01 17:24:38 -0700235 T *ret = static_cast<T *>(queue_->GetMessage());
brians35b15c42013-02-26 04:39:09 +0000236 assert(ret != NULL);
237 return ret;
brians343bc112013-02-10 01:53:46 +0000238}
239
240template <class T>
241aos::MessageBuilder<T> Queue<T>::MakeWithBuilder() {
242 Init();
243 return aos::MessageBuilder<T>(queue_, MakeRawMessage());
244}
245
246
247// This builder uses the safe message pointer so that it can be safely copied
Brian Silverman04fdc232014-02-12 14:51:11 -0800248// in places where it could be leaked.
brians343bc112013-02-10 01:53:46 +0000249template <class T>
250class SafeMessageBuilder {
251 public:
252 typedef T Message;
253 bool Send();
254};
255
256template <class T>
257aos::SafeMessageBuilder<T> Queue<T>::SafeMakeWithBuilder() {
258 Init();
259 return aos::SafeMessageBuilder<T>(queue_);
260}
261
262
263} // namespace aos