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