/* * Copyright (C) Texas Instruments - http://www.ti.com/ * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/poll.h> #include <unistd.h> #include <utils/Errors.h> #define LOG_TAG "MessageQueue" #include <utils/Log.h> #include "MessageQueue.h" namespace TIUTILS { /** @brief Constructor for the message queue class @param none @return none */ MessageQueue::MessageQueue() { LOG_FUNCTION_NAME; int fds[2] = {-1,-1}; android::status_t stat; stat = pipe(fds); if ( 0 > stat ) { MSGQ_LOGEB("Error while openning pipe: %s", strerror(stat) ); this->fd_read = 0; this->fd_write = 0; mHasMsg = false; } else { this->fd_read = fds[0]; this->fd_write = fds[1]; mHasMsg = false; } LOG_FUNCTION_NAME_EXIT; } /** @brief Destructor for the semaphore class @param none @return none */ MessageQueue::~MessageQueue() { LOG_FUNCTION_NAME; if(this->fd_read >= 0) { close(this->fd_read); } if(this->fd_write >= 0) { close(this->fd_write); } LOG_FUNCTION_NAME_EXIT; } /** @brief Get a message from the queue @param msg Message structure to hold the message to be retrieved @return android::NO_ERROR On success @return android::BAD_VALUE if the message pointer is NULL @return android::NO_INIT If the file read descriptor is not set @return android::UNKNOWN_ERROR if the read operation fromthe file read descriptor fails */ android::status_t MessageQueue::get(Message* msg) { LOG_FUNCTION_NAME; if(!msg) { MSGQ_LOGEA("msg is NULL"); LOG_FUNCTION_NAME_EXIT; return android::BAD_VALUE; } if(!this->fd_read) { MSGQ_LOGEA("read descriptor not initialized for message queue"); LOG_FUNCTION_NAME_EXIT; return android::NO_INIT; } char* p = (char*) msg; size_t read_bytes = 0; while( read_bytes < sizeof(*msg) ) { int err = read(this->fd_read, p, sizeof(*msg) - read_bytes); if( err < 0 ) { MSGQ_LOGEB("read() error: %s", strerror(errno)); return android::UNKNOWN_ERROR; } else { read_bytes += err; } } MSGQ_LOGDB("MQ.get(%d,%p,%p,%p,%p)", msg->command, msg->arg1,msg->arg2,msg->arg3,msg->arg4); mHasMsg = false; LOG_FUNCTION_NAME_EXIT; return 0; } /** @brief Get the input file descriptor of the message queue @param none @return file read descriptor */ int MessageQueue::getInFd() { return this->fd_read; } /** @brief Constructor for the message queue class @param fd file read descriptor @return none */ void MessageQueue::setInFd(int fd) { LOG_FUNCTION_NAME; if ( -1 != this->fd_read ) { close(this->fd_read); } this->fd_read = fd; LOG_FUNCTION_NAME_EXIT; } /** @brief Queue a message @param msg Message structure to hold the message to be retrieved @return android::NO_ERROR On success @return android::BAD_VALUE if the message pointer is NULL @return android::NO_INIT If the file write descriptor is not set @return android::UNKNOWN_ERROR if the write operation fromthe file write descriptor fails */ android::status_t MessageQueue::put(Message* msg) { LOG_FUNCTION_NAME; char* p = (char*) msg; size_t bytes = 0; if(!msg) { MSGQ_LOGEA("msg is NULL"); LOG_FUNCTION_NAME_EXIT; return android::BAD_VALUE; } if(!this->fd_write) { MSGQ_LOGEA("write descriptor not initialized for message queue"); LOG_FUNCTION_NAME_EXIT; return android::NO_INIT; } MSGQ_LOGDB("MQ.put(%d,%p,%p,%p,%p)", msg->command, msg->arg1,msg->arg2,msg->arg3,msg->arg4); while( bytes < sizeof(msg) ) { int err = write(this->fd_write, p, sizeof(*msg) - bytes); if( err < 0 ) { MSGQ_LOGEB("write() error: %s", strerror(errno)); LOG_FUNCTION_NAME_EXIT; return android::UNKNOWN_ERROR; } else { bytes += err; } } MSGQ_LOGDA("MessageQueue::put EXIT"); LOG_FUNCTION_NAME_EXIT; return 0; } /** @brief Returns if the message queue is empty or not @param none @return true If the queue is empty @return false If the queue has at least one message */ bool MessageQueue::isEmpty() { LOG_FUNCTION_NAME; struct pollfd pfd; pfd.fd = this->fd_read; pfd.events = POLLIN; pfd.revents = 0; if(!this->fd_read) { MSGQ_LOGEA("read descriptor not initialized for message queue"); LOG_FUNCTION_NAME_EXIT; return android::NO_INIT; } if( -1 == poll(&pfd,1,0) ) { MSGQ_LOGEB("poll() error: %s", strerror(errno)); LOG_FUNCTION_NAME_EXIT; return false; } if(pfd.revents & POLLIN) { mHasMsg = true; } else { mHasMsg = false; } LOG_FUNCTION_NAME_EXIT; return !mHasMsg; } void MessageQueue::clear() { if(!this->fd_read) { MSGQ_LOGEA("read descriptor not initialized for message queue"); LOG_FUNCTION_NAME_EXIT; return; } Message msg; while(!isEmpty()) { get(&msg); } } /** @brief Force whether the message queue has message or not @param hasMsg Whether the queue has a message or not @return none */ void MessageQueue::setMsg(bool hasMsg) { mHasMsg = hasMsg; } /** @briefWait for message in maximum three different queues with a timeout @param queue1 First queue. At least this should be set to a valid queue pointer @param queue2 Second queue. Optional. @param queue3 Third queue. Optional. @param timeout The timeout value (in micro secs) to wait for a message in any of the queues @return android::NO_ERROR On success @return android::BAD_VALUE If queue1 is NULL @return android::NO_INIT If the file read descriptor of any of the provided queues is not set */ android::status_t MessageQueue::waitForMsg(MessageQueue *queue1, MessageQueue *queue2, MessageQueue *queue3, int timeout) { LOG_FUNCTION_NAME; int n =1; struct pollfd pfd[3]; if(!queue1) { MSGQ_LOGEA("queue1 pointer is NULL"); LOG_FUNCTION_NAME_EXIT; return android::BAD_VALUE; } pfd[0].fd = queue1->getInFd(); if(!pfd[0].fd) { MSGQ_LOGEA("read descriptor not initialized for message queue1"); LOG_FUNCTION_NAME_EXIT; return android::NO_INIT; } pfd[0].events = POLLIN; pfd[0].revents = 0; if(queue2) { MSGQ_LOGDA("queue2 not-null"); pfd[1].fd = queue2->getInFd(); if(!pfd[1].fd) { MSGQ_LOGEA("read descriptor not initialized for message queue2"); LOG_FUNCTION_NAME_EXIT; return android::NO_INIT; } pfd[1].events = POLLIN; pfd[1].revents = 0; n++; } if(queue3) { MSGQ_LOGDA("queue3 not-null"); pfd[2].fd = queue3->getInFd(); if(!pfd[2].fd) { MSGQ_LOGEA("read descriptor not initialized for message queue3"); LOG_FUNCTION_NAME_EXIT; return android::NO_INIT; } pfd[2].events = POLLIN; pfd[2].revents = 0; n++; } int ret = poll(pfd, n, timeout); if(ret==0) { LOG_FUNCTION_NAME_EXIT; return ret; } if(ret<android::NO_ERROR) { MSGQ_LOGEB("Message queue returned error %d", ret); LOG_FUNCTION_NAME_EXIT; return ret; } if (pfd[0].revents & POLLIN) { queue1->setMsg(true); } if(queue2) { if (pfd[1].revents & POLLIN) { queue2->setMsg(true); } } if(queue3) { if (pfd[2].revents & POLLIN) { queue3->setMsg(true); } } LOG_FUNCTION_NAME_EXIT; return ret; } };