• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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