1 /****************************************************************************** 2 * 3 * Copyright (C) 2018 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ***************************************************************************** 18 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore 19 */ 20 21 /*****************************************************************************/ 22 /* */ 23 /* File Name : osal_thread.c */ 24 /* */ 25 /* Description : This file contains Thread API's implemented for */ 26 /* different platforms. */ 27 /* */ 28 /* List of Functions : osal_thread_create */ 29 /* osal_thread_destroy */ 30 /* osal_func */ 31 /* osal_set_thread_priority */ 32 /* osal_set_thread_core_affinity */ 33 /* osal_thread_sleep */ 34 /* osal_thread_yield */ 35 /* osal_thread_suspend */ 36 /* osal_thread_resume */ 37 /* osal_thread_wait */ 38 /* osal_get_thread_handle */ 39 /* osal_get_time */ 40 /* osal_get_time_usec */ 41 /* osal_get_last_error */ 42 /* osal_print_last_error */ 43 /* */ 44 /* Issues / Problems : None */ 45 /* */ 46 /* Revision History : */ 47 /* */ 48 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 49 /* 06 03 2006 Ittiam Draft */ 50 /* */ 51 /*****************************************************************************/ 52 53 /*****************************************************************************/ 54 /* File Includes */ 55 /*****************************************************************************/ 56 57 /* System include files */ 58 #include <stdio.h> 59 60 #include <semaphore.h> 61 #include <pthread.h> 62 #include <errno.h> 63 #include <sys/time.h> 64 #include <sys/resource.h> 65 66 #include <unistd.h> 67 #include <math.h> 68 #include <sched.h> /*for CPU_SET, etc.. */ 69 #include <linux/unistd.h> 70 #include <sys/syscall.h> 71 72 /* User include files */ 73 #include "cast_types.h" 74 #include "osal.h" 75 #include "osal_handle.h" 76 #include "osal_thread.h" 77 #include "osal_errno.h" 78 79 /*****************************************************************************/ 80 /* Static Function Declarations */ 81 /*****************************************************************************/ 82 83 static void osal_func(void *param); 84 85 /*****************************************************************************/ 86 /* */ 87 /* Function Name : osal_thread_create */ 88 /* */ 89 /* Description : This function create a new thread. */ 90 /* */ 91 /* Inputs : OSAL handle */ 92 /* Memory Manager Handle */ 93 /* Thread creation attributes */ 94 /* */ 95 /* Globals : None */ 96 /* */ 97 /* Processing : This function calls OS specific thread create API's and */ 98 /* creates a new thread with specified attributes. */ 99 /* */ 100 /* Outputs : Status of thread creation */ 101 /* */ 102 /* Returns : On SUCCESS - 0 */ 103 /* On FAILURE - -1 */ 104 /* */ 105 /* Issues : Only supports creating threads with default attributes */ 106 /* */ 107 /* Revision History: */ 108 /* */ 109 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 110 /* 06 03 2006 Ittiam Draft */ 111 /* */ 112 /*****************************************************************************/ 113 114 void *osal_thread_create(IN void *osal_handle, IN osal_thread_attr_t *attr) 115 { 116 osal_t *handle = (osal_t *)osal_handle; 117 WORD32 priority = 0; 118 void *mmr_handle = 0; 119 120 /* If Handle or attributes are not valid, return ERRORED. */ 121 if(0 == attr) 122 return 0; 123 124 if(0 == handle || 0 == handle->alloc || 0 == handle->free) 125 return 0; 126 127 /* Initialize MMR handle */ 128 mmr_handle = handle->mmr_handle; 129 130 { 131 pthread_attr_t tattr; 132 thread_handle_t *hdl = 0; 133 134 attr->sched_policy = OSAL_SCHED_RR; 135 136 /* Allocate memory for thread handle */ 137 hdl = handle->alloc(mmr_handle, sizeof(thread_handle_t)); 138 if(0 == hdl) 139 return 0; 140 141 /* Initialize thread handle parameters */ 142 hdl->mmr_handle = mmr_handle; 143 hdl->hdl = handle; 144 hdl->exit_code = attr->exit_code; 145 hdl->priority = priority; 146 hdl->thread_func = attr->thread_func; 147 hdl->thread_param = attr->thread_param; 148 149 /* initialized with default attributes */ 150 if(0 != pthread_attr_init(&tattr)) 151 { 152 handle->free(hdl->mmr_handle, hdl); 153 return 0; 154 } 155 156 /* Create the thread */ 157 hdl->thread_id = pthread_create( 158 &(hdl->thread_handle), /* Thread Handle */ 159 &tattr, /* Attributes */ 160 (void *(*)(void *))osal_func, 161 hdl); /* Parameters */ 162 163 /* In case of error in thread creationn, Free the handle memory and */ 164 /* return error. */ 165 if(0 != hdl->thread_id) 166 { 167 handle->free(hdl->mmr_handle, hdl); 168 return 0; 169 } 170 171 pthread_attr_destroy(&tattr); 172 173 return hdl; 174 } 175 } 176 177 /*****************************************************************************/ 178 /* */ 179 /* Function Name : osal_thread_destroy */ 180 /* */ 181 /* Description : This function calls OS specific API's to close a thread */ 182 /* which is represented by specified handle. */ 183 /* */ 184 /* Inputs : Initialized thread handle */ 185 /* */ 186 /* Globals : None */ 187 /* */ 188 /* Processing : Closing other threads is supported only in windows. So, */ 189 /* only windows platform supports this API. */ 190 /* */ 191 /* Outputs : Status of thread close */ 192 /* */ 193 /* Returns : On SUCCESS - 0 */ 194 /* On FAILURE - -1 */ 195 /* */ 196 /* Issues : None */ 197 /* */ 198 /* Revision History: */ 199 /* */ 200 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 201 /* 06 03 2006 Ittiam Draft */ 202 /* */ 203 /*****************************************************************************/ 204 205 WORD32 osal_thread_destroy(IN void *thread_handle) 206 { 207 /* If thread handle is not valid, return error */ 208 if(0 == thread_handle) 209 return OSAL_ERROR; 210 211 { 212 thread_handle_t *hdl = (thread_handle_t *)thread_handle; 213 214 /* Free memory allocated for Thread handle */ 215 ((osal_t *)hdl->hdl)->free(hdl->mmr_handle, hdl); 216 217 return OSAL_SUCCESS; 218 } 219 } 220 221 /*****************************************************************************/ 222 /* */ 223 /* Function Name : osal_func */ 224 /* */ 225 /* Description : This function calls the registered threads calling */ 226 /* function */ 227 /* */ 228 /* Inputs : Thread Handle */ 229 /* */ 230 /* Globals : None */ 231 /* */ 232 /* Processing : Calls each registered thread function */ 233 /* */ 234 /* Outputs : None */ 235 /* Returns : None */ 236 /* */ 237 /* Issues : None */ 238 /* */ 239 /* Revision History: */ 240 /* */ 241 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 242 /* 10 05 2006 Ittiam Draft */ 243 /* */ 244 /*****************************************************************************/ 245 246 void osal_func(IN void *param) 247 { 248 thread_handle_t *hdl = (thread_handle_t *)param; 249 250 while(1) 251 { 252 /* Untill thread returns exit code, invoke the thread function */ 253 if(hdl->exit_code == hdl->thread_func(hdl->thread_param)) 254 break; 255 } 256 257 /* On Linux platforms call pthread_exit() to release all the resources */ 258 /* allocated. */ 259 pthread_exit(NULL); 260 } 261 262 /*****************************************************************************/ 263 /* */ 264 /* Function Name : osal_thread_sleep */ 265 /* */ 266 /* Description : This function calls OS specific API and makes thread */ 267 /* sleep for specified number of milli seconds. */ 268 /* */ 269 /* Inputs : Initialized thread handle */ 270 /* Time to sleep in millisceonds */ 271 /* */ 272 /* Globals : None */ 273 /* */ 274 /* Processing : Calls API to sleep for specified number of milli seconds */ 275 /* */ 276 /* Outputs : Status of sleep */ 277 /* */ 278 /* Returns : On SUCCESS - 0 */ 279 /* On FAILURE - -1 */ 280 /* */ 281 /* Issues : None */ 282 /* */ 283 /* Revision History: */ 284 /* */ 285 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 286 /* 06 03 2006 Ittiam Draft */ 287 /* */ 288 /*****************************************************************************/ 289 290 WORD32 osal_thread_sleep(IN UWORD32 milli_seconds) 291 { 292 { 293 struct timespec timer; 294 295 /* Convert time in milliseconds into seconds and nano seconds */ 296 timer.tv_sec = milli_seconds / 1000; 297 milli_seconds -= (timer.tv_sec * 1000); 298 timer.tv_nsec = milli_seconds * MEGA_CONST; 299 300 /* Using Monotonic clock to sleep, also flag is set to 0 for relative */ 301 /* time to current clock time */ 302 if(0 == clock_nanosleep(CLOCK_MONOTONIC, 0, &timer, NULL)) 303 { 304 return OSAL_SUCCESS; 305 } 306 307 return OSAL_ERROR; 308 } 309 } 310 311 /*****************************************************************************/ 312 /* */ 313 /* Function Name : osal_thread_yield */ 314 /* */ 315 /* Description : This function causes the yield its execution. */ 316 /* */ 317 /* Inputs : Thread Handle */ 318 /* */ 319 /* Globals : None */ 320 /* */ 321 /* Processing : Calls OS specific yield calls. */ 322 /* */ 323 /* Outputs : Status of Thread Yield */ 324 /* */ 325 /* Returns : On SUCCESS - 0 */ 326 /* On FAILURE - -1 */ 327 /* */ 328 /* Issues : Yield in WIN32 (whihc is a 16 - bit API) is still present*/ 329 /* only to maintian backward compatibility. Can get */ 330 /* deprecated in future. */ 331 /* */ 332 /* Revision History: */ 333 /* */ 334 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 335 /* 06 03 2006 Ittiam Draft */ 336 /* */ 337 /*****************************************************************************/ 338 339 WORD32 osal_thread_yield() 340 { 341 if(0 == sched_yield()) 342 return OSAL_SUCCESS; 343 344 return OSAL_ERROR; 345 } 346 347 /*****************************************************************************/ 348 /* */ 349 /* Function Name : osal_thread_suspend */ 350 /* */ 351 /* Description : This function causes the suspension its execution. */ 352 /* */ 353 /* Inputs : Thread Handle */ 354 /* */ 355 /* Globals : None */ 356 /* */ 357 /* Processing : Calls OS specific suspend calls. */ 358 /* */ 359 /* Outputs : Status of Thread Suspend */ 360 /* */ 361 /* Returns : On SUCCESS - 0 */ 362 /* On FAILURE - -1 */ 363 /* */ 364 /* Issues : API not supported in Redhat Linux. Refer Redhat */ 365 /* documentation in: */ 366 /* http://www.redhat.com/docs/wp/solaris_port/c1347.html */ 367 /* */ 368 /* Revision History: */ 369 /* */ 370 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 371 /* 30 03 2006 Ittiam Draft */ 372 /* */ 373 /*****************************************************************************/ 374 375 WORD32 osal_thread_suspend(IN void *thread_handle) 376 { 377 /* If thread handle is not valid, return error */ 378 if(0 == thread_handle) 379 return OSAL_ERROR; 380 381 { 382 /* Thread suspend are not supported in Redhat Linux. Refer link */ 383 /* http://www.redhat.com/docs/wp/solaris_port/c1347.html */ 384 385 return OSAL_NOT_SUPPORTED; 386 } 387 } 388 389 /*****************************************************************************/ 390 /* */ 391 /* Function Name : osal_thread_resume */ 392 /* */ 393 /* Description : This function causes the resumption its execution. */ 394 /* */ 395 /* Inputs : Thread Handle */ 396 /* */ 397 /* Globals : None */ 398 /* */ 399 /* Processing : Calls OS specific resume calls. */ 400 /* */ 401 /* Outputs : Status of Thread Suspend */ 402 /* */ 403 /* Returns : On SUCCESS - 0 */ 404 /* On FAILURE - -1 */ 405 /* */ 406 /* Issues : API not supported in Redhat Linux. Refer Redhat */ 407 /* documentation in: */ 408 /* http://www.redhat.com/docs/wp/solaris_port/c1347.html */ 409 /* */ 410 /* Revision History: */ 411 /* */ 412 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 413 /* 30 03 2006 Ittiam Draft */ 414 /* */ 415 /*****************************************************************************/ 416 417 WORD32 osal_thread_resume(IN void *thread_handle) 418 { 419 /* If thread handle is not valid, return error */ 420 if(0 == thread_handle) 421 return OSAL_ERROR; 422 423 { 424 /* Thread suspend are not supported in Redhat Linux. Refer link */ 425 /* http://www.redhat.com/docs/wp/solaris_port/c1347.html */ 426 427 return OSAL_NOT_SUPPORTED; 428 } 429 } 430 431 /*****************************************************************************/ 432 /* */ 433 /* Function Name : osal_thread_wait */ 434 /* */ 435 /* Description : This function causes the wait untill called thread */ 436 /* finishes execution */ 437 /* */ 438 /* Inputs : Thread Handle */ 439 /* */ 440 /* Globals : None */ 441 /* */ 442 /* Processing : Calls OS specific wait call for wait on another thread */ 443 /* */ 444 /* Outputs : Status of Thread wait */ 445 /* */ 446 /* Returns : On SUCCESS - 0 */ 447 /* On FAILURE - -1 */ 448 /* */ 449 /* Issues : None */ 450 /* */ 451 /* Revision History: */ 452 /* */ 453 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 454 /* 30 03 2006 Ittiam Draft */ 455 /* */ 456 /*****************************************************************************/ 457 458 WORD32 osal_thread_wait(IN void *thread_handle) 459 { 460 if(0 == thread_handle) 461 return OSAL_ERROR; 462 463 { 464 WORD32 result = 0; 465 void *status = 0; 466 467 thread_handle_t *hdl = (thread_handle_t *)thread_handle; 468 469 /* Join the thread to wait for thread to complete execution */ 470 result = pthread_join(hdl->thread_handle, (void **)&status); 471 472 return result; 473 } 474 } 475 476 /*****************************************************************************/ 477 /* */ 478 /* Function Name : osal_get_thread_handle */ 479 /* */ 480 /* Description : This function gets current thread handle. Currently not */ 481 /* supported */ 482 /* */ 483 /* Inputs : OSAL handle. */ 484 /* */ 485 /* Globals : None */ 486 /* */ 487 /* Processing : Gets all the thread properities and constructs a new */ 488 /* thread handle . */ 489 /* */ 490 /* Outputs : Thread handle to current thread. */ 491 /* */ 492 /* Returns : On SUCCESS - Current thread handle */ 493 /* On FAILURE - NULL */ 494 /* */ 495 /* Issues : Not supported on Linux and BIOS platforms. */ 496 /* */ 497 /* Revision History: */ 498 /* */ 499 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 500 /* 10 05 2006 Ittiam Draft */ 501 /* */ 502 /*****************************************************************************/ 503 504 void *osal_get_thread_handle(IN void *osal_handle) 505 { 506 osal_t *handle = (osal_t *)osal_handle; 507 508 if(0 == osal_handle) 509 return 0; 510 511 { 512 thread_handle_t *hdl = handle->alloc(handle->mmr_handle, sizeof(thread_handle_t)); 513 WORD32 schedpolicy; 514 struct sched_param schedparam; 515 516 if(0 == hdl) 517 return 0; 518 519 hdl->mmr_handle = handle->mmr_handle; 520 hdl->hdl = handle; 521 hdl->exit_code = 0; 522 hdl->thread_func = 0; 523 hdl->thread_param = 0; 524 hdl->thread_handle = pthread_self(); 525 hdl->thread_id = 0; 526 hdl->priority = schedparam.sched_priority; 527 528 /* Get thread priority from scheduling parameters */ 529 if(0 != pthread_getschedparam(hdl->thread_handle, &schedpolicy, &schedparam)) 530 { 531 return 0; 532 } 533 534 return hdl; 535 } 536 } 537 538 /*****************************************************************************/ 539 /* */ 540 /* Function Name : osal_get_time */ 541 /* */ 542 /* Description : This function returns absolute time in milli seconds */ 543 /* */ 544 /* Inputs : None */ 545 /* Globals : None */ 546 /* */ 547 /* Processing : Gets the absolute time by calling OS specific API's. */ 548 /* */ 549 /* Outputs : Absolute time in milli seconds. */ 550 /* */ 551 /* Returns : +ve 32 bit value */ 552 /* */ 553 /* Issues : None */ 554 /* */ 555 /* Revision History: */ 556 /* */ 557 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 558 /* 06 03 2006 Ittiam Draft */ 559 /* */ 560 /*****************************************************************************/ 561 562 UWORD32 osal_get_time() 563 { 564 { 565 struct timespec time_val; 566 int cur_time; 567 568 /* Get the Monotonic time */ 569 clock_gettime(CLOCK_MONOTONIC, &time_val); 570 571 /* Convert time in seconds and micro seconds into milliseconds time */ 572 cur_time = time_val.tv_sec * 1000 + time_val.tv_nsec / 1000000; 573 return cur_time; 574 } 575 } 576 577 /*****************************************************************************/ 578 /* */ 579 /* Function Name : osal_get_time_usec */ 580 /* */ 581 /* Description : This function returns absolute time in micro seconds */ 582 /* */ 583 /* Inputs : None */ 584 /* Globals : None */ 585 /* */ 586 /* Processing : Gets the absolute time by calling OS specific API's. */ 587 /* */ 588 /* Outputs : Absolute time in micro seconds. */ 589 /* */ 590 /* Returns : +ve 32 bit value */ 591 /* */ 592 /* Issues : None */ 593 /* */ 594 /* Revision History: */ 595 /* */ 596 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 597 /* 06 03 2009 Ittiam Draft */ 598 /* */ 599 /*****************************************************************************/ 600 601 WORD32 osal_get_time_usec(UWORD32 *sec, UWORD32 *usec) 602 { 603 if((0 == sec) || (0 == usec)) 604 return OSAL_ERROR; 605 606 { 607 struct timespec time_val; 608 609 /* Get the Monotonic time */ 610 clock_gettime(CLOCK_MONOTONIC, &time_val); 611 612 /* Convert time in seconds and micro seconds into milliseconds time */ 613 *sec = time_val.tv_sec; 614 *usec = time_val.tv_nsec / 1000; 615 616 return OSAL_SUCCESS; 617 } 618 } 619 620 /*****************************************************************************/ 621 /* */ 622 /* Function Name : osal_get_last_error */ 623 /* */ 624 /* Description : This function gets the last error code. */ 625 /* */ 626 /* Inputs : None */ 627 /* Globals : None */ 628 /* */ 629 /* Processing : Gets the last occured error code by calling OS specific */ 630 /* API call. */ 631 /* */ 632 /* Outputs : Error Number */ 633 /* */ 634 /* Returns : If no error - 0 */ 635 /* Else - +ve number */ 636 /* */ 637 /* Issues : None */ 638 /* */ 639 /* Revision History: */ 640 /* */ 641 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 642 /* 06 03 2006 Ittiam Draft */ 643 /* */ 644 /*****************************************************************************/ 645 646 UWORD32 osal_get_last_error() 647 { 648 UWORD32 get_linux_error(void); 649 return get_linux_error(); 650 } 651 652 /*****************************************************************************/ 653 /* */ 654 /* Function Name : osal_print_last_error */ 655 /* */ 656 /* Description : This function prints the last error message. */ 657 /* */ 658 /* Inputs : None */ 659 /* Globals : None */ 660 /* */ 661 /* Processing : Gets the last occured error code by calling OS specific */ 662 /* API call. It prints argument string (if not NULL), */ 663 /* followed by ': ' then the error_string and <new_line>. */ 664 /* */ 665 /* Outputs : None */ 666 /* */ 667 /* Returns : None */ 668 /* */ 669 /* Issues : None */ 670 /* */ 671 /* Revision History: */ 672 /* */ 673 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 674 /* 10 03 2006 Ittiam Draft */ 675 /* */ 676 /*****************************************************************************/ 677 678 void osal_print_last_error(IN const STRWORD8 *string) 679 { 680 perror(string); 681 } 682 683 /*****************************************************************************/ 684 /* */ 685 /* Function Name : osal_get_current_tid */ 686 /* */ 687 /* Description : Gets the tid of the thread in whose context this call */ 688 /* was made */ 689 /* */ 690 /* Inputs : None */ 691 /* Globals : None */ 692 /* Processing : None */ 693 /* Outputs : None */ 694 /* Returns : Thread ID, as a WORD32 */ 695 /* Issues : None */ 696 /* */ 697 /* Revision History: */ 698 /* */ 699 /* DD MM YYYY Author(s) Changes (Describe the changes made) */ 700 /* 07 05 2015 Ittiam Draft */ 701 /* */ 702 /*****************************************************************************/ 703 704 WORD32 osal_get_current_tid(void) 705 { 706 return syscall(__NR_gettid); 707 } 708