MessageQueue.cpp revision f7a4d11e9f710e2cd0592310ac1baecccb85f1d1
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
32namespace Ti {
33namespace Utils {
34
35/**
36   @brief Constructor for the message queue class
37
38   @param none
39   @return none
40 */
41MessageQueue::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 */
74MessageQueue::~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 */
100android::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
152int 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
164void 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
188android::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 */
242bool 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
280void 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 */
306void 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 */
323android::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