Try   HackMD

作業系統工程-IPC

Table Of Content

tags: 作業系統工程 Operating System Programming note, 110-1, 2021


IPC = Inter-Process Communication

IPC 在 rtdef 中的定義

struct rt_ipc_object { struct rt_object parent; /**< inherit from rt_object */ rt_list_t suspend_thread; /**< threads pended on this resource */ };

MailBox

Concept

  • a thread or interrupt service routine sends a 4-byte long message to the mailbox, and one or more threads can receive and process these messages from the mailbox .
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →
  • 若 receive mail 直到郵箱為空時,接收方(receiving thread)可以選擇 waiting/hanging thread、 直到有新的 mail 進來的之後再 wakeup,或可以選擇設一個 timeout,時間到了就出去再重新排隊。
  • 若有 mail 存在於 mailbox,receiving thread 就會接收 mailbox 中 4-bytes 的 message 到 receiving buffer 中。
  • MailBox 可使用的操作功能
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

Mailbox 在 rtdef 中的定義

#ifdef RT_USING_MAILBOX struct rt_mailbox { struct rt_ipc_object parent; /*inherit from ipc_object */ rt_ubase_t *msg_pool; /*message buffer 的起始位置 */ rt_uint16_t size; /*message pool 的空間大小 */ rt_uint16_t entry; /*msg_pool(郵箱) 中 mail 的數量 */ rt_uint16_t in_offset; /* input offset of the message buffer */ rt_uint16_t out_offset; /* output offset of the message buffer */ rt_list_t suspend_sender_thread;/* sender thread suspended on this mailbox */ }; typedef struct rt_mailbox *rt_mailbox_t; #endif

:star: 動態創建&刪除:create & delete
:star: 靜態創建&刪除:initial & detach

創建

  1. create
rt_mailbox_t rt_mb_create(const char *name, rt_size_t size, rt_uint8_t flag)
  • parameters
    1. name : mailbox 名稱
    2. size : mailbox 容量的大小
    3. flag : 可以知道這個 mailbox 是要 FIFO or Priority (RT_IPC_FLAG_FIFO 或RT_IPC_FLAG_PRIO)
{ rt_mailbox_t mb; RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO)); RT_DEBUG_NOT_IN_INTERRUPT; /* allocate object */ mb = (rt_mailbox_t)rt_object_allocate(RT_Object_Class_MailBox, name); if (mb == RT_NULL) return mb; /* set parent */ mb->parent.parent.flag = flag; /* initialize ipc object */ _ipc_object_init(&(mb->parent)); /* initialize mailbox */ mb->size = size; mb->msg_pool = (rt_ubase_t *)RT_KERNEL_MALLOC(mb->size * sizeof(rt_ubase_t)); if (mb->msg_pool == RT_NULL) { /* delete mailbox object */ rt_object_delete(&(mb->parent.parent)); return RT_NULL; } mb->entry = 0; mb->in_offset = 0; mb->out_offset = 0; /* initialize an additional list of sender suspend thread */ rt_list_init(&(mb->suspend_sender_thread)); return mb; }
  1. initial
rt_err_t rt_mb_init(rt_mailbox_t mb, const char *name, void *msgpool, rt_size_t size, rt_uint8_t flag) { RT_ASSERT(mb != RT_NULL); RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO)); /* initialize object */ rt_object_init(&(mb->parent.parent), RT_Object_Class_MailBox, name); /* set parent flag */ mb->parent.parent.flag = flag; /* initialize ipc object */ _ipc_object_init(&(mb->parent)); /* initialize mailbox */ mb->msg_pool = (rt_ubase_t *)msgpool; mb->size = size; mb->entry = 0; mb->in_offset = 0; mb->out_offset = 0; /* initialize an additional list of sender suspend thread */ rt_list_init(&(mb->suspend_sender_thread)); return RT_EOK; }

Send mail

  • 呼叫 rt_mb_send_wait() 函式,並自動將 timeout 設為 0
rt_err_t rt_mb_send(rt_mailbox_t mb, rt_ubase_t value) { return rt_mb_send_wait(mb, value, 0); }
  • send & wait(有 timeout)
rt_err_t rt_mb_send_wait(rt_mailbox_t mb, rt_ubase_t value, rt_int32_t timeout) { struct rt_thread *thread; register rt_ubase_t temp; rt_uint32_t tick_delta; /* parameter check */ RT_ASSERT(mb != RT_NULL); RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox); /* initialize delta tick */ tick_delta = 0; /* get current thread */ thread = rt_thread_self(); RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mb->parent.parent)));
  • 從這邊開始為 critical section,所以要把中斷關掉。
/* disable interrupt */ temp = rt_hw_interrupt_disable(); /* for non-blocking call */ if (mb->entry == mb->size && timeout == 0) { rt_hw_interrupt_enable(temp); return -RT_EFULL; }
  • send mail 時,要處理 mailbax full 就不能再 send 的情形
/* mailbox is full */ while (mb->entry == mb->size) { /* reset error number in thread */ thread->error = RT_EOK; /* no waiting, return timeout */ if (timeout == 0) {// 如果沒有時間再等待就不等,打開中斷就 return waiting queue 是滿的 /* enable interrupt */ rt_hw_interrupt_enable(temp); return -RT_EFULL; } RT_DEBUG_IN_THREAD_CONTEXT; /* suspend current thread */ _ipc_list_suspend(&(mb->suspend_sender_thread), thread, mb->parent.parent.flag); //!mailbox 是滿的,所以現在的 thread 沒有辦法被放入 mailbox 進行IPC! 只好被掛起來 waiting,等到 wakeup 時再從這邊回來執行!! /* has waiting time, start thread timer */ if (timeout > 0) { /* get the start tick of timer */ tick_delta = rt_tick_get(); RT_DEBUG_LOG(RT_DEBUG_IPC, ("mb_send_wait: start timer of thread:%s\n", thread->name)); /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout); rt_timer_start(&(thread->thread_timer)); } /* enable interrupt */ rt_hw_interrupt_enable(temp); //要打開中斷才可以進行排程。 /* re-schedule */ rt_schedule(); /* resume from suspend state */ if (thread->error != RT_EOK) return thread->error;/* return error */ /* disable interrupt */ temp = rt_hw_interrupt_disable(); /* if it's not waiting forever and then re-calculate timeout tick */ if (timeout > 0) { tick_delta = rt_tick_get() - tick_delta; timeout -= tick_delta; if (timeout < 0) timeout = 0; //如果減完 tick_delta 後得到的 timeout <0,就將 timeout 設為 0,讓下層迴圈時進入 line 18準備進行 return } } /* set ptr */ mb->msg_pool[mb->in_offset] = value; /* increase input offset */ ++ mb->in_offset; if (mb->in_offset >= mb->size) mb->in_offset = 0; if(mb->entry < RT_MB_ENTRY_MAX) mb->entry ++;/* increase message entry */ else { rt_hw_interrupt_enable(temp); /* enable interrupt */ return -RT_EFULL; /* value overflowed */ } /* resume suspended thread */ if (!rt_list_isempty(&mb->parent.suspend_thread)) { _ipc_list_resume(&(mb->parent.suspend_thread)); /* enable interrupt */ rt_hw_interrupt_enable(temp); // 做完 critical section 就要把中斷打開。 //要打開中斷才可以進行排程。 rt_schedule(); return RT_EOK; } /* enable interrupt */ rt_hw_interrupt_enable(temp); //回傳之前要將中斷打開。 return RT_EOK; }

Receive mail

rt_err_t rt_mb_recv(rt_mailbox_t mb, rt_ubase_t *value, rt_int32_t timeout) { struct rt_thread *thread; register rt_ubase_t temp; rt_uint32_t tick_delta; /* parameter check */ RT_ASSERT(mb != RT_NULL); RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox); /* initialize delta tick */ tick_delta = 0; /* get current thread */ thread = rt_thread_self(); RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mb->parent.parent)));
  • 關中斷。
/* disable interrupt */ temp = rt_hw_interrupt_disable(); /* for non-blocking call */ if (mb->entry == 0 && timeout == 0) { rt_hw_interrupt_enable(temp); return -RT_ETIMEOUT; }//和 send 大同小異
  • receive mail 時,要處理 mailbax empty 就不能再拿 mail 的情形
/* mailbox is empty */ while (mb->entry == 0) { /* reset error number in thread */ thread->error = RT_EOK; /* no waiting, return timeout */ if (timeout == 0) { /* enable interrupt */ rt_hw_interrupt_enable(temp); thread->error = -RT_ETIMEOUT; return -RT_ETIMEOUT; } RT_DEBUG_IN_THREAD_CONTEXT; /* suspend current thread */ _ipc_list_suspend(&(mb->parent.suspend_thread), thread, mb->parent.parent.flag);
  • receive 和 send 大同小異,不同於 send 是因 mailbox full 才進此 while loop 而被 hanging,而 receive 是因 mailbox empty 才要被 hanging
/* has waiting time, start thread timer */ if (timeout > 0) { /* get the start tick of timer */ tick_delta = rt_tick_get(); RT_DEBUG_LOG(RT_DEBUG_IPC, ("mb_recv: start timer of thread:%s\n", thread->name)); /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout); rt_timer_start(&(thread->thread_timer)); } /* enable interrupt */ rt_hw_interrupt_enable(temp); /* re-schedule */ rt_schedule(); /* resume from suspend state */ if (thread->error != RT_EOK) return thread->error;/* return error */ /* disable interrupt */ temp = rt_hw_interrupt_disable(); /* if it's not waiting forever and then re-calculate timeout tick */ if (timeout > 0) { tick_delta = rt_tick_get() - tick_delta; timeout -= tick_delta; if (timeout < 0) timeout = 0; } } /* fill ptr */ *value = mb->msg_pool[mb->out_offset]; /* increase output offset */ ++ mb->out_offset; if (mb->out_offset >= mb->size) mb->out_offset = 0; /* decrease message entry */ if(mb->entry > 0) mb->entry --; /* resume suspended thread */ if (!rt_list_isempty(&(mb->suspend_sender_thread))) { _ipc_list_resume(&(mb->suspend_sender_thread)); /* enable interrupt */ rt_hw_interrupt_enable(temp); RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mb->parent.parent))); rt_schedule(); return RT_EOK; } /* enable interrupt */ rt_hw_interrupt_enable(temp); RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mb->parent.parent))); return RT_EOK; }

刪除

  1. delete
  • 和 create 相對,刪除 create 動態配置的 mailbox
  • 如果有 thread 被 hanged 在該郵箱對像上,kernek 要先 wakeup 在該 mailbox 的所有 hanging threads(線程返回值是-RT_ERROR),然後再釋放郵箱使用的內存,最後刪除郵箱對象。
rt_err_t rt_mb_delete(rt_mailbox_t mb) { /* parameter check */ RT_ASSERT(mb != RT_NULL); RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox); RT_ASSERT(rt_object_is_systemobject(&mb->parent.parent) == RT_FALSE); RT_DEBUG_NOT_IN_INTERRUPT; // 叫醒 hanging threads _ipc_list_resume_all(&(mb->parent.suspend_thread));/* resume all suspended thread */ _ipc_list_resume_all(&(mb->suspend_sender_thread));/* also resume all mailbox private suspended thread */ /* free mailbox pool */ RT_KERNEL_FREE(mb->msg_pool);//因為是動態,不用的話要 free 掉才不會占空間 /* delete mailbox object */ rt_object_delete(&(mb->parent.parent)); return RT_EOK; }
  1. detach
  • 和 init 相對,移除 init 靜態配置的 mailbox。
rt_err_t rt_mb_detach(rt_mailbox_t mb) { /* parameter check */ RT_ASSERT(mb != RT_NULL); RT_ASSERT(rt_object_get_type(&mb->parent.parent) == RT_Object_Class_MailBox); RT_ASSERT(rt_object_is_systemobject(&mb->parent.parent)); // 叫醒 hanging threads _ipc_list_resume_all(&(mb->parent.suspend_thread));/* resume all suspended thread */ _ipc_list_resume_all(&(mb->suspend_sender_thread));/* also resume all mailbox private suspended thread */ /* detach mailbox object */ rt_object_detach(&(mb->parent.parent)); return RT_EOK; }

Message Queue

Concept

  • Message 可使用的操作功能
    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

Message Queue 在 rtdef 中的定義

#ifdef RT_USING_MESSAGEQUEUE struct rt_messagequeue { struct rt_ipc_object parent; /* inherit from ipc_object */ void *msg_pool; /* start address of message queue */ rt_uint16_t msg_size; /* message size of each message */ //每個 message 的大小 rt_uint16_t max_msgs; /* max number of messages */ //最大可以放的 message 數量 rt_uint16_t entry; /* index of messages in the queue */ void *msg_queue_head; /* list head */ void *msg_queue_tail; /* list tail */ void *msg_queue_free; /* pointer indicated the free node of queue */ rt_list_t suspend_sender_thread;/* sender thread suspended on this message queue */ // hanging queue }; typedef struct rt_messagequeue *rt_mq_t; #endif

message Queue 在 ipc.c 的 structure

struct rt_mq_message { struct rt_mq_message *next;// linker-list 指向下一個 node 的 pointer };

創建

  1. create
rt_mq_t rt_mq_create(const char *name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag) { struct rt_messagequeue *mq; struct rt_mq_message *head; register rt_base_t temp; RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO)); RT_DEBUG_NOT_IN_INTERRUPT; /* allocate object */ mq = (rt_mq_t)rt_object_allocate(RT_Object_Class_MessageQueue, name); if (mq == RT_NULL) return mq; /* set parent */ mq->parent.parent.flag = flag; /* initialize ipc object */ _ipc_object_init(&(mq->parent)); /* initialize message queue */ /* get correct message size */ mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE); mq->max_msgs = max_msgs; /* allocate message pool */ mq->msg_pool = RT_KERNEL_MALLOC((mq->msg_size + sizeof(struct rt_mq_message)) * mq->max_msgs); if (mq->msg_pool == RT_NULL) { rt_object_delete(&(mq->parent.parent)); return RT_NULL; } /* initialize message list */ mq->msg_queue_head = RT_NULL; mq->msg_queue_tail = RT_NULL; /* initialize message empty list */ mq->msg_queue_free = RT_NULL; for (temp = 0; temp < mq->max_msgs; temp ++) { head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool + temp*(mq->msg_size + sizeof(struct rt_mq_message))); head->next = (struct rt_mq_message *)mq->msg_queue_free; mq->msg_queue_free = head; } mq->entry = 0;/* the initial entry is zero */ rt_list_init(&(mq->suspend_sender_thread));/* initialize an additional list of sender suspend thread */ return mq; }
  1. initial
rt_err_t rt_mq_init(rt_mq_t mq, const char *name, void *msgpool, rt_size_t msg_size, rt_size_t pool_size, rt_uint8_t flag) { struct rt_mq_message *head; register rt_base_t temp; /* parameter check */ RT_ASSERT(mq != RT_NULL); RT_ASSERT((flag == RT_IPC_FLAG_FIFO) || (flag == RT_IPC_FLAG_PRIO)); /* initialize object */ rt_object_init(&(mq->parent.parent), RT_Object_Class_MessageQueue, name); /* set parent flag */ mq->parent.parent.flag = flag; /* initialize ipc object */ _ipc_object_init(&(mq->parent)); /* set message pool */ mq->msg_pool = msgpool; /* get correct message size */ mq->msg_size = RT_ALIGN(msg_size, RT_ALIGN_SIZE); mq->max_msgs = pool_size / (mq->msg_size + sizeof(struct rt_mq_message)); /* initialize message list */ mq->msg_queue_head = RT_NULL; mq->msg_queue_tail = RT_NULL; /* initialize message empty list */ mq->msg_queue_free = RT_NULL; for (temp = 0; temp < mq->max_msgs; temp ++) { head = (struct rt_mq_message *)((rt_uint8_t *)mq->msg_pool + temp*(mq->msg_size + sizeof(struct rt_mq_message))); head->next = (struct rt_mq_message *)mq->msg_queue_free; mq->msg_queue_free = head; } mq->entry = 0;/* the initial entry is zero */ /* initialize an additional list of sender suspend thread */ rt_list_init(&(mq->suspend_sender_thread)); return RT_EOK; }

Send message

rt_err_t rt_mq_send(rt_mq_t mq, const void *buffer, rt_size_t size) { return rt_mq_send_wait(mq, buffer, size, 0); }
rt_err_t rt_mq_send_wait(rt_mq_t mq, const void *buffer, rt_size_t size, rt_int32_t timeout) { register rt_ubase_t temp; struct rt_mq_message *msg; rt_uint32_t tick_delta; struct rt_thread *thread; /* parameter check */ RT_ASSERT(mq != RT_NULL); RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue); RT_ASSERT(buffer != RT_NULL); RT_ASSERT(size != 0); /* greater than one message size */ if (size > mq->msg_size) return -RT_ERROR; /* initialize delta tick */ tick_delta = 0; /* get current thread */ thread = rt_thread_self(); RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(mq->parent.parent))); /* disable interrupt */ temp = rt_hw_interrupt_disable(); /* get a free list, there must be an empty item */ msg = (struct rt_mq_message *)mq->msg_queue_free; /* for non-blocking call */ if (msg == RT_NULL && timeout == 0) { /* enable interrupt */ rt_hw_interrupt_enable(temp); return -RT_EFULL; } /* message queue is full */ while ((msg = (struct rt_mq_message *)mq->msg_queue_free) == RT_NULL) { /* reset error number in thread */ thread->error = RT_EOK; /* no waiting, return timeout */ if (timeout == 0) { /* enable interrupt */ rt_hw_interrupt_enable(temp); return -RT_EFULL; } RT_DEBUG_IN_THREAD_CONTEXT; /* suspend current thread */ _ipc_list_suspend(&(mq->suspend_sender_thread), thread, mq->parent.parent.flag); /* has waiting time, start thread timer */ if (timeout > 0) { /* get the start tick of timer */ tick_delta = rt_tick_get(); RT_DEBUG_LOG(RT_DEBUG_IPC, ("mq_send_wait: start timer of thread:%s\n", thread->name)); /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout); rt_timer_start(&(thread->thread_timer)); } /* enable interrupt */ rt_hw_interrupt_enable(temp); /* re-schedule */ rt_schedule(); /* resume from suspend state */ if (thread->error != RT_EOK) { /* return error */ return thread->error; } /* disable interrupt */ temp = rt_hw_interrupt_disable(); /* if it's not waiting forever and then re-calculate timeout tick */ if (timeout > 0) { tick_delta = rt_tick_get() - tick_delta; timeout -= tick_delta; if (timeout < 0) timeout = 0; } } /* move free list pointer */ mq->msg_queue_free = msg->next; /* enable interrupt */ rt_hw_interrupt_enable(temp); /* the msg is the new tailer of list, the next shall be NULL */ msg->next = RT_NULL; /* copy buffer */ rt_memcpy(msg + 1, buffer, size); /* disable interrupt */ temp = rt_hw_interrupt_disable(); /* link msg to message queue */ if (mq->msg_queue_tail != RT_NULL)/* if the tail exists*/ ((struct rt_mq_message *)mq->msg_queue_tail)->next = msg; /* set new tail */ mq->msg_queue_tail = msg; /* if the head is empty, set head */ if (mq->msg_queue_head == RT_NULL) mq->msg_queue_head = msg; if(mq->entry < RT_MQ_ENTRY_MAX) mq->entry ++;/* increase message entry */ else { rt_hw_interrupt_enable(temp); /* enable interrupt */ return -RT_EFULL; /* value overflowed */ } /* resume suspended thread */ if (!rt_list_isempty(&mq->parent.suspend_thread)) { _ipc_list_resume(&(mq->parent.suspend_thread)); /* enable interrupt */ rt_hw_interrupt_enable(temp); rt_schedule(); return RT_EOK; } /* enable interrupt */ rt_hw_interrupt_enable(temp); return RT_EOK; }

Receive message

rt_err_t rt_mq_recv(rt_mq_t mq, void *buffer, rt_size_t size, rt_int32_t timeout) { struct rt_thread *thread; register rt_ubase_t temp; struct rt_mq_message *msg; rt_uint32_t tick_delta; /* parameter check */ RT_ASSERT(mq != RT_NULL); RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue); RT_ASSERT(buffer != RT_NULL); RT_ASSERT(size != 0); /* initialize delta tick */ tick_delta = 0; /* get current thread */ thread = rt_thread_self(); RT_OBJECT_HOOK_CALL(rt_object_trytake_hook, (&(mq->parent.parent))); /* disable interrupt */ temp = rt_hw_interrupt_disable(); /* for non-blocking call */ if (mq->entry == 0 && timeout == 0) { rt_hw_interrupt_enable(temp); return -RT_ETIMEOUT; } /* message queue is empty */ while (mq->entry == 0) { RT_DEBUG_IN_THREAD_CONTEXT; /* reset error number in thread */ thread->error = RT_EOK; /* no waiting, return timeout */ if (timeout == 0) { /* enable interrupt */ rt_hw_interrupt_enable(temp); thread->error = -RT_ETIMEOUT; return -RT_ETIMEOUT; } /* suspend current thread */ _ipc_list_suspend(&(mq->parent.suspend_thread), thread, mq->parent.parent.flag); /* has waiting time, start thread timer */ if (timeout > 0) { /* get the start tick of timer */ tick_delta = rt_tick_get(); RT_DEBUG_LOG(RT_DEBUG_IPC, ("set thread:%s to timer list\n", thread->name)); /* reset the timeout of thread timer and start it */ rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout); rt_timer_start(&(thread->thread_timer)); } /* enable interrupt */ rt_hw_interrupt_enable(temp); /* re-schedule */ rt_schedule(); /* recv message */ if (thread->error != RT_EOK) return thread->error;/* return error */ /* disable interrupt */ temp = rt_hw_interrupt_disable(); /* if it's not waiting forever and then re-calculate timeout tick */ if (timeout > 0) { tick_delta = rt_tick_get() - tick_delta; timeout -= tick_delta; if (timeout < 0) timeout = 0; } } /* get message from queue */ msg = (struct rt_mq_message *)mq->msg_queue_head; /* move message queue head */ mq->msg_queue_head = msg->next; /* reach queue tail, set to NULL */ if (mq->msg_queue_tail == msg) mq->msg_queue_tail = RT_NULL; /* decrease message entry */ if(mq->entry > 0) mq->entry --; /* enable interrupt */ rt_hw_interrupt_enable(temp); /* copy message */ rt_memcpy(buffer, msg + 1, size > mq->msg_size ? mq->msg_size : size); /* disable interrupt */ temp = rt_hw_interrupt_disable(); /* put message to free list */ msg->next = (struct rt_mq_message *)mq->msg_queue_free; mq->msg_queue_free = msg; /* resume suspended thread */ if (!rt_list_isempty(&(mq->suspend_sender_thread))) { _ipc_list_resume(&(mq->suspend_sender_thread)); /* enable interrupt */ rt_hw_interrupt_enable(temp); RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mq->parent.parent))); rt_schedule(); return RT_EOK; } /* enable interrupt */ rt_hw_interrupt_enable(temp); RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(mq->parent.parent))); return RT_EOK; }

刪除

  • mq 的刪除(delete 和 detach)和 mb 的觀念差不多,就不再贅述。
  1. delete
rt_err_t rt_mq_delete(rt_mq_t mq) { /* parameter check */ RT_ASSERT(mq != RT_NULL); RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue); RT_ASSERT(rt_object_is_systemobject(&mq->parent.parent) == RT_FALSE); RT_DEBUG_NOT_IN_INTERRUPT; _ipc_list_resume_all(&(mq->parent.suspend_thread));/* resume all suspended thread */ _ipc_list_resume_all(&(mq->suspend_sender_thread));/* also resume all message queue private suspended thread */ RT_KERNEL_FREE(mq->msg_pool);/* free message queue pool */ rt_object_delete(&(mq->parent.parent));/* delete message queue object */ return RT_EOK; }
  1. detach
rt_err_t rt_mq_detach(rt_mq_t mq) { /* parameter check */ RT_ASSERT(mq != RT_NULL); RT_ASSERT(rt_object_get_type(&mq->parent.parent) == RT_Object_Class_MessageQueue); RT_ASSERT(rt_object_is_systemobject(&mq->parent.parent)); _ipc_list_resume_all(&mq->parent.suspend_thread);/* resume all suspended thread */ _ipc_list_resume_all(&(mq->suspend_sender_thread));/* also resume all message queue private suspended thread */ rt_object_detach(&(mq->parent.parent));/* detach message queue object */ return RT_EOK; }