Rt-thread IPC Mechanism-semaphore source code analysis

Source: Internet
Author: User

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 ;}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.