1. 程式人生 > 其它 >程序排程-【轉載】schedule_timeout和schedule_timeout_interruptible讓出CPU

程序排程-【轉載】schedule_timeout和schedule_timeout_interruptible讓出CPU

 

作者:TASK_RUNNING
連結:https://www.jianshu.com/p/60e7238876a2

 

我們在驅動程式設計時,如果程式內使用了死迴圈,則一般會使CPU的佔用率達到100%,某些情況下,我們希望降低CPU使用率,那應該怎麼辦呢?

1. schedule_timeout

schedule_timeout,做了兩件事:

  1. 設定timer
  2. schedule

此呼叫並沒有改變程序的狀態TASK_RUNNING,所以在__schedule()中,不會把程序從執行佇列中移出去。當系統進行排程的時候,這個程序仍然會被排程進來。

2. schedule_timeout_interruptible

schedule_timeout_interruptible, 在呼叫schedule之前,會先呼叫set_current_state設定程序狀態,所以會將程序移出執行佇列。從而達到降低CPU使用率的作用。
類似的還有:
schedule_timeout_uninterruptible,  schedule_timeout_killable


原始碼分析
kernel/time/timer.c
1801/**
1802 * schedule_timeout - sleep until timeout
1803 * @timeout: timeout value in jiffies
1804 *
1805 * Make the current task sleep until @timeout jiffies have elapsed.
1806 * The function behavior depends on the current task state
1807 * (see also set_current_state() description): 1808 * 1809 * %TASK_RUNNING - the scheduler is called, but the task does not sleep 1810 * at all. That happens because sched_submit_work() does nothing for 1811 * tasks in %TASK_RUNNING state. 1812 * 1813 * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to 1814 * pass
before the routine returns unless the current task is explicitly 1815 * woken up, (e.g. by wake_up_process()). 1816 * 1817 * %TASK_INTERRUPTIBLE - the routine may return early if a signal is 1818 * delivered to the current task or the current task is explicitly woken 1819 * up. 1820 * 1821 * The current task state is guaranteed to be %TASK_RUNNING when this 1822 * routine returns. 1823 * 1824 * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule 1825 * the CPU away without a bound on the timeout. In this case the return 1826 * value will be %MAX_SCHEDULE_TIMEOUT. 1827 * 1828 * Returns 0 when the timer has expired otherwise the remaining time in 1829 * jiffies will be returned. In all cases the return value is guaranteed 1830 * to be non-negative. 1831
*/ 1832signed long __sched schedule_timeout(signed long timeout) 1833{ 1834 struct process_timer timer; 1835 unsigned long expire; 1836 1837 switch (timeout) 1838 { 1839 case MAX_SCHEDULE_TIMEOUT: 1840 /* 1841 * These two special cases are useful to be comfortable 1842 * in the caller. Nothing more. We could take 1843 * MAX_SCHEDULE_TIMEOUT from one of the negative value 1844 * but I' d like to return a valid offset (>=0) to allow 1845 * the caller to do everything it want with the retval. 1846 */ 1847 schedule(); 1848 goto out; 1849 default: 1850 /* 1851 * Another bit of PARANOID. Note that the retval will be 1852 * 0 since no piece of kernel is supposed to do a check 1853 * for a negative retval of schedule_timeout() (since it 1854 * should never happens anyway). You just have the printk() 1855 * that will tell you if something is gone wrong and where. 1856 */ 1857 if (timeout < 0) { 1858 printk(KERN_ERR "schedule_timeout: wrong timeout " 1859 "value %lx\n", timeout); 1860 dump_stack(); 1861 current->state = TASK_RUNNING; 1862 goto out; 1863 } 1864 } 1865 1866 expire = timeout + jiffies; 1867 1868 timer.task = current; 1869 timer_setup_on_stack(&timer.timer, process_timeout, 0); 1870 __mod_timer(&timer.timer, expire, MOD_TIMER_NOTPENDING); 1871 schedule(); 1872 del_singleshot_timer_sync(&timer.timer); 1873 1874 /* Remove the timer from the object tracker */ 1875 destroy_timer_on_stack(&timer.timer); 1876 1877 timeout = expire - jiffies; 1878 1879 out: 1880 return timeout < 0 ? 0 : timeout; 1881} 1882EXPORT_SYMBOL(schedule_timeout); 1883 1884/* 1885 * We can use __set_current_state() here because schedule_timeout() calls 1886 * schedule() unconditionally. 1887 */ 1888signed long __sched schedule_timeout_interruptible(signed long timeout) 1889{ 1890 __set_current_state(TASK_INTERRUPTIBLE); 1891 return schedule_timeout(timeout); 1892} 1893EXPORT_SYMBOL(schedule_timeout_interruptible); 1894 1895signed long __sched schedule_timeout_killable(signed long timeout) 1896{ 1897 __set_current_state(TASK_KILLABLE); 1898 return schedule_timeout(timeout); 1899} 1900EXPORT_SYMBOL(schedule_timeout_killable); 1901 1902signed long __sched schedule_timeout_uninterruptible(signed long timeout) 1903{ 1904 __set_current_state(TASK_UNINTERRUPTIBLE); 1905 return schedule_timeout(timeout); 1906} 1907EXPORT_SYMBOL(schedule_timeout_uninterruptible);

1834 定義一個 process_timer 物件

1868 ~ 1870 填充 timer 物件,然後將這個 timer  使用   __mod_timer 函式,加入 到系統中。

1071 呼叫 schedule 函式進行排程

 

1888 ~ 1907  schedule_timeout_interruptable /  schedule_timeout_uninterruptable  / schedule_timeout_killable   的實現,先設定狀態,再呼叫  schedule_timeout 。