Home | History | Annotate | Download | only in libtiutils
      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  */
     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  */
     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  */
    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 
    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 
    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 
    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  */
    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 
    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  */
    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  */
    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