1 /*
2 * Copyright (C) Texas Instruments - http://www.ti.com/
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18 #include <errno.h>
19 #include <string.h>
20 #include <sys/types.h>
21 #include <sys/poll.h>
22 #include <unistd.h>
23 #include <utils/Errors.h>
24
25
26
27 #define LOG_TAG "MessageQueue"
28 #include <utils/Log.h>
29
30 #include "MessageQueue.h"
31
32 namespace TIUTILS {
33
34 /**
35 @brief Constructor for the message queue class
36
37 @param none
38 @return none
39 */
MessageQueue()40 MessageQueue::MessageQueue()
41 {
42 LOG_FUNCTION_NAME;
43
44 int fds[2] = {-1,-1};
45 android::status_t stat;
46
47 stat = pipe(fds);
48
49 if ( 0 > stat )
50 {
51 MSGQ_LOGEB("Error while openning pipe: %s", strerror(stat) );
52 this->fd_read = 0;
53 this->fd_write = 0;
54 mHasMsg = false;
55 }
56 else
57 {
58 this->fd_read = fds[0];
59 this->fd_write = fds[1];
60
61 mHasMsg = false;
62 }
63
64 LOG_FUNCTION_NAME_EXIT;
65 }
66
67 /**
68 @brief Destructor for the semaphore class
69
70 @param none
71 @return none
72 */
~MessageQueue()73 MessageQueue::~MessageQueue()
74 {
75 LOG_FUNCTION_NAME;
76
77 if(this->fd_read >= 0)
78 {
79 close(this->fd_read);
80 }
81
82 if(this->fd_write >= 0)
83 {
84 close(this->fd_write);
85 }
86
87 LOG_FUNCTION_NAME_EXIT;
88 }
89
90 /**
91 @brief Get a message from the queue
92
93 @param msg Message structure to hold the message to be retrieved
94 @return android::NO_ERROR On success
95 @return android::BAD_VALUE if the message pointer is NULL
96 @return android::NO_INIT If the file read descriptor is not set
97 @return android::UNKNOWN_ERROR if the read operation fromthe file read descriptor fails
98 */
get(Message * msg)99 android::status_t MessageQueue::get(Message* msg)
100 {
101 LOG_FUNCTION_NAME;
102
103 if(!msg)
104 {
105 MSGQ_LOGEA("msg is NULL");
106 LOG_FUNCTION_NAME_EXIT;
107 return android::BAD_VALUE;
108 }
109
110 if(!this->fd_read)
111 {
112 MSGQ_LOGEA("read descriptor not initialized for message queue");
113 LOG_FUNCTION_NAME_EXIT;
114 return android::NO_INIT;
115 }
116
117 char* p = (char*) msg;
118 size_t read_bytes = 0;
119
120 while( read_bytes < sizeof(*msg) )
121 {
122 int err = read(this->fd_read, p, sizeof(*msg) - read_bytes);
123
124 if( err < 0 )
125 {
126 MSGQ_LOGEB("read() error: %s", strerror(errno));
127 return android::UNKNOWN_ERROR;
128 }
129 else
130 {
131 read_bytes += err;
132 }
133 }
134
135 MSGQ_LOGDB("MQ.get(%d,%p,%p,%p,%p)", msg->command, msg->arg1,msg->arg2,msg->arg3,msg->arg4);
136
137 mHasMsg = false;
138
139 LOG_FUNCTION_NAME_EXIT;
140
141 return 0;
142 }
143
144 /**
145 @brief Get the input file descriptor of the message queue
146
147 @param none
148 @return file read descriptor
149 */
150
getInFd()151 int MessageQueue::getInFd()
152 {
153 return this->fd_read;
154 }
155
156 /**
157 @brief Constructor for the message queue class
158
159 @param fd file read descriptor
160 @return none
161 */
162
setInFd(int fd)163 void MessageQueue::setInFd(int fd)
164 {
165 LOG_FUNCTION_NAME;
166
167 if ( -1 != this->fd_read )
168 {
169 close(this->fd_read);
170 }
171
172 this->fd_read = fd;
173
174 LOG_FUNCTION_NAME_EXIT;
175 }
176
177 /**
178 @brief Queue a message
179
180 @param msg Message structure to hold the message to be retrieved
181 @return android::NO_ERROR On success
182 @return android::BAD_VALUE if the message pointer is NULL
183 @return android::NO_INIT If the file write descriptor is not set
184 @return android::UNKNOWN_ERROR if the write operation fromthe file write descriptor fails
185 */
186
put(Message * msg)187 android::status_t MessageQueue::put(Message* msg)
188 {
189 LOG_FUNCTION_NAME;
190
191 char* p = (char*) msg;
192 size_t bytes = 0;
193
194 if(!msg)
195 {
196 MSGQ_LOGEA("msg is NULL");
197 LOG_FUNCTION_NAME_EXIT;
198 return android::BAD_VALUE;
199 }
200
201 if(!this->fd_write)
202 {
203 MSGQ_LOGEA("write descriptor not initialized for message queue");
204 LOG_FUNCTION_NAME_EXIT;
205 return android::NO_INIT;
206 }
207
208
209 MSGQ_LOGDB("MQ.put(%d,%p,%p,%p,%p)", msg->command, msg->arg1,msg->arg2,msg->arg3,msg->arg4);
210
211 while( bytes < sizeof(msg) )
212 {
213 int err = write(this->fd_write, p, sizeof(*msg) - bytes);
214
215 if( err < 0 )
216 {
217 MSGQ_LOGEB("write() error: %s", strerror(errno));
218 LOG_FUNCTION_NAME_EXIT;
219 return android::UNKNOWN_ERROR;
220 }
221 else
222 {
223 bytes += err;
224 }
225 }
226
227 MSGQ_LOGDA("MessageQueue::put EXIT");
228
229 LOG_FUNCTION_NAME_EXIT;
230 return 0;
231 }
232
233
234 /**
235 @brief Returns if the message queue is empty or not
236
237 @param none
238 @return true If the queue is empty
239 @return false If the queue has at least one message
240 */
isEmpty()241 bool MessageQueue::isEmpty()
242 {
243 LOG_FUNCTION_NAME;
244
245 struct pollfd pfd;
246
247 pfd.fd = this->fd_read;
248 pfd.events = POLLIN;
249 pfd.revents = 0;
250
251 if(!this->fd_read)
252 {
253 MSGQ_LOGEA("read descriptor not initialized for message queue");
254 LOG_FUNCTION_NAME_EXIT;
255 return android::NO_INIT;
256 }
257
258
259 if( -1 == poll(&pfd,1,0) )
260 {
261 MSGQ_LOGEB("poll() error: %s", strerror(errno));
262 LOG_FUNCTION_NAME_EXIT;
263 return false;
264 }
265
266 if(pfd.revents & POLLIN)
267 {
268 mHasMsg = true;
269 }
270 else
271 {
272 mHasMsg = false;
273 }
274
275 LOG_FUNCTION_NAME_EXIT;
276 return !mHasMsg;
277 }
278
clear()279 void MessageQueue::clear()
280 {
281 if(!this->fd_read)
282 {
283 MSGQ_LOGEA("read descriptor not initialized for message queue");
284 LOG_FUNCTION_NAME_EXIT;
285 return;
286 }
287
288 Message msg;
289 while(!isEmpty())
290 {
291 get(&msg);
292 }
293
294 }
295
296
297 /**
298 @brief Force whether the message queue has message or not
299
300 @param hasMsg Whether the queue has a message or not
301 @return none
302 */
setMsg(bool hasMsg)303 void MessageQueue::setMsg(bool hasMsg)
304 {
305 mHasMsg = hasMsg;
306 }
307
308
309 /**
310 @briefWait for message in maximum three different queues with a timeout
311
312 @param queue1 First queue. At least this should be set to a valid queue pointer
313 @param queue2 Second queue. Optional.
314 @param queue3 Third queue. Optional.
315 @param timeout The timeout value (in micro secs) to wait for a message in any of the queues
316 @return android::NO_ERROR On success
317 @return android::BAD_VALUE If queue1 is NULL
318 @return android::NO_INIT If the file read descriptor of any of the provided queues is not set
319 */
waitForMsg(MessageQueue * queue1,MessageQueue * queue2,MessageQueue * queue3,int timeout)320 android::status_t MessageQueue::waitForMsg(MessageQueue *queue1, MessageQueue *queue2, MessageQueue *queue3, int timeout)
321 {
322 LOG_FUNCTION_NAME;
323
324 int n =1;
325 struct pollfd pfd[3];
326
327 if(!queue1)
328 {
329 MSGQ_LOGEA("queue1 pointer is NULL");
330 LOG_FUNCTION_NAME_EXIT;
331 return android::BAD_VALUE;
332 }
333
334 pfd[0].fd = queue1->getInFd();
335 if(!pfd[0].fd)
336 {
337 MSGQ_LOGEA("read descriptor not initialized for message queue1");
338 LOG_FUNCTION_NAME_EXIT;
339 return android::NO_INIT;
340 }
341 pfd[0].events = POLLIN;
342 pfd[0].revents = 0;
343 if(queue2)
344 {
345 MSGQ_LOGDA("queue2 not-null");
346 pfd[1].fd = queue2->getInFd();
347 if(!pfd[1].fd)
348 {
349 MSGQ_LOGEA("read descriptor not initialized for message queue2");
350 LOG_FUNCTION_NAME_EXIT;
351 return android::NO_INIT;
352 }
353
354 pfd[1].events = POLLIN;
355 pfd[1].revents = 0;
356 n++;
357 }
358
359 if(queue3)
360 {
361 MSGQ_LOGDA("queue3 not-null");
362 pfd[2].fd = queue3->getInFd();
363 if(!pfd[2].fd)
364 {
365 MSGQ_LOGEA("read descriptor not initialized for message queue3");
366 LOG_FUNCTION_NAME_EXIT;
367 return android::NO_INIT;
368 }
369
370 pfd[2].events = POLLIN;
371 pfd[2].revents = 0;
372 n++;
373 }
374
375
376 int ret = poll(pfd, n, timeout);
377 if(ret==0)
378 {
379 LOG_FUNCTION_NAME_EXIT;
380 return ret;
381 }
382
383 if(ret<android::NO_ERROR)
384 {
385 MSGQ_LOGEB("Message queue returned error %d", ret);
386 LOG_FUNCTION_NAME_EXIT;
387 return ret;
388 }
389
390 if (pfd[0].revents & POLLIN)
391 {
392 queue1->setMsg(true);
393 }
394
395 if(queue2)
396 {
397 if (pfd[1].revents & POLLIN)
398 {
399 queue2->setMsg(true);
400 }
401 }
402
403 if(queue3)
404 {
405 if (pfd[2].revents & POLLIN)
406 {
407 queue3->setMsg(true);
408 }
409 }
410
411 LOG_FUNCTION_NAME_EXIT;
412 return ret;
413 }
414
415 };
416