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