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