Detailed description of Down and up operations in the semaphore mechanism

Source: Internet
Author: User


Down operation: in the Linux kernel, the down operation on semaphores is as follows:

  • Void down (struct semaphore * SEM); // It cannot be interrupted.
  • Int down_interruptible (struct semaphore * SEM); // can be interrupted
  • Int down_killable (struct semaphore * SEM); // sleep processes can be awakened due to a fatal signal and the semaphore acquisition operation is interrupted.
  • Int down_trylock (struct semaphore * SEM); // attempts to obtain the semaphore. If it cannot be obtained, 1 is returned without sleep. If 0 is returned, the semaphore is obtained.
  • Int down_timeout (struct semaphore * SEM, long jiffies); // indicates that the sleep time is limited. If the semaphore still cannot be obtained at the time specified by jiffies, the error code is returned.

Among the above four functions, the most frequently used driver is the down_interruptible function, which will be analyzed below.

The down_interruptible function is defined as follows:

int down_interruptible(struct semaphore *sem){       unsigned long flags;       int result = 0;       spin_lock_irqsave(&sem->lock,flags);       if (likely(sem->count> 0))              sem->count--;       else              result =__down_interruptible(sem);       spin_unlock_irqrestore(&sem->lock,flags);       return result;}

Function Analysis:The function first guarantees the atomicity of the SEM-> count operation by calling the spin_lock_irqsave function. If the count is greater than 0, the current process can obtain the semaphore, and the count value is reduced by 1 and then exited. If the Count value is not greater than 0, it indicates that the current process cannot obtain the semaphore, call _ down_interruptible, and the latter will continue to call _ down_common.

The _ down_common function is defined as follows:

static inline int __sched __down_common(struct semaphore *sem, longstate,                                                        longtimeout){       struct task_struct *task= current;       struct semaphore_waiterwaiter;       list_add_tail(&waiter.list,&sem->wait_list);       waiter.task = task;       waiter.up = 0;        for (;;) {              if(signal_pending_state(state, task))                     gotointerrupted;              if (timeout <=0)                     gototimed_out;              __set_task_state(task,state);              spin_unlock_irq(&sem->lock);              timeout =schedule_timeout(timeout);              spin_lock_irq(&sem->lock);              if (waiter.up)                     return 0;       }  timed_out:       list_del(&waiter.list);       return -ETIME; interrupted:       list_del(&waiter.list);       return -EINTR;}

Function Analysis:The following operations are performed on the number of _ down_common functions.

(1) place the current process in the queue managed by the semaphore member variable wait_list.

(2) In a for loop, the current process status is task_interruptible. When schedule_timeout is called to make the current process sleep, the function will stay on the schedule_timeout call, the task is scheduled again.

(3) when the process is scheduled again, perform the corresponding action based on the reason: if waiter. if the value of up is not 0, the process is awakened by the up operation of the semaphore. The process can obtain the semaphore. If the process is awakened due to the interruption of the user space signal or timeout signal, the corresponding error code is returned.

Up Operation: Only one up function is provided in the Linux kernel.

The up function is defined as follows:

void up(struct semaphore *sem){       unsigned long flags;        spin_lock_irqsave(&sem->lock,flags);       if(likely(list_empty(&sem->wait_list)))              sem->count++;       else              __up(sem);       spin_unlock_irqrestore(&sem->lock,flags);}

Function Analysis:If the wait_list queue of SEM is empty, it indicates that no other process is waiting for the semaphore. You only need to add the Count of SEM to 1. If the wait_list queue is not empty, it indicates that other processes are sleeping on wait_list waiting for this signal. At this time, _ up (SEM) is called to wake up the process:

The _ up () function is defined as follows:

static noinline void __sched __up(struct semaphore *sem){       struct semaphore_waiter*waiter = list_first_entry(&sem->wait_list,                                          structsemaphore_waiter, list);       list_del(&waiter->list);       waiter->up = 1;       wake_up_process(waiter->task);}

Function Analysis:In the function, wake_up_process is called to wake up the process, so that the process will wake up from the timeout = schedule_timeout (timeout) in the previous _ down_interruptible call. Wait-up = 1, _ down_interruptible returns 0, and the process obtains the semaphore.

The relationship between up () and down () functions:From the analysis of the two functions above, we can know that timeout = schedule_timeout (timeout) plays an important role in the __down_common function.

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.