* @brief This function will take a semaphore, if the semaphore is unavailable, the thread shall wait for * the semaphore up to a specified time. * * @note When this function is called, the count value of the sem->value will decrease 1 until it is equal to 0. * When the sem->value is 0, it means that the semaphore is unavailable. At this time, it will suspend the *
| 556 | * @warning This function can ONLY be called in the thread context. It MUST NOT BE called in interrupt context. |
| 557 | */ |
| 558 | static rt_err_t _rt_sem_take(rt_sem_t sem, rt_int32_t timeout, int suspend_flag) |
| 559 | { |
| 560 | rt_base_t level; |
| 561 | struct rt_thread *thread; |
| 562 | rt_err_t ret; |
| 563 | |
| 564 | /* parameter check */ |
| 565 | RT_ASSERT(sem != RT_NULL); |
| 566 | RT_ASSERT(rt_object_get_type(&sem->parent.parent) == RT_Object_Class_Semaphore); |
| 567 | |
| 568 | RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(sem->parent.parent))); |
| 569 | |
| 570 | /* current context checking */ |
| 571 | RT_DEBUG_SCHEDULER_AVAILABLE(1); |
| 572 | |
| 573 | level = rt_spin_lock_irqsave(&(sem->spinlock)); |
| 574 | |
| 575 | LOG_D("thread %s take sem:%s, which value is: %d", |
| 576 | rt_thread_self()->parent.name, |
| 577 | sem->parent.parent.name, |
| 578 | sem->value); |
| 579 | |
| 580 | if (sem->value > 0) |
| 581 | { |
| 582 | /* semaphore is available */ |
| 583 | sem->value --; |
| 584 | rt_spin_unlock_irqrestore(&(sem->spinlock), level); |
| 585 | } |
| 586 | else |
| 587 | { |
| 588 | /* no waiting, return with timeout */ |
| 589 | if (timeout == 0) |
| 590 | { |
| 591 | rt_spin_unlock_irqrestore(&(sem->spinlock), level); |
| 592 | return -RT_ETIMEOUT; |
| 593 | } |
| 594 | else |
| 595 | { |
| 596 | /* semaphore is unavailable, push to suspend list */ |
| 597 | /* get current thread */ |
| 598 | thread = rt_thread_self(); |
| 599 | |
| 600 | /* reset thread error number */ |
| 601 | thread->error = RT_EINTR; |
| 602 | |
| 603 | LOG_D("sem take: suspend thread - %s", thread->parent.name); |
| 604 | |
| 605 | /* suspend thread */ |
| 606 | ret = rt_thread_suspend_to_list(thread, &(sem->parent.suspend_thread), |
| 607 | sem->parent.parent.flag, suspend_flag); |
| 608 | if (ret != RT_EOK) |
| 609 | { |
| 610 | rt_spin_unlock_irqrestore(&(sem->spinlock), level); |
| 611 | return ret; |
| 612 | } |
| 613 | |
| 614 | /* has waiting time, start thread timer */ |
| 615 | if (timeout > 0) |
no test coverage detected