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 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 279void 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 */ 303void 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 */ 320android::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