The IPC (Inter-Process Communication) of the rt-thread operating system contains semaphores, mutex locks, events, mailboxes, and message queues. this article focuses on semaphores. 1. Semaphore control block [cpp]/*** Semaphore structure */struct rt_semaphore {struct rt_ipc_object parent;/*** <inherit from ipc_object * // derived from IPC object rt_uint16_t value; /** <value of semaphore. * // semaphore counter}; typedef struct rt_semaphore * rt_sem_t; value indicates the signal counter, and parent indicates rt_ipc_object, which is the IPC object. Its definition is as follows: [cpp]/*** Base structure of IPC obje Ct */struct rt_ipc_object {struct rt_object parent;/** <inherit from rt_object * // you can see that it is derived from the kernel object rt_list_t suspend_thread; /*** <threads pended on this resource * // thread-suspended linked list}; The definition structure of rt_ipc_object shows that it is derived from the rt_object structure, that is, the definition of the kernel object (refer to the http://blog.csdn.net/flydream0/article/details/8568463 ), in addition, it does not contain a linked list and is used to store threads suspended due to semaphores. 2 semaphore creation and initialization 2.1 initialization [cpp]/*** This function will initialize a semaphore and put it under contr Ol of * resource management. ** @ param sem the semaphore object * @ param name the name of semaphore * @ param value the init value of semaphore * @ param flag the flag of semaphore ** @ return the operation status, RT_EOK on successful */rt_err_t rt_sem_init (rt_sem_t sem, const char * name, rt_uint32_t value, rt_uint8_t flag) {RT_ASSERT (sem! = RT_NULL);/* init object */rt_object_init (& (sem-> parent. parent), RT_Object_Class_Semaphore, name); // initialize the kernel object of the semaphore/* init ipc object */rt_ipc_object_init (& (sem-> parent )); // initialize the IPC object of the semaphore/* set init value */sem-> value = value; // set the value of the semaphore counter/* set parent */sem-> parent. parent. flag = flag; // set the flag of the semaphore Kernel Object return RT_EOK;} The rt_object_init has been introduced in the previous article about the rt-thread kernel object (see: http://blog.csdn.net/flydream0 /Article/details/8568463). The rt_ipc_object_init function is described as follows: [cpp]/*** @ addtogroup IPC * // * @ {* // *** This function will initialize an IPC object *** @ param ipc the IPC object **@ return the operation status, RT_EOK on successful */rt_inline rt_err_t rt_ipc_object_init (struct rt_ipc_object * ipc) {/* init ipc object */rt_list_init (& (ipc-> suspend_thread )); // The initialization thread suspends the linked list return RT_EOK;} 2.2 creates a semaphore [cpp]/** * This function will create a semaphore from system resource ** @ param name the name of semaphore * @ param value the init value of semaphore * @ param flag the flag of semaphore ** @ return the created semaphore, RT_NULL on error happen ** @ see rt_sem_init */rt_sem_t rt_sem_create (const char * name, rt_uint32_t value, rt_uint8_t flag) {rt_sem_t sem; done; // make sure that this function is not used during interruption/* Llocate object */sem = (rt_sem_t) rt_object_allocate (RT_Object_Class_Semaphore, name); // dynamically allocates the kernel object if (sem = RT_NULL) return sem; /* init ipc object */rt_ipc_object_init (& (sem-> parent); // initialize the IPC object of the semaphore/* set init value */sem-> value = value; // initialize the counter value of the semaphore/* set parent */sem-> parent. parent. flag = flag; // set the flag of the semaphore Kernel Object return sem;} 3. detach and delete the semaphore 3.1. detach the semaphore [cpp]/*** This function will detach a semaphor E from resource management ** @ param sem the semaphore object ** @ return the operation status, RT_EOK on successful ** @ see rt_sem_delete */rt_err_t rt_sem_detach (rt_sem_t sem) {RT_ASSERT (sem! = RT_NULL);/* wakeup all suspend threads */rt_ipc_list_resume_all (& (sem-> parent. suspend_thread); // wake up the threads suspended in all semaphores/* detach semaphore object */rt_object_detach (& (sem-> parent. parent); // return RT_EOK from the semaphore kernel object;} The rt_ipc_list_resume_all function is as follows: [cpp]/*** This function will resume all suincluded threads in a list, including * suspend list of IPC object and private list of mailbox etc. ** @ param lis T of the threads to resume ** @ return the operation status, RT_EOK on successful */rt_inline rt_err_t encode (rt_list_t * list) {struct rt_thread * thread; register rt_ubase_t temp; /* wakeup all suspend threads */while (! Rt_list_isempty (list) // traverses the thread to suspend the linked list {/* disable interrupt */temp = rt_hw_interrupt_disable (); // Guanzhong disconnection/* get next suspend thread */thread = rt_list_entry (list-> next, struct rt_thread, tlist ); // obtain the thread/* set error code to RT_ERROR */thread-> error =-RT_ERROR; // set the error code of the thread to-RT_ERROR/** resume thread * In rt_thread_resume function, it will remove current thread from * suspend list */rt_thread_resume (threa D); // wake up this thread/* enable interrupt */rt_hw_interrupt_enable (temp); // open interrupt} return RT_EOK ;} 3.2 delete thread [cpp]/*** This function will delete a semaphore object and release the memory ** @ param sem the semaphore object ** @ return the error code ** @ see rt_sem_detach */rt_err_t rt_sem_delete (rt_sem_t sem) {RT_DEBUG_NOT_IN_INTERRUPT; // make sure this function does not use RT_ASSERT (sem! = RT_NULL);/* wakeup all suspend threads */rt_ipc_list_resume_all (& (sem-> parent. suspend_thread); // wake up all pending threads/* delete semaphore object */rt_object_delete (& (sem-> parent. parent); // Delete the semaphore Kernel Object return RT_EOK;} 4 obtain the semaphore 4.1 wait for the semaphore [cpp]/*** This function will take a semaphore, if the semaphore is unavailable, the * thread shall wait for a specified time. ** @ param sem the semaphore object * @ param ti Me the waiting time ** @ return the error code */rt_err_t rt_sem_take (rt_sem_t sem, rt_int32_t time) {register rt_base_t temp; struct rt_thread * thread; RT_ASSERT (sem! = RT_NULL); RT_OBJECT_HOOK_CALL (rt_object_trytake_hook, (& (sem-> parent. parent);/* disable interrupt */temp = rt_hw_interrupt_disable (); // disconnect RT_DEBUG_LOG (RT_DEBUG_IPC, ("thread % s take sem: % s, which value is: % d \ n ", rt_thread_self ()-> name, (struct rt_object *) sem)-> name, sem-> value )); if (sem-> value> 0) // if the counter value of this semaphore is greater than 0, there is a signal, then {/* semaphore is available */sem-> value --; // is returned immediately to subtract the value of the semaphore counter. 1/* enable interrupt */rt_hw_interrupt_enable (temp); // open interrupt} else // If the counter value of this semaphore is less than or equal to 0, note that no signal {/* no waiting, return with timeout */if (time = 0) // if the wait time parameter is 0, then the timeout error {rt_hw_interrupt_enable (temp) is returned immediately; // The return-RT_ETIMEOUT is interrupted; // The return timeout error} else // wait signal {/* current context checking */RT_DEBUG_NOT_IN_INTERRUPT; // ensure that the thread is not interrupted at this time/* semaphore is unavailable, push to suspend list */* get current thread */Thread = rt_thread_self (); // obtain the currently running thread/* reset thread error number */thread-> error = RT_EOK; // set the error code of the current thread to RT_EOK. Note the following: RT_DEBUG_LOG (RT_DEBUG_IPC, ("sem take: suspend thread-% s \ n", thread-> name )); /* suspend thread */rt_ipc_list_suspend (& (sem-> parent. suspend_thread), // suspend the thread linked list thread from the current thread to the semaphore, sem-> parent. parent. flag);/* has waiting time, start thread timer */if (time> 0) // if the time parameter is greater than 0 {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), // set the timer RT_TIMER_CTRL_SET_TIME, & time ); rt_timer_start (& (thread-> thread_timer); // start the timer to start the timer}/* enable interrupt */rt_hw_interrupt_enable (temp ); // enable/* do schedule */rt_schedule (); // The current thread has been suspended. You need to re-debug the thread // rt_schedule and then execute it here. Only There are two possibilities: the current thread has arrived after being suspended. At this time, the timer's timeout callback handler sets the err value of this thread to-RT_ETIMEOU, as shown in thread. the rt_thread_timeout function in the c source file. In another case, when a semaphore arrives, the current thread is awakened by the rt_sem_release function. At this time, the err value of this thread remains unchanged, therefore, the following may determine whether the current thread has received the semaphore if (thread-> error! = RT_EOK) // if the error code of the current thread is not RT_EOK, it is returned. Otherwise, it is blocked until a signal arrives or times out. {return thread-> error ;}}} RT_OBJECT_HOOK_CALL (rt_object_take_hook, (& (sem-> parent. parent); return RT_EOK ;} 4.2 obtain a non-waiting semaphore [cpp]/*** This function will try to take a semaphore and immediately return ** @ param sem the semaphore object ** @ return the error code */ rt_err_t rt_sem_trytake (rt_sem_t sem) {return rt_sem_take (sem, 0);} it can be seen that rt _ Sem_trytake is only a special case of the rt_sem_take function. The time parameter is 0. 5. release the semaphore [cpp]/*** This function will release a semaphore, if there are threads suincluded on * semaphore, it will be waked up. ** @ param sem the semaphore object ** @ return the error code */rt_err_t rt_sem_release (rt_sem_t sem) {register rt_base_t temp; register rt_bool_t need_schedule, (& (sem-> parent. parent ))); Need_schedule = RT_FALSE; // by default, you do not need to re-schedule the tag/* disable interrupt */temp = rt_hw_interrupt_disable (); // disable RT_DEBUG_LOG (RT_DEBUG_IPC, ("thread % s releases sem: % s, which value is: % d \ n", rt_thread_self ()-> name, (struct rt_object *) sem)-> name, sem-> value); if (! Rt_list_isempty (& sem-> parent. suspend_thread) // the suspended thread is not empty {/* resume the suincluded thread */rt_ipc_list_resume (& (sem-> parent. suspend_thread); // wake up the first suspended thread need_schedule = RT_TRUE; // needs to be rescheduled} else sem-> value ++; /* increase value * // Add 1/* enable interrupt */rt_hw_interrupt_enable (temp) to the semaphore counter; // enable/* resume a thread, re-schedule */if (need_schedule = RT_TRUE) // if you need to reschedule the thread, reschedule rt_schedule (); retur N RT_EOK;} the function rt_ipc_list_resume only wakes up the first suspended thread in the semaphore. The source code is as follows: [cpp]/*** This function will resume the first thread in the list of a IPC object: *-remove the thread from suspend queue of IPC object *-put the thread into system ready queue ** @ param list the thread list ** @ return the operation status, RT_EOK on successful */rt_inline rt_err_t rt_ipc_list_resume (rt_list_t * list) {struct rt_thre Ad * thread;/* get thread entry */thread = rt_list_entry (list-> next, struct rt_thread, tlist); // obtain the RT_DEBUG_LOG (RT_DEBUG_IPC, ("resume thread: % s \ n ", thread-> name);/* resume it */rt_thread_resume (thread); // wake up this thread return RT_EOK ;} 6. semaphore control [cpp]/*** This function can get or set some extra attributions of a semaphore object. ** @ param sem the semaphore object * @ param cmd the execution command * @ Param arg the execution argument ** @ return the error code */rt_err_t rt_sem_control (rt_sem_t sem, rt_uint8_t cmd, void * arg) {rt_ubase_t level; RT_ASSERT (sem! = RT_NULL); if (cmd = rt_ipc_1__reset) // reset the counter value of the semaphore {rt_uint32_t value;/* get value */value = (rt_uint32_t) arg; /* disable interrupt */level = rt_hw_interrupt_disable (); // Guanzhong disconnection/* resume all waiting thread */www.2cto.com rt_ipc_list_resume_all (& sem-> parent. suspend_thread); // wake up all suspended threads on the semaphore/* set new value */sem-> value = (rt_uint16_t) value; // set the counter value for the signal/* enable interrupt */rt_hw_interrupt_enable (level); // enable or disable rt_schedule (); // debug return RT_EOK immediately ;} return-RT_ERROR ;}