메시지 메일박스(Message Mailbox) 기능

메시지 메일박스(Message Mailbox) 기능

메시지 메일박스는 태스크(Task)나 ISR(Interrupt Service Routine)에서 다른 태스크로 포인터(메시지)를 전송하기 위해 사용되는 매우 중요한 커널 오브젝트입니다.

본 포스팅에서는 메일박스의 개념부터 생성/삭제, 메시지 대기/전송, 상태 조회, 그리고 바이너리 세마포어처럼 활용하는 방법까지 차근차근 알아보겠습니다.

목차

  1. 메시지 메일박스란?
  2. 메일박스 생성: OSMboxCreate()
  3. 메일박스 삭제: OSMboxDel()
  4. 메일박스에서 메시지 대기: OSMboxPend()
  5. 메일박스로 메시지 보내기: OSMboxPost()
  6. 대기 없이 메시지 얻기: OSMboxAccept()
  7. 메일박스 상태 조회: OSMboxQuery()
  8. 메일박스를 바이너리 세마포어로 사용
  9. 마무리 및 참고

1. 메시지 메일박스란?

**메시지 메일박스(메일박스)**는 uC/OS-II에서 제공하는 커널 오브젝트 중 하나로,

  • 포인터 변수를 전달하여 태스크 간 통신을 수행
  • 전달되는 포인터는 보통 사용자가 정의한 “메시지” 구조체를 가리키는 포인터

주요 특징

  • 메일박스는 한 번에 하나의 포인터만 저장 가능
  • 메일박스에 포인터가 존재하면(차 있음) -> NULL이 아닌 값 보유
  • 메일박스가 비어 있으면 -> NULL 포인터
  • 태스크 혹은 ISR에서 메일박스에 메시지를 “보내거나(Post)”
  • 메일박스에 대기 중이던 태스크가 메시지를 “받거나(Pend)” 함

대표적인 메일박스 관련 API 함수

  • OSMboxCreate()
  • OSMboxPend()
  • OSMboxPost()
  • OSMboxPostOpt()
  • OSMboxAccept()
  • OSMboxQuery()

아래 그림은 태스크/ISR과 메시지 메일박스의 관계를 간단히 보여줍니다.

scss

복사편집

[ Task A ] —>(Post)—+

                       [ Message Mailbox ]—>(Pend)– [ Task B ]

[    ISR ] —>(Post)—+


2. 메일박스 생성: OSMboxCreate()

메일박스를 생성하려면 OSMboxCreate() 함수를 사용합니다. 이때 메일박스에 들어갈 초기 포인터를 지정할 수 있습니다(주로 NULL로 초기화).

c

복사편집

OS_EVENT *OSMboxCreate (void *msg) {

    OS_EVENT *pevent;

    …

    if (pevent != (OS_EVENT *)0) {

        pevent->OSEventType = OS_EVENT_TYPE_MBOX;

        pevent->OSEventCnt  = 0;       // 메일박스에서는 사용되지 않음

        pevent->OSEventPtr  = msg;     // 초기 메시지 포인터(주로 NULL)

        OSEventWaitListInit(pevent);

    }

    return (pevent);

}

  • msg: 초기화하고자 하는 메시지 포인터
  • 반환값: 생성한 메일박스를 가리키는 OS_EVENT * (ECB: Event Control Block)

생성 시 초기값 예시

  1. NULL로 생성: 이벤트 발생을 기다리는 용도
  2. NULL이 아닌 값: 이미 자원이 “사용 가능” 상태(바이너리 세마포어로 응용 가능)

3. 메일박스 삭제: OSMboxDel()

메일박스를 삭제할 수도 있습니다. 단, OS_MBOX_DEL_EN이 1로 설정되어 있어야 OSMboxDel() 함수를 사용할 수 있습니다.

c

복사편집

OS_EVENT *OSMboxDel (OS_EVENT *pevent, INT8U opt, INT8U *err) {

    BOOLEAN tasks_waiting;

    …

    switch (opt) {

        case OS_DEL_NO_PEND:

            // 메일박스에 대기 중인 태스크가 없어야 삭제 가능

            if (tasks_waiting == FALSE) {

                pevent->OSEventType = OS_EVENT_TYPE_UNUSED;

                pevent->OSEventPtr  = OSEventFreeList;

                OSEventFreeList     = pevent;

                *err = OS_NO_ERR; 

                return ((OS_EVENT *)0); // 메일박스 삭제 완료

            } else {

                *err = OS_ERR_TASK_WAITING; // 대기 중인 태스크가 있어 삭제 불가

                return (pevent);

            }

        …

    }

}

  • 옵션:
    • OS_DEL_NO_PEND: 대기 중인 태스크가 없을 때만 삭제
    • OS_DEL_ALWAYS: 강제로 삭제(대기 중인 태스크 모두 해제) – 설정 여부에 따라 달라질 수 있음

4. 메일박스에서 메시지 대기: OSMboxPend()

OSMboxPend() 함수는 지정한 메일박스에 메시지가 들어올 때까지 대기(Pend)하는 역할을 합니다.

  • 이미 메시지가 있으면 -> 즉시 메시지 획득
  • 메시지가 없다면 -> 태스크가 대기 상태로 전환되고, 메시지가 들어오면 깨어남

c

복사편집

void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) {

    void *msg;

    // 우선, 메일박스에 메시지가 있는지 확인

    msg = pevent->OSEventPtr;

    if (msg != (void *)0) {

        pevent->OSEventPtr = (void *)0; // 메일박스에서 메시지 꺼냄

        *err = OS_NO_ERR;

        return (msg);

    }

    // 메시지가 없으므로 대기 상태로 전환

    OSTCBCur->OSTCBStat |= OS_STAT_MBOX;

    OSTCBCur->OSTCBDly   = timeout;     // 타임아웃 설정

    OS_EventTaskWait(pevent);

    OS_Sched();                         // 다른 태스크에게 CPU 양보

    // 대기 해제 후(메시지가 도착했거나 타임아웃), 다시 확인

    msg = OSTCBCur->OSTCBMsg;

    if (msg != (void *)0) {

        OSTCBCur->OSTCBMsg  = (void *)0;

        OSTCBCur->OSTCBStat = OS_STAT_RDY;

        *err                = OS_NO_ERR;

        return (msg);

    }

    // 타임아웃 등으로 인한 에러 처리

    *err = OS_TIMEOUT;

    return ( (void *)0 );

}

  • timeout: 0이면 무한 대기, 0이 아니라면 지정한 틱(Tick) 수만큼 대기
  • 리턴값: 메시지를 가리키는 포인터(없으면 NULL)

5. 메일박스로 메시지 보내기: OSMboxPost()

다른 태스크나 ISR에서 특정 메일박스에 메시지를 전송하려면 OSMboxPost()를 사용합니다.

c

복사편집

INT8U OSMboxPost (OS_EVENT *pevent, void *msg) {

    OS_ENTER_CRITICAL();

    if (pevent->OSEventGrp != 0x00) {

        // 대기 중인 태스크가 있으면 즉시 꺠워서 메시지 전달

        OS_EventTaskRdy(pevent, msg, OS_STAT_MBOX);

        OS_EXIT_CRITICAL();

        OS_Sched();

        return (OS_NO_ERR);

    }

    // 메일박스가 이미 메시지를 보유(가득)하고 있는지 검사

    if (pevent->OSEventPtr != (void *)0) {

        OS_EXIT_CRITICAL();

        return (OS_MBOX_FULL); // 이미 다른 메시지가 차있음

    }

    // 메시지 대기 태스크도 없고, 메일박스가 비어있다면 메시지 저장

    pevent->OSEventPtr = msg;

    OS_EXIT_CRITICAL();

    return (OS_NO_ERR);

}

  • 메일박스에 이미 메시지가 있다면 -> OS_MBOX_FULL 에러 반환
  • 메시지를 기다리는 태스크가 있다면 -> 즉시 태스크를 깨워서(Ready) 메시지 전달

6. 대기 없이 메시지 얻기: OSMboxAccept()

OSMboxAccept()는 대기(Pend) 없이 메일박스에서 메시지를 가져오는 함수입니다.

  • 메일박스에 메시지가 없으면 NULL 리턴
  • 메시지가 있다면 가져온 후 메일박스를 비움(NULL로 설정)

c

복사편집

void *OSMboxAccept (OS_EVENT *pevent) {

    void *msg;

    OS_ENTER_CRITICAL();

    msg = pevent->OSEventPtr;

    pevent->OSEventPtr = (void *)0; // 메시지를 꺼냈다면 메일박스 비움

    OS_EXIT_CRITICAL();

    return (msg); // 메시지(또는 NULL) 반환

}


7. 메일박스 상태 조회: OSMboxQuery()

**OSMboxQuery()**를 사용하면 특정 메일박스(ECB)의 현재 상태를 얻을 수 있습니다.

  • 어떤 태스크들이 대기 중인지, 메일박스에 메시지가 있는지 등을 확인 가능

c

복사편집

INT8U OSMboxQuery (OS_EVENT *pevent, OS_MBOX_DATA *pdata) {

    INT8U *psrc, *pdest;

    …

    OS_ENTER_CRITICAL();

    pdata->OSEventGrp = pevent->OSEventGrp;

    psrc  = &pevent->OSEventTbl[0];

    pdest = &pdata->OSEventTbl[0];

    // 대기 테이블 복사 (크기만큼)

    #if OS_EVENT_TBL_SIZE > 0

        *pdest++ = *psrc++;

    #endif

    …

    OS_EXIT_CRITICAL();

    …

    return (OS_NO_ERR);

}

  • OS_MBOX_DATA *pdata 구조체에 메일박스 관련 정보 저장
  • 실제로는 OSEventGrp, OSEventTbl[] 등을 통해 대기 중인 태스크 상태 확인

8. 메일박스를 바이너리 세마포어로 사용

메일박스에 NULL이 아닌 값(예: (void *)1)을 저장하여 바이너리 세마포어처럼 활용할 수 있습니다.

  • 자원(세마포어)을 획득: OSMboxPend() (메일박스가 NULL이면 대기)
  • 자원 해제: OSMboxPost() (메일박스가 비었다면 NULL -> (void *)1로 채움)

c

복사편집

OS_EVENT *MboxSem;

void Task1 (void *pdata) {

    INT8U err;

    for (;;) {

        // 세마포어 획득과 동일하게 메일박스 대기

        OSMboxPend(MboxSem, 0, &err);

        // 자원 사용

        …

        // 자원 반납

        OSMboxPost(MboxSem, (void *)1);

    }

}

장점

  • 메일박스와 바이너리 세마포어를 동시에 사용할 필요 없이, **하나의 오브젝트(메일박스)**로 두 가지 기능을 모두 만족
  • 코드 공간 절약 및 구조 단순화

9. 마무리 및 참고

이상으로 uC/OS-II 메시지 메일박스(Message Mailbox) 기능을 살펴보았습니다.

  1. **OSMboxCreate()**로 생성 (초기 포인터 설정)
  2. 메시지 수신은 OSMboxPend()(대기) 혹은 OSMboxAccept()(대기 없이)
  3. 메시지 전송은 **OSMboxPost()**로 수행
  4. 필요 시 **OSMboxDel()**로 삭제 가능
  5. 메일박스를 바이너리 세마포어처럼 활용 가능

메시지 메일박스는 uC/OS-II에서 태스크 간 통신동기화를 간단하게 처리할 수 있는 강력한 도구입니다. 특히 포인터를 통해 자유로운 형식의 데이터를 전달할 수 있으므로, 임베디드 시스템 설계 시 유용하게 사용할 수 있습니다.

함께 보면 좋은 자료

  • uC/OS-II 공식 문서
  • [uC/OS-II 세마포어, 이벤트 플래그]

  • uC/OS-II 메일박스
  • 임베디드 RTOS 통신
  • Message Mailbox
  • OSMboxCreate, OSMboxPost, OSMboxPend
  • 바이너리 세마포어 활용
  • 임베디드 시스템 동기화

Leave a Comment