blob: 0cc93920fbecaca5a8af3be2f78a6eef9d95262e [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 Silverman08661c72013-09-01 17:24:38 -070026 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
55#ifndef SWIG
56 operator bool() {
57 return msg_ != NULL;
58 }
59
60 const T *get() const { return msg_; }
61
62 const T &operator*() const {
63 const T *msg = get();
64 assert(msg != NULL);
65 return *msg;
66 }
67
68 const T *operator->() const {
69 const T *msg = get();
70 assert(msg != NULL);
71 return msg;
72 }
73#endif // SWIG
74
75 // Sends the message and removes our reference to it.
76 // If the queue is full, over-rides the oldest message in it with our new
77 // message.
78 // Returns true on success, and false otherwise.
79 // The message will be freed.
80 bool Send() {
81 assert(msg_ != NULL);
82 assert(queue_ != NULL);
83 msg_->SetTimeToNow();
Brian Silverman08661c72013-09-01 17:24:38 -070084 T *shm_msg = static_cast<T *>(queue_->GetMessage());
brians343bc112013-02-10 01:53:46 +000085 if (shm_msg == NULL) {
86 return false;
87 }
88 *shm_msg = *msg_;
Brian Silverman08661c72013-09-01 17:24:38 -070089 bool return_value = queue_->WriteMessage(shm_msg, RawQueue::kOverride);
brians343bc112013-02-10 01:53:46 +000090 reset();
91 return return_value;
92 }
93
94 // Sends the message and removes our reference to it.
95 // If the queue is full, blocks until it is no longer full.
96 // Returns true on success, and false otherwise.
97 // Frees the message.
98 bool SendBlocking() {
99 assert(msg_ != NULL);
100 assert(queue_ != NULL);
101 msg_->SetTimeToNow();
Brian Silverman08661c72013-09-01 17:24:38 -0700102 T *shm_msg = static_cast<T *>(queue_->GetMessage());
brians343bc112013-02-10 01:53:46 +0000103 if (shm_msg == NULL) {
104 return false;
105 }
106 *shm_msg = *msg_;
Brian Silverman08661c72013-09-01 17:24:38 -0700107 bool return_value = queue_->WriteMessage(shm_msg, RawQueue::kBlock);
brians343bc112013-02-10 01:53:46 +0000108 reset();
109 return return_value;
110 }
111
112 // Frees the contained message.
113 ~SafeScopedMessagePtr() {
114 reset();
115 }
116
117#ifndef SWIG
118 // Implements a move constructor to take the message pointer from the
119 // temporary object to save work.
120 SafeScopedMessagePtr(SafeScopedMessagePtr<T> &&ptr)
121 : queue_(ptr.queue_),
122 msg_(ptr.msg_) {
123 ptr.msg_ = NULL;
124 }
125#endif // SWIG
126
127 // Copy constructor actually copies the data.
128 SafeScopedMessagePtr(const SafeScopedMessagePtr<T> &ptr)
129 : queue_(ptr.queue_),
130 msg_(NULL) {
131 reset(new T(*ptr.get()));
132 }
133#ifndef SWIG
134 // Equal operator copies the data.
135 void operator=(const SafeScopedMessagePtr<T> &ptr) {
136 queue_ = ptr.queue_;
137 reset(new T(*ptr.get()));
138 }
139#endif // SWIG
140
141 private:
142 // Provide access to private constructor.
143 friend class aos::Queue<typename std::remove_const<T>::type>;
144 friend class aos::SafeMessageBuilder<T>;
145
146 // Only Queue should be able to build a message pointer.
Brian Silverman08661c72013-09-01 17:24:38 -0700147 SafeScopedMessagePtr(RawQueue *queue)
brians343bc112013-02-10 01:53:46 +0000148 : queue_(queue), msg_(new T()) {}
149
150 // Sets the pointer to msg, freeing the old value if it was there.
151 // This is private because nobody should be able to get a pointer to a message
152 // that needs to be scoped without using the queue.
153 void reset(T *msg = NULL) {
154 if (msg_) {
155 delete msg_;
156 }
157 msg_ = msg;
158 }
159
160 // Sets the queue that owns this message.
Brian Silverman08661c72013-09-01 17:24:38 -0700161 void set_queue(RawQueue *queue) { queue_ = queue; }
brians343bc112013-02-10 01:53:46 +0000162
163 // The queue that the message is a part of.
Brian Silverman08661c72013-09-01 17:24:38 -0700164 RawQueue *queue_;
brians343bc112013-02-10 01:53:46 +0000165 // The message or NULL.
166 T *msg_;
167};
168
169template <class T>
170void Queue<T>::Init() {
171 if (queue_ == NULL) {
Brian Silverman08661c72013-09-01 17:24:38 -0700172 queue_ = RawQueue::Fetch(queue_name_, sizeof(T),
173 static_cast<int>(T::kHash),
174 T::kQueueLength);
brians343bc112013-02-10 01:53:46 +0000175 queue_msg_.set_queue(queue_);
176 }
177}
178
179template <class T>
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800180void Queue<T>::Clear() {
Austin Schuhfa033692013-02-24 01:00:55 -0800181 if (queue_ != NULL) {
Austin Schuhdc1c84a2013-02-23 16:33:10 -0800182 queue_msg_.reset();
183 queue_ = NULL;
184 queue_msg_.set_queue(NULL);
185 }
186}
187
188template <class T>
brians343bc112013-02-10 01:53:46 +0000189bool Queue<T>::FetchNext() {
190 Init();
Brian Silverman08661c72013-09-01 17:24:38 -0700191 // TODO(aschuh): Use RawQueue::ReadMessageIndex so that multiple readers
brians343bc112013-02-10 01:53:46 +0000192 // reading don't randomly get only part of the messages.
193 // Document here the tradoffs that are part of each method.
Brian Silverman08661c72013-09-01 17:24:38 -0700194 const T *msg = static_cast<const T *>(
195 queue_->ReadMessage(RawQueue::kNonBlock));
brians343bc112013-02-10 01:53:46 +0000196 // Only update the internal pointer if we got a new message.
197 if (msg != NULL) {
198 queue_msg_.reset(msg);
199 }
200 return msg != NULL;
201}
202
203template <class T>
204bool Queue<T>::FetchNextBlocking() {
205 Init();
Brian Silverman08661c72013-09-01 17:24:38 -0700206 const T *msg = static_cast<const T *>(queue_->ReadMessage(RawQueue::kBlock));
brians343bc112013-02-10 01:53:46 +0000207 queue_msg_.reset(msg);
208 assert (msg != NULL);
209 return true;
210}
211
212template <class T>
213bool Queue<T>::FetchLatest() {
214 Init();
Brian Silverman08661c72013-09-01 17:24:38 -0700215 const T *msg = static_cast<const T *>(queue_->ReadMessage(
216 RawQueue::kFromEnd | RawQueue::kNonBlock | RawQueue::kPeek));
brians343bc112013-02-10 01:53:46 +0000217 // Only update the internal pointer if we got a new message.
218 if (msg != NULL && msg != queue_msg_.get()) {
219 queue_msg_.reset(msg);
220 return true;
221 }
Brian Silverman08661c72013-09-01 17:24:38 -0700222 // The message has to get freed if we didn't use it (and RawQueue::FreeMessage
223 // is ok to call on NULL).
224 queue_->FreeMessage(msg);
brians343bc112013-02-10 01:53:46 +0000225 return false;
226}
227
228template <class T>
229SafeScopedMessagePtr<T> Queue<T>::SafeMakeMessage() {
230 Init();
231 SafeScopedMessagePtr<T> safe_msg(queue_);
232 safe_msg->Zero();
233 return safe_msg;
234}
235
236template <class T>
237ScopedMessagePtr<T> Queue<T>::MakeMessage() {
238 Init();
239 return ScopedMessagePtr<T>(queue_, MakeRawMessage());
240}
241
242template <class T>
243T *Queue<T>::MakeRawMessage() {
Brian Silverman08661c72013-09-01 17:24:38 -0700244 T *ret = static_cast<T *>(queue_->GetMessage());
brians35b15c42013-02-26 04:39:09 +0000245 assert(ret != NULL);
246 return ret;
brians343bc112013-02-10 01:53:46 +0000247}
248
249template <class T>
250aos::MessageBuilder<T> Queue<T>::MakeWithBuilder() {
251 Init();
252 return aos::MessageBuilder<T>(queue_, MakeRawMessage());
253}
254
255
256// This builder uses the safe message pointer so that it can be safely copied
257// and used by SWIG or in places where it could be leaked.
258template <class T>
259class SafeMessageBuilder {
260 public:
261 typedef T Message;
262 bool Send();
263};
264
265template <class T>
266aos::SafeMessageBuilder<T> Queue<T>::SafeMakeWithBuilder() {
267 Init();
268 return aos::SafeMessageBuilder<T>(queue_);
269}
270
271
272} // namespace aos