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 Ti { 33 namespace Utils { 34 35 /** 36 @brief Constructor for the message queue class 37 38 @param none 39 @return none 40 */ 41 MessageQueue::MessageQueue() 42 { 43 LOG_FUNCTION_NAME; 44 45 int fds[2] = {-1,-1}; 46 android::status_t stat; 47 48 stat = pipe(fds); 49 50 if ( 0 > stat ) 51 { 52 MSGQ_LOGEB("Error while openning pipe: %s", strerror(stat) ); 53 this->fd_read = 0; 54 this->fd_write = 0; 55 mHasMsg = false; 56 } 57 else 58 { 59 this->fd_read = fds[0]; 60 this->fd_write = fds[1]; 61 62 mHasMsg = false; 63 } 64 65 LOG_FUNCTION_NAME_EXIT; 66 } 67 68 /** 69 @brief Destructor for the semaphore class 70 71 @param none 72 @return none 73 */ 74 MessageQueue::~MessageQueue() 75 { 76 LOG_FUNCTION_NAME; 77 78 if(this->fd_read >= 0) 79 { 80 close(this->fd_read); 81 } 82 83 if(this->fd_write >= 0) 84 { 85 close(this->fd_write); 86 } 87 88 LOG_FUNCTION_NAME_EXIT; 89 } 90 91 /** 92 @brief Get a message from the queue 93 94 @param msg Message structure to hold the message to be retrieved 95 @return android::NO_ERROR On success 96 @return android::BAD_VALUE if the message pointer is NULL 97 @return android::NO_INIT If the file read descriptor is not set 98 @return android::UNKNOWN_ERROR if the read operation fromthe file read descriptor fails 99 */ 100 android::status_t MessageQueue::get(Message* msg) 101 { 102 LOG_FUNCTION_NAME; 103 104 if(!msg) 105 { 106 MSGQ_LOGEA("msg is NULL"); 107 LOG_FUNCTION_NAME_EXIT; 108 return android::BAD_VALUE; 109 } 110 111 if(!this->fd_read) 112 { 113 MSGQ_LOGEA("read descriptor not initialized for message queue"); 114 LOG_FUNCTION_NAME_EXIT; 115 return android::NO_INIT; 116 } 117 118 char* p = (char*) msg; 119 size_t read_bytes = 0; 120 121 while( read_bytes < sizeof(*msg) ) 122 { 123 int err = read(this->fd_read, p, sizeof(*msg) - read_bytes); 124 125 if( err < 0 ) 126 { 127 MSGQ_LOGEB("read() error: %s", strerror(errno)); 128 return android::UNKNOWN_ERROR; 129 } 130 else 131 { 132 read_bytes += err; 133 } 134 } 135 136 MSGQ_LOGDB("MQ.get(%d,%p,%p,%p,%p)", msg->command, msg->arg1,msg->arg2,msg->arg3,msg->arg4); 137 138 mHasMsg = false; 139 140 LOG_FUNCTION_NAME_EXIT; 141 142 return 0; 143 } 144 145 /** 146 @brief Get the input file descriptor of the message queue 147 148 @param none 149 @return file read descriptor 150 */ 151 152 int MessageQueue::getInFd() 153 { 154 return this->fd_read; 155 } 156 157 /** 158 @brief Constructor for the message queue class 159 160 @param fd file read descriptor 161 @return none 162 */ 163 164 void MessageQueue::setInFd(int fd) 165 { 166 LOG_FUNCTION_NAME; 167 168 if ( -1 != this->fd_read ) 169 { 170 close(this->fd_read); 171 } 172 173 this->fd_read = fd; 174 175 LOG_FUNCTION_NAME_EXIT; 176 } 177 178 /** 179 @brief Queue a message 180 181 @param msg Message structure to hold the message to be retrieved 182 @return android::NO_ERROR On success 183 @return android::BAD_VALUE if the message pointer is NULL 184 @return android::NO_INIT If the file write descriptor is not set 185 @return android::UNKNOWN_ERROR if the write operation fromthe file write descriptor fails 186 */ 187 188 android::status_t MessageQueue::put(Message* msg) 189 { 190 LOG_FUNCTION_NAME; 191 192 char* p = (char*) msg; 193 size_t bytes = 0; 194 195 if(!msg) 196 { 197 MSGQ_LOGEA("msg is NULL"); 198 LOG_FUNCTION_NAME_EXIT; 199 return android::BAD_VALUE; 200 } 201 202 if(!this->fd_write) 203 { 204 MSGQ_LOGEA("write descriptor not initialized for message queue"); 205 LOG_FUNCTION_NAME_EXIT; 206 return android::NO_INIT; 207 } 208 209 210 MSGQ_LOGDB("MQ.put(%d,%p,%p,%p,%p)", msg->command, msg->arg1,msg->arg2,msg->arg3,msg->arg4); 211 212 while( bytes < sizeof(msg) ) 213 { 214 int err = write(this->fd_write, p, sizeof(*msg) - bytes); 215 216 if( err < 0 ) 217 { 218 MSGQ_LOGEB("write() error: %s", strerror(errno)); 219 LOG_FUNCTION_NAME_EXIT; 220 return android::UNKNOWN_ERROR; 221 } 222 else 223 { 224 bytes += err; 225 } 226 } 227 228 MSGQ_LOGDA("MessageQueue::put EXIT"); 229 230 LOG_FUNCTION_NAME_EXIT; 231 return 0; 232 } 233 234 235 /** 236 @brief Returns if the message queue is empty or not 237 238 @param none 239 @return true If the queue is empty 240 @return false If the queue has at least one message 241 */ 242 bool MessageQueue::isEmpty() 243 { 244 LOG_FUNCTION_NAME; 245 246 struct pollfd pfd; 247 248 pfd.fd = this->fd_read; 249 pfd.events = POLLIN; 250 pfd.revents = 0; 251 252 if(!this->fd_read) 253 { 254 MSGQ_LOGEA("read descriptor not initialized for message queue"); 255 LOG_FUNCTION_NAME_EXIT; 256 return android::NO_INIT; 257 } 258 259 260 if( -1 == poll(&pfd,1,0) ) 261 { 262 MSGQ_LOGEB("poll() error: %s", strerror(errno)); 263 LOG_FUNCTION_NAME_EXIT; 264 return false; 265 } 266 267 if(pfd.revents & POLLIN) 268 { 269 mHasMsg = true; 270 } 271 else 272 { 273 mHasMsg = false; 274 } 275 276 LOG_FUNCTION_NAME_EXIT; 277 return !mHasMsg; 278 } 279 280 void MessageQueue::clear() 281 { 282 LOG_FUNCTION_NAME; 283 284 if(!this->fd_read) 285 { 286 MSGQ_LOGEA("read descriptor not initialized for message queue"); 287 LOG_FUNCTION_NAME_EXIT; 288 return; 289 } 290 291 Message msg; 292 while(!isEmpty()) 293 { 294 get(&msg); 295 } 296 297 } 298 299 300 /** 301 @brief Force whether the message queue has message or not 302 303 @param hasMsg Whether the queue has a message or not 304 @return none 305 */ 306 void MessageQueue::setMsg(bool hasMsg) 307 { 308 mHasMsg = hasMsg; 309 } 310 311 312 /** 313 @briefWait for message in maximum three different queues with a timeout 314 315 @param queue1 First queue. At least this should be set to a valid queue pointer 316 @param queue2 Second queue. Optional. 317 @param queue3 Third queue. Optional. 318 @param timeout The timeout value (in micro secs) to wait for a message in any of the queues 319 @return android::NO_ERROR On success 320 @return android::BAD_VALUE If queue1 is NULL 321 @return android::NO_INIT If the file read descriptor of any of the provided queues is not set 322 */ 323 android::status_t MessageQueue::waitForMsg(MessageQueue *queue1, MessageQueue *queue2, MessageQueue *queue3, int timeout) 324 { 325 LOG_FUNCTION_NAME; 326 327 int n =1; 328 struct pollfd pfd[3]; 329 330 if(!queue1) 331 { 332 MSGQ_LOGEA("queue1 pointer is NULL"); 333 LOG_FUNCTION_NAME_EXIT; 334 return android::BAD_VALUE; 335 } 336 337 pfd[0].fd = queue1->getInFd(); 338 if(!pfd[0].fd) 339 { 340 MSGQ_LOGEA("read descriptor not initialized for message queue1"); 341 LOG_FUNCTION_NAME_EXIT; 342 return android::NO_INIT; 343 } 344 pfd[0].events = POLLIN; 345 pfd[0].revents = 0; 346 if(queue2) 347 { 348 MSGQ_LOGDA("queue2 not-null"); 349 pfd[1].fd = queue2->getInFd(); 350 if(!pfd[1].fd) 351 { 352 MSGQ_LOGEA("read descriptor not initialized for message queue2"); 353 LOG_FUNCTION_NAME_EXIT; 354 return android::NO_INIT; 355 } 356 357 pfd[1].events = POLLIN; 358 pfd[1].revents = 0; 359 n++; 360 } 361 362 if(queue3) 363 { 364 MSGQ_LOGDA("queue3 not-null"); 365 pfd[2].fd = queue3->getInFd(); 366 if(!pfd[2].fd) 367 { 368 MSGQ_LOGEA("read descriptor not initialized for message queue3"); 369 LOG_FUNCTION_NAME_EXIT; 370 return android::NO_INIT; 371 } 372 373 pfd[2].events = POLLIN; 374 pfd[2].revents = 0; 375 n++; 376 } 377 378 379 int ret = poll(pfd, n, timeout); 380 if(ret==0) 381 { 382 LOG_FUNCTION_NAME_EXIT; 383 return ret; 384 } 385 386 if(ret<android::NO_ERROR) 387 { 388 MSGQ_LOGEB("Message queue returned error %d", ret); 389 LOG_FUNCTION_NAME_EXIT; 390 return ret; 391 } 392 393 if (pfd[0].revents & POLLIN) 394 { 395 queue1->setMsg(true); 396 } 397 398 if(queue2) 399 { 400 if (pfd[1].revents & POLLIN) 401 { 402 queue2->setMsg(true); 403 } 404 } 405 406 if(queue3) 407 { 408 if (pfd[2].revents & POLLIN) 409 { 410 queue3->setMsg(true); 411 } 412 } 413 414 LOG_FUNCTION_NAME_EXIT; 415 return ret; 416 } 417 418 } // namespace Utils 419 } // namespace Ti 420