MessageQueue.cpp revision 18d4cb78c873c0ac1ab145f9b70d8f3d0e715185
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 <Errors.h> 24 25 26 27#define LOG_TAG "MessageQueue" 28#include <utils/Log.h> 29 30#include "MessageQueue.h" 31 32namespace TIUTILS { 33 34/** 35 @brief Constructor for the message queue class 36 37 @param none 38 @return none 39 */ 40MessageQueue::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 */ 73MessageQueue::~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 */ 99android::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 151int 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 163void 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 187android::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 */ 241bool 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/** 280 @brief Force whether the message queue has message or not 281 282 @param hasMsg Whether the queue has a message or not 283 @return none 284 */ 285void MessageQueue::setMsg(bool hasMsg) 286 { 287 mHasMsg = hasMsg; 288 } 289 290 291/** 292 @briefWait for message in maximum three different queues with a timeout 293 294 @param queue1 First queue. At least this should be set to a valid queue pointer 295 @param queue2 Second queue. Optional. 296 @param queue3 Third queue. Optional. 297 @param timeout The timeout value (in micro secs) to wait for a message in any of the queues 298 @return android::NO_ERROR On success 299 @return android::BAD_VALUE If queue1 is NULL 300 @return android::NO_INIT If the file read descriptor of any of the provided queues is not set 301 */ 302android::status_t MessageQueue::waitForMsg(MessageQueue *queue1, MessageQueue *queue2, MessageQueue *queue3, int timeout) 303 { 304 LOG_FUNCTION_NAME; 305 306 int n =1; 307 struct pollfd pfd[3]; 308 309 if(!queue1) 310 { 311 MSGQ_LOGEA("queue1 pointer is NULL"); 312 LOG_FUNCTION_NAME_EXIT; 313 return android::BAD_VALUE; 314 } 315 316 pfd[0].fd = queue1->getInFd(); 317 if(!pfd[0].fd) 318 { 319 MSGQ_LOGEA("read descriptor not initialized for message queue1"); 320 LOG_FUNCTION_NAME_EXIT; 321 return android::NO_INIT; 322 } 323 pfd[0].events = POLLIN; 324 pfd[0].revents = 0; 325 if(queue2) 326 { 327 MSGQ_LOGDA("queue2 not-null"); 328 pfd[1].fd = queue2->getInFd(); 329 if(!pfd[1].fd) 330 { 331 MSGQ_LOGEA("read descriptor not initialized for message queue2"); 332 LOG_FUNCTION_NAME_EXIT; 333 return android::NO_INIT; 334 } 335 336 pfd[1].events = POLLIN; 337 pfd[1].revents = 0; 338 n++; 339 } 340 341 if(queue3) 342 { 343 MSGQ_LOGDA("queue3 not-null"); 344 pfd[2].fd = queue3->getInFd(); 345 if(!pfd[2].fd) 346 { 347 MSGQ_LOGEA("read descriptor not initialized for message queue3"); 348 LOG_FUNCTION_NAME_EXIT; 349 return android::NO_INIT; 350 } 351 352 pfd[2].events = POLLIN; 353 pfd[2].revents = 0; 354 n++; 355 } 356 357 358 int ret = poll(pfd, n, timeout); 359 if(ret==0) 360 { 361 LOG_FUNCTION_NAME_EXIT; 362 return ret; 363 } 364 365 if(ret<android::NO_ERROR) 366 { 367 MSGQ_LOGEB("Message queue returned error %d", ret); 368 LOG_FUNCTION_NAME_EXIT; 369 return ret; 370 } 371 372 if (pfd[0].revents & POLLIN) 373 { 374 queue1->setMsg(true); 375 } 376 377 if(queue2) 378 { 379 if (pfd[1].revents & POLLIN) 380 { 381 queue2->setMsg(true); 382 } 383 } 384 385 if(queue3) 386 { 387 if (pfd[2].revents & POLLIN) 388 { 389 queue3->setMsg(true); 390 } 391 } 392 393 LOG_FUNCTION_NAME_EXIT; 394 return ret; 395 } 396 397}; 398