blob: 150299867e036db7bdff8588fd12f06840756ecd [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 }
Brian Silvermand8a7cf02014-03-22 17:15:23 -0700180 index_ = 0;
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800181}
182
183template <class T>
brians343bc112013-02-10 01:53:46 +0000184bool Queue<T>::FetchNext() {
185 Init();
Brian Silverman08661c72013-09-01 17:24:38 -0700186 const T *msg = static_cast<const T *>(
Austin Schuh287d98e2014-03-09 00:41:55 -0800187 queue_->ReadMessageIndex(RawQueue::kNonBlock, &index_));
brians343bc112013-02-10 01:53:46 +0000188 // Only update the internal pointer if we got a new message.
189 if (msg != NULL) {
190 queue_msg_.reset(msg);
191 }
192 return msg != NULL;
193}
194
195template <class T>
196bool Queue<T>::FetchNextBlocking() {
197 Init();
Austin Schuh287d98e2014-03-09 00:41:55 -0800198 const T *msg = static_cast<const T *>(queue_->ReadMessageIndex(RawQueue::kBlock, &index_));
brians343bc112013-02-10 01:53:46 +0000199 queue_msg_.reset(msg);
200 assert (msg != NULL);
201 return true;
202}
203
204template <class T>
205bool Queue<T>::FetchLatest() {
206 Init();
Austin Schuh287d98e2014-03-09 00:41:55 -0800207 const T *msg = static_cast<const T *>(queue_->ReadMessageIndex(
208 RawQueue::kFromEnd | RawQueue::kNonBlock, &index_));
brians343bc112013-02-10 01:53:46 +0000209 // Only update the internal pointer if we got a new message.
210 if (msg != NULL && msg != queue_msg_.get()) {
211 queue_msg_.reset(msg);
212 return true;
213 }
Brian Silverman08661c72013-09-01 17:24:38 -0700214 // The message has to get freed if we didn't use it (and RawQueue::FreeMessage
215 // is ok to call on NULL).
216 queue_->FreeMessage(msg);
brians343bc112013-02-10 01:53:46 +0000217 return false;
218}
219
220template <class T>
221SafeScopedMessagePtr<T> Queue<T>::SafeMakeMessage() {
222 Init();
223 SafeScopedMessagePtr<T> safe_msg(queue_);
224 safe_msg->Zero();
225 return safe_msg;
226}
227
228template <class T>
229ScopedMessagePtr<T> Queue<T>::MakeMessage() {
230 Init();
231 return ScopedMessagePtr<T>(queue_, MakeRawMessage());
232}
233
234template <class T>
235T *Queue<T>::MakeRawMessage() {
Brian Silverman08661c72013-09-01 17:24:38 -0700236 T *ret = static_cast<T *>(queue_->GetMessage());
brians35b15c42013-02-26 04:39:09 +0000237 assert(ret != NULL);
238 return ret;
brians343bc112013-02-10 01:53:46 +0000239}
240
241template <class T>
242aos::MessageBuilder<T> Queue<T>::MakeWithBuilder() {
243 Init();
244 return aos::MessageBuilder<T>(queue_, MakeRawMessage());
245}
246
247
248// This builder uses the safe message pointer so that it can be safely copied
Brian Silverman04fdc232014-02-12 14:51:11 -0800249// in places where it could be leaked.
brians343bc112013-02-10 01:53:46 +0000250template <class T>
251class SafeMessageBuilder {
252 public:
253 typedef T Message;
254 bool Send();
255};
256
257template <class T>
258aos::SafeMessageBuilder<T> Queue<T>::SafeMakeWithBuilder() {
259 Init();
260 return aos::SafeMessageBuilder<T>(queue_);
261}
262
263
264} // namespace aos