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 | |
31 | namespace MSGUTILS { |
32 | |
33 | /** |
34 | @brief Constructor for the message queue class |
35 | |
36 | @param none |
37 | @return none |
38 | */ |
39 | MessageQueue::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 | */ |
70 | MessageQueue::~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 | */ |
95 | android::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 | |
147 | int 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 | |
159 | void 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 | |
182 | android::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 | */ |
234 | bool 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 | |
272 | void 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 | */ |
296 | void 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 | */ |
313 | android::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 |