summaryrefslogtreecommitdiffstats
path: root/libtiutils/MessageQueue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libtiutils/MessageQueue.cpp')
-rw-r--r--libtiutils/MessageQueue.cpp415
1 files changed, 415 insertions, 0 deletions
diff --git a/libtiutils/MessageQueue.cpp b/libtiutils/MessageQueue.cpp
new file mode 100644
index 0000000..e3647d4
--- /dev/null
+++ b/libtiutils/MessageQueue.cpp
@@ -0,0 +1,415 @@
+/*
+ * 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;
+ }
+
+};