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 TIUTILS {
     33 
     34 /**
     35    @brief Constructor for the message queue class
     36 
     37    @param none
     38    @return none
     39  */
     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  */
     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  */
     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 
    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 
    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 
    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  */
    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 
    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  */
    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  */
    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