개요

_tx_byte_allocate에서는 인자로 제시된 memory_ptrmemory_size만큼 데이터를 할당하는 것을 목적으로 가지는 함수이다.

아래는 코드를 풀어서 표현한 플로우 차트이다.

이때 ‘대기 후 재시도’ 항목은 _tx_byte_allocate함수 내부에서 진행이 이루어지는 것이 아니라 _tx_byte_release가 호출 될 때, 재시도하게 된다.

tx_byte_pool_suspension_list로 들어가서 할당이 되기를 기다리게 된다. 이 큐에는 할당에 실패한 스레드가 들어가기 때문에 release가 이루어진 이후 다시 할당이 가능한지 확인하도록 동작한다.

이제 각 부분에 대해서 코드를 보며 보다 자세한 설명을 해보겠다.

충분한 메모리 발견?

_tx_byte_pool_search를 이해한다면 대부분 쉽게 이해할 수 있는 부분이다. 필요한 메모리를 탐색하고 할당에 성공 혹은 실패함에 따라서 work_ptr이 설정된다.

/* Loop to handle cases where the owner of the pool changed.  */
    do
    {
 
        /* Indicate that this thread is the current owner.  */
        pool_ptr -> tx_byte_pool_owner =  thread_ptr;
 
        /* Restore interrupts.  */
        TX_RESTORE
 
        /* At this point, the executing thread owns the pool and can perform a search
           for free memory.  */
        work_ptr =  _tx_byte_pool_search(pool_ptr, memory_size);
 
        /* Optional processing extension.  */
        TX_BYTE_ALLOCATE_EXTENSION
 
        /* Lockout interrupts.  */
        TX_DISABLE
 
        /* Determine if we are finished.  */
        if (work_ptr != TX_NULL)
        {
 
            /* Yes, we have found a block the search is finished.  */
            finished =  TX_TRUE;
        }
        else
        {
 
            /* No block was found, does this thread still own the pool?  */
            if (pool_ptr -> tx_byte_pool_owner == thread_ptr)
            {
 
                /* Yes, then we have looked through the entire pool and haven't found the memory.  */
                finished =  TX_TRUE;
            }
        }
 
    } while (finished == TX_FALSE);

while로 감싸져있는 것이 의아할 수 있는데, 내가 이해하기로는 search에서 실패한 이후 컨텍스트 스위칭이 이루어졌다면 해당 스레드에서 메모리를 release했을 가능성이 있으므로 search과정을 다시 수행하는 것으로 보인다.

코드에서 poolsearch하는 스레드가 소유하고 있다면 while을 탈출하는 것을 볼 수 있다.

할당이 성공적이라면 다음과 같은 status를 반환한다.

status =  TX_SUCCESS;
 
...
...
 
*memory_ptr =  (VOID *) work_ptr;
 
...
...
 
/* Return completion status.  */
return(status);

대기 옵션이 설정되었는가?

대기 옵션이 설정되지 않았다면 실패에 대한 status를 반환하고 함수를 마무리한다.

if (wait_option != TX_NO_WAIT)
{
 
    /* Determine if the preempt disable flag is non-zero.  */
    if (_tx_thread_preempt_disable != ((UINT) 0))
    {
 
        /* Suspension is not allowed if the preempt disable flag is non-zero at this point - return error completion.  */
        status =  TX_NO_MEMORY;
 
        /* Restore interrupts.  */
        TX_RESTORE
    }
    else
    {
        ...
        ...
    }
    ...
    ...
}

대기 옵션이 설정되어 있으면 작업이 조금 복잡해지는데 이후에 보다 자세하게 작성해보겠다.

스레드 일시중단

다음 3가지 데이터를 갱신하고 _tx_thread_system_suspend를 호출하여 스레드를 정지시킨다.

  • pool_ptr -> tx_byte_pool_suspension_list
  • thread_ptr -> tx_thread_suspended_next
  • thread_ptr -> tx_thread_suspended_previous
/* Prepare for suspension of this thread.  */
 
/* Setup cleanup routine pointer.  */
thread_ptr -> tx_thread_suspend_cleanup =  &(_tx_byte_pool_cleanup);
 
/* Setup cleanup information, i.e. this pool control block.  */
thread_ptr -> tx_thread_suspend_control_block =  (VOID *) pool_ptr;
 
/* Save the return memory pointer address as well.  */
thread_ptr -> tx_thread_additional_suspend_info =  (VOID *) memory_ptr;
 
/* Save the byte size requested.  */
thread_ptr -> tx_thread_suspend_info =  memory_size;
 
/* Pickup the number of suspended threads.  */
suspended_count =  pool_ptr -> tx_byte_pool_suspended_count;
 
/* Increment the suspension count.  */
(pool_ptr -> tx_byte_pool_suspended_count)++;
 
/* Setup suspension list.  */
if (suspended_count == TX_NO_SUSPENSIONS)
{
 
    /* No other threads are suspended.  Setup the head pointer and
    just setup this threads pointers to itself.  */
    pool_ptr -> tx_byte_pool_suspension_list =      thread_ptr;
    thread_ptr -> tx_thread_suspended_next =        thread_ptr;
    thread_ptr -> tx_thread_suspended_previous =    thread_ptr;
}
else
{
 
    /* This list is not NULL, add current thread to the end. */
    next_thread =                                   pool_ptr -> tx_byte_pool_suspension_list;
    thread_ptr -> tx_thread_suspended_next =        next_thread;
    previous_thread =                               next_thread -> tx_thread_suspended_previous;
    thread_ptr -> tx_thread_suspended_previous =    previous_thread;
    previous_thread -> tx_thread_suspended_next =   thread_ptr;
    next_thread -> tx_thread_suspended_previous =   thread_ptr;
}
 
/* Set the state to suspended.  */
thread_ptr -> tx_thread_state =       TX_BYTE_MEMORY;
 
/* Set the suspending flag.  */
thread_ptr -> tx_thread_suspending =  TX_TRUE;
 
/* Setup the timeout period.  */
thread_ptr -> tx_thread_timer.tx_timer_internal_remaining_ticks =  wait_option;
 
/* Temporarily disable preemption.  */
_tx_thread_preempt_disable++;
 
/* Restore interrupts.  */
TX_RESTORE
 
/* Call actual thread suspension routine.  */
_tx_thread_system_suspend(thread_ptr);
                
/* Return the completion status.  */
status =  thread_ptr -> tx_thread_suspend_status;

대기 후 재시도

이는 해당 함수의 범위를 벗어나므로 이후 다루도록 하겠다.

할당에 실패한 이상 _tx_byte_allocate에서는 더 이상 시도할 것이 없고 할당된 메모리가 해제되는 것을 기다려야하기 때문이다.