본문 바로가기
선점형 Kernel에서 wait, send, clr signal의 구현과 IRQ Handler

TCB를 관리하여, Kernel에게 현재 Task가 해야할 일과 상태를 알려주기 위한 Kernel API들 , 즉, wait_signal(), send_signal(), clr_signal()을 구현하려면 어떻게 하면 좋을 까..? 요? 일단 API가 어떻게 동작해야 하는지에 대해서 다시 한번 정리를 해 본다면, wait_signal()은 Task가 스스로 CPU 점유권을 놓으면서 특정 Signal을 기다리겠다는 의미이고요, send_signal()은 나 아닌 다른 Task에게 signal을 날려서 일좀 해다오 라는 의미이지요.
 
그리고, clr_signal()은 방금 활성화 된 Running Task가 방금 받은 signal을 지워서, 곧바로 다시 받을 수 있는 환경을 만들어 주겠다는 의미에요. 그러면, 현재 running task의 TCB의 member인 wait_signal, receive_signal을 이용해서 API를 한번 구현해 보시죠. signal은 32가지 종류를 처리할 수 있다고 치고, 32bit unsigned integer type으로 처리하는 게 좋을 것 같아요. 

자, 이렇게 구현이 가능한데, 조건이 하나 달렸죠. 조건은 해당 Task가 wait하려고 보니까, 그새 어떤 다른 넘이 자기한테 또 일을 시켰나 보는 거에요. 다른 넘이 일을 시켰으면 wait하기 전에 또 일을 하는 거죠 머. 조건 안에는 우리가 원래 하려던 일이 들어 있어요. 기다리려는 signal을 tcb에 등록 시키고요, Ready된 넘들 중에 제일 priority가 높은 넘을 찾고, 그 놈으로 Context Switching을 하는 거죠. find_highst_task_scheduler() + Context_Switching() 요 두 놈을 Scheduler라고 보믄 되겠네요.
두 번째로, 그러면 send_signal()은 어떻게 구현하면 좋을까요.
ⓐ send_signal의 인자로는 Destination Task의 TCB가 들어가야 하고요, 보낼 signal이 인자로 들어가야겠지요.
ⓑ그리고 send_signal은 destination task를 ready 상태로 만들어야겠고요.
 
ⓒ 그리고, Scheduling은 signal을 받는 task의 priority가 현재 ready된 task중 (현재 signal을 보내는 running task를 포함하여) 가장 priority가 높으면 Context switching을 해주고요, 아니면 CPU의 사용권을 놓지 않고요, - 왜냐하면 signal을 받은 놈이 ready된 놈 중에 가장 높으면 곧바로 일을 시킬 수 있으니까 뭐 그렇게 하는 거죠 - signal을 보낸 건 보낸 거고. 그냥 일을 계속 하는 거지요. 굳이 signal을 보내고 CPU의 사용권을 놓고 싶으면 wait_signal()을 꼭 해줘야 하는 거에요. 참고로, Ready Task List를 따로 관리하는 경우에는 send_signal()의 마지막 부분에, dest_tcb를 Ready Task List에 자신의 Priority에 맞는 위치에 넣어주시는 센스를 발휘해 주시면 돼요.

마지막으로 clr_signal()은 어떻게 구현되는 걸까요? 원하는 signal만 잘 지울 수 있으면 되겠죠. bit operation이니까 간단하게 이해 하시겠지요. 다만 signal을 clear하는 경우에는 Context switching이 일어날 필요가 없으니까, scheduler를 호출 할 필요가 전혀 엄써요.
 
void clr_signal (uint32 signal)
{
   uint32 tmp_signal;
 
   signal = ~signal;
   curr_task_tcb->receive_signal = curr_task_tcb->receive_signal & signal;
   return;
 
}
 
뭐, 대충 어떤 식으로 signal을 처리해야 할지를 봤는데, 실제로 Context Switching이 언제

일어 나는지 눈으로 확인해 봤네요. 이런 식이라면, wait_signal()이 불린 경우와, send_signa()이 불린 경우에 Context Switching이 일어날 껀데, wait_signal()이 불린 경우에는 해당 Task가 더 할 일이 없으면 무조건 Context Switching이 일어나고요, send_signal()의 경우에는 Context Switching이 일어날 수도 있고, 아닐 수도 있사와요. send_signal()을 하게 되면 대상 Task는 Ready가 되고요, Ready가 되면 뭐합니까, Priority가 Runnning Task보다 낮으면 일단은 Running Task가 할 일을 다 한 다음에야 순서를 받는 거죠. 머. 뭐, 이런 식으로 Task끼리는 Context Switching이 이루어 지고요, 선점형 Context Switching은 Interrupt가 걸린 후에 Highest Priority Ready Task가 시시 각각 변하는 것이겠죠.

 

그렇다는 건 Scheduler가 호출 되는 건 이런 Kernel API를 통해서 뿐만 아니라, IRQ mode에서 빠져 나오기 전에 호출 되게 Design 되어야 해요. 어떻게 해야 하느냐면,

 

IRQ_Handler
    SUB     lr, lr, #4   
    STMFD   sp!, {r0-r12, r14}
    LDR r3, = ISR_Handler
    LDR r3, [r3]
    BLX r3
 
    여기에 현재 가장 Priority가 높은 Task를 선정 할 수 있도록 하고,
    if (Priority가 가장 높은 Task가 방금 전까지 (Interrupt가 걸리던 순간) 실행 되던 Task와 같은지?)
    {
        같은 경우에는, Preemption이 일어나지 않을 case이므로,
        그냥 돌아가면 되고.
        STMFD   sp!, {r0-r2, pc}^ ; SPSR을 다시 CPSR로 복구해 주고, lr을 pc에 넣어주는 거죠.
     }
    else
    {
         다른 경우에는,
         Preemption이 일어나는 경우이므로, 이전에 실행되던 Task의 Context 즉, 현재
         IRQ mode의 Stack에 저장되어 있는 Context를 해당 Task의
         Stack에 저장해 주시고, 새롭게 선정된 다음 Task의 Context내용을 불러들여야 하니까
         다음 차례의 Task Context를 불러오는 방법은 다음 차례 Task의 TCB에 들어 있는
         Context를 TCB안의 sp를 참조하여 IRQ mode 이전의 Mode의 Register 에다가
         Context를 불러들인 후, SPSR을 CPSR로 복구하면 새로운 Task의 Context가 현재 CPU의
         Cotext가 되겠지요
     }
 
아.. 기네요. 이런 식으로 IRQ Handler를 만들어 주면 되겠죠.
 
요렇게 하면,

요런식의 Context Swtiching이 일어나게 할 수 있겠죠.
 
위의 의사 코드로 적은 부분을 일일히 다 코드 레벨로 들여다 보게 되면, 머리가 지끈 거릴 게 뻔하니까, 이 정도의 의사 코드로 접으려고 해요. Concept은 잘 들 아시니까, 구현을 한다거나, 해석을 할 때 제대로 할 수 있으리라 생각하고, 넘어 갑니다~
 

의사코드라는 건 영어로 유식하게는 Pseudo Code라고 부르고요, 실은 코드처럼 생긴 말로 된 코드를 의사코드라 불러요. 이걸 이용해서 코드의 원리를 설명할 때가 많고요, 저같은 경우에는 의사코드로 먼저 코드를 짠다음에 - 물론 /* */ 등으로 막아 놓고요, 그걸 실제 코드로 작성하는 일도 많아요. 상당히 유용하게 쓰인다니까요.

친절한 임베디드 시스템 개발자 되기 강좌 글 전체 리스트 (링크) -



댓글





친절한 임베디드 개발자 되기 강좌 글 전체 리스트 (링크) -