久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

對(duì)Linux系統(tǒng)休眠的理解

 panhoy 2014-07-06

     今天看了一個(gè)關(guān)于中斷例程為什么不能休眠的文章,,引發(fā)了我的思考。其實(shí)這個(gè)問(wèn)題在學(xué)習(xí)驅(qū)動(dòng)的時(shí)候早就應(yīng)該解決了,,但是由于5年前學(xué)驅(qū)動(dòng)的時(shí)候?qū)儆?/span>Linux初學(xué)者,,能力有限,,所以對(duì)這個(gè)問(wèn)題就知其然,,沒(méi)有能力知其所以然?,F(xiàn)在回頭看這個(gè)問(wèn)題的時(shí)候,感覺(jué)應(yīng)該可以有一個(gè)較為清晰的認(rèn)識(shí)了,。

首先必須意識(shí)到:休眠是一種進(jìn)程的特殊狀態(tài)(即task->state= TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)]


  • 一,、休眠的目的

    簡(jiǎn)單的說(shuō),休眠是為在一個(gè)當(dāng)前進(jìn)程等待暫時(shí)無(wú)法獲得的資源或者一個(gè)event的到來(lái)時(shí)(原因),,避免當(dāng)前進(jìn)程浪費(fèi)CPU時(shí)間(目的),,將自己放入進(jìn)程等待隊(duì)列中,,同時(shí)讓出CPU給別的進(jìn)程(工作),。休眠就是為了更好地利用CPU

     一旦資源可用或event到來(lái),,將由內(nèi)核代碼(可能是其他進(jìn)程通過(guò)系統(tǒng)調(diào)用)喚醒某個(gè)等待隊(duì)列上的部分或全部進(jìn)程,。從這點(diǎn)來(lái)說(shuō),休眠也是一種進(jìn)程間的同步機(jī)制,。

 

  • 二,、休眠的對(duì)象

     休眠是針對(duì)進(jìn)程,,也就是擁有task_struct的獨(dú)立個(gè)體。

     當(dāng)進(jìn)程執(zhí)行某個(gè)系統(tǒng)調(diào)用的時(shí)候,,暫時(shí)無(wú)法獲得的某種資源或必須等待某event的到來(lái),,在這個(gè)系統(tǒng)調(diào)用的底層實(shí)現(xiàn)代碼就可以通過(guò)讓系統(tǒng)調(diào)度的手段讓出CPU,讓當(dāng)前進(jìn)程處于休眠狀態(tài),。


  • 進(jìn)程什么時(shí)候會(huì)被休眠,?

    進(jìn)程進(jìn)入休眠狀態(tài),必然是他自己的代碼中調(diào)用了某個(gè)系統(tǒng)調(diào)用,,而這個(gè)系統(tǒng)調(diào)用中存在休眠代碼,。這個(gè)休眠代碼在某種條件下會(huì)被激活,從而讓改變進(jìn)程狀態(tài),,說(shuō)到底就是以各種方式包含了:

1,、條件判斷語(yǔ)句

2、進(jìn)程狀態(tài)改變語(yǔ)句

3,、schedule();


  • 三,、休眠操作做了什么

    進(jìn)程被置為休眠,意味著它被標(biāo)識(shí)為處于一個(gè)特殊的狀態(tài)(TASK_UNINTERRUPTIBLE TASK_INTERRUPTIBLE),,并且從調(diào)度器的運(yùn)行隊(duì)列中移走,。這個(gè)進(jìn)程將不在任何 CPU 調(diào)度,即不會(huì)被運(yùn)行,。 直到發(fā)生某些事情改變了那個(gè)狀態(tài)(to TASK_WAKING),。這時(shí)處理器重新開(kāi)始執(zhí)行此進(jìn)程,此時(shí)進(jìn)程會(huì)再次檢查是否需要繼續(xù)休眠(資源是否真的可用,?),,如果不需要就做清理工作,并將自己的狀態(tài)調(diào)整為TASK_RUNNING,。過(guò)程如下圖所示:


  • 四,、誰(shuí)來(lái)喚醒休眠進(jìn)程

     進(jìn)程在休眠后,就不再被調(diào)度器執(zhí)行,,就不可能由自己?jiǎn)拘炎约?,也就是說(shuō)進(jìn)程不可能睡覺(jué)睡到自然醒。喚醒工作必然是由其他進(jìn)程或者內(nèi)核本身來(lái)完成的,。喚醒需要改變進(jìn)程的task_struct中的狀態(tài)等,,代碼必然在內(nèi)核中,所以喚醒必然是在系統(tǒng)調(diào)用的實(shí)現(xiàn)代碼中(如你驅(qū)動(dòng)中的read,、write方法)以及各種形式的中斷代碼(包括軟,、硬中斷)中。

     如果在系統(tǒng)調(diào)用代碼中喚醒,則說(shuō)明是由其他的某個(gè)進(jìn)程來(lái)調(diào)用了這個(gè)系統(tǒng)調(diào)用喚醒了休眠的進(jìn)程,。

      如果是中斷中喚醒,,那么喚醒的任務(wù)可以說(shuō)是內(nèi)核完成了。

 

· 如何找到需要喚醒的進(jìn)程:等待隊(duì)列

    上面其實(shí)已經(jīng)提到了:休眠代碼的一個(gè)工作就是將當(dāng)前進(jìn)程信息放入一個(gè)等待隊(duì)列中,。它其實(shí)是一個(gè)包含等待某個(gè)特定事件的所有進(jìn)程相關(guān)信息的鏈表,。一個(gè)等待隊(duì)列由一個(gè)wait_queue_head_t 結(jié)構(gòu)體來(lái)管理,其定義在<linux/wait.h>中,。

wait_queue_head_t 類(lèi)型的數(shù)據(jù)結(jié)構(gòu)如下: 


  1. struct __wait_queue_head {
  2.     spinlock_t lock;
  3.     struct list_head task_list;
  4. };
  5. typedef struct __wait_queue_head wait_queue_head_t;

    它包含一個(gè)自旋鎖和一個(gè)鏈表,。這是一個(gè)等待隊(duì)列鏈表頭,鏈表中的元素被聲明做wait_queue_t,。自旋鎖用于包含鏈表操作的原子性,。 

wait_queue_t包含關(guān)于睡眠進(jìn)程的信息和喚醒函數(shù)


  1. typedef struct __wait_queue wait_queue_t;
  2. typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key);
  3. int default_wake_function(wait_queue_t *wait, unsigned mode, int flags, void *key); 

  4. struct __wait_queue {
  5. unsigned int flags;
  6. #define WQ_FLAG_EXCLUSIVE 0x01  /* 表示等待進(jìn)程想要被獨(dú)占地喚醒 */ 
  7. void *private;  /* 指向等待進(jìn)程的task_struct結(jié)構(gòu)圖 */ 
  8. wait_queue_func_t func;  /* 用于喚醒等待進(jìn)程的處理例程,,在其中實(shí)現(xiàn)了進(jìn)程狀態(tài)的改變和將自己從等待隊(duì)列中刪除的工作 */
  9. struct list_head task_list;  /* 雙向鏈表結(jié)構(gòu)體,,用于將wait_queue_t鏈接到wait_queue_head_t */ 
  10. };

他們?cè)趦?nèi)存中的結(jié)構(gòu)大致如下圖所示:

 

 

等待隊(duì)列頭wait_queue_head_t一般是定義在模塊或內(nèi)核代碼中的全局變量,而其中鏈接的元素 wait_queue_t的定義被包含在了休眠宏中,。

休眠和喚醒的過(guò)程如下圖所示:

五,、休眠和喚醒的代碼簡(jiǎn)要分析

下面我們簡(jiǎn)單分析一下休眠與喚醒的內(nèi)核原語(yǔ)。

1,、休眠:wait_event 

  1. /**
  2. * wait_event - 休眠,,直到 condition 為真
  3. * @wq: 所休眠的等待隊(duì)列
  4. * @condition: 所等待事件的一個(gè)C表達(dá)式
  5. *
  6. * 進(jìn)程被置為等待狀態(tài) (TASK_UNINTERRUPTIBLE) 直到
  7. * @condition 評(píng)估為真. @condition 在每次等待隊(duì)列@wq 被喚醒時(shí)
  8. * 都被檢查。
  9. *
  10. * wake_up() 必須在改變?nèi)魏慰赡苡绊懙却龡l件結(jié)果
  11. * 的變量之后被調(diào)用,。
  12. */
  13. #define wait_event(wq, condition) \
  14. do { \
  15. if (condition) \
  16. break; \
    1. 先測(cè)試條件,,看看是否真的需要休眠
  17. __wait_event(wq, condition)\
  18. } while (0)
  19.  
  20. #define __wait_event(wq, condition) \
  21. do { \
  22. DEFINE_WAIT(__wait); \

    1. 定義一個(gè)插入到等待隊(duì)列中的等待隊(duì)列結(jié)構(gòu)體,注意.private = current,(即當(dāng)前進(jìn)程)
    2. #define DEFINE_WAIT_FUNC(name, function) \
    3. wait_queue_t name = { \
    4. .private = current, \
    5. .func = function, \
    6. .task_list = LIST_HEAD_INIT((name).task_list), \
    7. }
    8. #define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)
  23. \
  24. for (;;) { \
  25. prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); \

    1. 將上面定義的結(jié)構(gòu)體__wait放入wq等待隊(duì)列中,,并設(shè)置當(dāng)前進(jìn)程狀態(tài)為T(mén)ASK_UNINTERRUPTIBLE
  26. if (condition) \
  27. break; \
    1. 測(cè)試條件狀態(tài),,看看是否真的需要休眠調(diào)度
  28. schedule(); \
    1. 開(kāi)始調(diào)度,程序停于此處,,直到有其他進(jìn)程喚醒本進(jìn)程,,就從此處繼續(xù)......
  29. } \
  30. finish_wait(&wq, &__wait); \

    1. 由于測(cè)試條件狀態(tài)為假,跳出以上循環(huán)后執(zhí)行休眠后的掃尾工作:
    2. 設(shè)置當(dāng)前進(jìn)程狀態(tài)為T(mén)ASK_RUNNING
    3. 將上面定義的__wait從等待隊(duì)列鏈表中刪除,。
    }
     while (0)

2,、喚醒:wake_up


  1. #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)


  1. /**
  2. * __wake_up - 喚醒阻塞在等待隊(duì)列上的線程.
  3. * @q: 等待隊(duì)列
  4. * @mode: which threads
  5. * @nr_exclusive: how many wake-one or wake-many threads to wake up
  6. * @key: is directly passed to the wakeup function
  7. *
  8. * It may be assumed that this function implies a write memory barrier before
  9. * changing the task state if and only if any tasks are woken up.
  10. */
  11. void __wake_up(wait_queue_head_t *q, unsigned int mode,
  12. int nr_exclusive, void *key)
  13. {
  14. unsigned long flags;
  15. spin_lock_irqsave(&q->lock, flags);
  16. __wake_up_common(q, mode, nr_exclusive, 0, key);
  17. spin_unlock_irqrestore(&q->lock, flags);
  18. }
  19. EXPORT_SYMBOL(__wake_up);

kernel/sched.c

  1. /*
  2. * 核心喚醒函數(shù).非獨(dú)占喚醒(nr_exclusive == 0) 只是
  3. * 喚醒所有進(jìn)程. If it's an exclusive wakeup (nr_exclusive == small +ve
  4. * number) then we wake all the non-exclusive tasks and one exclusive task.
  5. *
  6. * There are circumstances in which we can try to wake a task which has already
  7. * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns
  8. * zero in this (rare) case, and we handle it by continuing to scan the queue.
  9. */
  10. static void __wake_up_common(wait_queue_head_t *q, unsigned int mode,
  11. int nr_exclusive, int wake_flags, void *key)
  12. {
  13. wait_queue_t *curr, *next;
  14. list_for_each_entry_safe(curr, next, &q->task_list, task_list) {

    1. 遍歷指定等待隊(duì)列中的wait_queue_t.
  15. unsigned flags = curr->flags;
  16. if (curr->func(curr, mode, wake_flags, key) &&
  17. (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive)
  18. break;

    1. 調(diào)用喚醒函數(shù),也就是創(chuàng)建wait_queue_t時(shí)的 autoremove_wake_function
    }
  19. }


  1. int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
  2. {
  3. int ret = default_wake_function(wait, mode, sync, key);

  4. if (ret)
  5. list_del_init(&wait->task_list);

    1. 從等待隊(duì)列中刪除這個(gè)進(jìn)程
    return ret;
  6. }
  7. EXPORT_SYMBOL(autoremove_wake_function);
  8.  
  9. int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,
  10. void *key)
  11. {
  12. return try_to_wake_up(curr->private, mode, wake_flags);

    1. 主要是要改變進(jìn)程狀態(tài)為 TASK_WAKING,,讓調(diào)度器可以重新執(zhí)行此進(jìn)程,。
    }
  13. EXPORT_SYMBOL(default_wake_function);
    上面分析的休眠函數(shù)是最簡(jiǎn)單的休眠喚醒函數(shù),其他類(lèi)似的函數(shù),,如后綴為_timeout,、_interruptible,、_interruptible_timeout的函數(shù)其實(shí)都是在喚醒后的條件判斷上有些不同,,多判斷一些喚醒條件而已,。這里就不再贅述了。


六,、使用休眠的注意事項(xiàng)

1 永遠(yuǎn)不要在原子上下文中進(jìn)入休眠,,即當(dāng)驅(qū)動(dòng)在持有一個(gè)自旋鎖、seqlock或者 RCU 鎖時(shí)不能睡眠,;關(guān)閉中斷也不能睡眠,,終端例程中也不可休眠。

      持有一個(gè)信號(hào)量時(shí)休眠是合法的,,如果代碼在持有一個(gè)信號(hào)量時(shí)睡眠,,任何其他的等待這個(gè)信號(hào)量的線程也會(huì)休眠。發(fā)生在持有信號(hào)量時(shí)的休眠必須短暫,,而且決不能阻塞那個(gè)將最終喚醒你的進(jìn)程,。

2)當(dāng)進(jìn)程被喚醒,它并不知道休眠了多長(zhǎng)時(shí)間以及休眠時(shí)發(fā)生什么,;也不知道是否另有進(jìn)程也在休眠等待同一事件,,且那個(gè)進(jìn)程可能在它之前醒來(lái)并獲取了所等待的資源。所以不能對(duì)喚醒后的系統(tǒng)狀態(tài)做任何的假設(shè),,并必須重新檢查等待條件來(lái)確保正確的響應(yīng),。


3)除非確信其他進(jìn)程會(huì)在其他地方喚醒休眠的進(jìn)程,否則也不能睡眠,。使進(jìn)程可被找到意味著:需要維護(hù)一個(gè)等待隊(duì)列的數(shù)據(jù)結(jié)構(gòu),。它是一個(gè)進(jìn)程鏈表,其中包含了等待某個(gè)特定事件的所有進(jìn)程的相關(guān)信息,。

 

七,、不可在中斷例程中休眠的原因

     如果在某個(gè)系統(tǒng)調(diào)用中把當(dāng)前進(jìn)程休眠,是有明確目標(biāo)的,,這個(gè)目標(biāo)就是過(guò)來(lái)call這個(gè)系統(tǒng)調(diào)用的進(jìn)程(注意這個(gè)進(jìn)程正在running),。

     但是中斷和進(jìn)程是異步的,在中斷上下文中,,當(dāng)前進(jìn)程大部分時(shí)候和中斷代碼可能一點(diǎn)關(guān)系都沒(méi)有,。要是在這里調(diào)用了休眠代碼,把當(dāng)前進(jìn)程給休眠了,,那就極有可能把無(wú)關(guān)的進(jìn)程休眠了,。再者,如果中斷不斷到來(lái),,會(huì)殃及許多無(wú)辜的進(jìn)程,。

    在中斷中休眠某個(gè)特定進(jìn)程是可以實(shí)現(xiàn)的,通過(guò)內(nèi)核的task_struct鏈表可以找到的,不論是根據(jù)PID還是name,。但是只要這個(gè)進(jìn)程不是當(dāng)前進(jìn)程,,休眠它也可能沒(méi)有必要??赡苓@個(gè)進(jìn)程本來(lái)就在休眠,;或者正在執(zhí)行隊(duì)列中但是還沒(méi)執(zhí)行到,如果執(zhí)行到他了可能又無(wú)須休眠了,。

    還有一個(gè)原因是中斷也是所謂的原子上下文,,有的中斷例程中會(huì)禁止所有中斷,有的中斷例程還會(huì)使用自旋鎖等機(jī)制,,在其中使用休眠也是非常危險(xiǎn)的,。 下面會(huì)介紹。

 

八,、不可在持有自旋鎖,、seqlockRCU 鎖或關(guān)閉中斷時(shí)休眠的原因 

    其實(shí)自旋鎖,、seqlock,、RCU 鎖或關(guān)閉中斷期間的代碼都稱(chēng)為原子上下文,比較有代表性的就是自旋鎖spinlock,。

    對(duì)于UP系統(tǒng),,如果A進(jìn)程在擁有spinlock時(shí)休眠,這個(gè)進(jìn)程在擁有自旋鎖后主動(dòng)放棄了處理器,。其他的進(jìn)程就開(kāi)始使用處理器,,只要有一個(gè)進(jìn)程B去獲取同一個(gè)自旋鎖,B必然無(wú)法獲取,,并做所謂的自旋等待,。由于自旋鎖禁止所有中斷和搶占,B的自旋等待是不會(huì)被打斷的,,并且B也永遠(yuǎn)獲得不了鎖,。因?yàn)?/span>BCPU中運(yùn)行,沒(méi)有其他進(jìn)程可以運(yùn)行并喚醒A并釋放鎖,。系統(tǒng)就此鎖死,,只能復(fù)位了。

    對(duì)于SMP系統(tǒng),,如果A進(jìn)程在擁有spinlock時(shí)休眠,,這個(gè)進(jìn)程在擁有自旋鎖后主動(dòng)放棄了處理器。如果所有處理器都為了獲取這個(gè)鎖而自旋等待,,由于自旋鎖禁止所有中斷和搶占,,,,就不會(huì)有進(jìn)程可能去喚醒A了,系統(tǒng)也就鎖死了,。

    并不是所一旦系統(tǒng)獲得自旋鎖休眠就會(huì)死,,而是有這個(gè)可能。但是注意了計(jì)算機(jī)的運(yùn)行速度之快,,只要有億分之一的可能,也是很容易發(fā)生,。

    所有的原子上下文都有這樣的共性:不可在其中休眠,,否則系統(tǒng)極有可能鎖死。

    如果你對(duì)此還有懷疑,,眼見(jiàn)為實(shí),。我編寫(xiě)了一個(gè)故意鎖死系統(tǒng)的及其簡(jiǎn)單的驅(qū)動(dòng):
   只要對(duì)其設(shè)備節(jié)點(diǎn)做兩次讀寫(xiě)操作,系統(tǒng)必死,。我在X86 SMP系統(tǒng),,ARMv5ARMv6,、ARMv7中都做了如下的實(shí)驗(yàn)(單核(UP)系統(tǒng)必須配置CONFIG_DEBUG_SPINLOCK,,否則自旋鎖是沒(méi)有實(shí)際效果(起碼不會(huì)有“自旋”), 系統(tǒng)可以多次獲取自旋鎖,,沒(méi)有實(shí)驗(yàn)效果,。之后博文中有詳細(xì)描述)。現(xiàn)象都和上面敘述的死法相同,,看了源碼就知道(關(guān)鍵在read\write方法),。以下是實(shí)驗(yàn)記錄:
  1. insmod spin_lock_sleep.ko
  2. spin_lock sleep module loaded!
  3. # cat /proc/devices
  4. Character devices:
  5. 1 mem
  6. 4 /dev/vc/0
  7. 4 tty
  8. 4 ttyS
  9. 5 /dev/tty
  10. 5 /dev/console
  11. 5 /dev/ptmx
  12. 7 vcs
  13. 10 misc
  14. 13 input
  15. 14 sound
  16. 21 sg
  17. 29 fb
  18. 81 video4linux
  19. 89 i2c
  20. 90 mtd
  21. 116 alsa
  22. 128 ptm
  23. 136 pts
  24. 252 spin_lock_sleep
  25. 253 ttyO
  26. 254 rtc
  27. Block devices:
  28. 1 ramdisk
  29. 259 blkext
  30. 7 loop
  31. 8 sd
  32. 11 sr
  33. 31 mtdblock
  34. 65 sd
  35. 66 sd
  36. 67 sd
  37. 68 sd
  38. 69 sd
  39. 70 sd
  40. 71 sd
  41. 128 sd
  42. 129 sd
  43. 130 sd
  44. 131 sd
  45. 132 sd
  46. 133 sd
  47. 134 sd
  48. 135 sd
  49. 179 mmc
  50. # mknod spin_lock_sleep c 252 0
  51. # cat spin_lock_sleep
  52. spin_lock_sleep_read:prepare to get spin_lock! PID:1227
  53. spin_lock_sleep_read:have got the spin_lock! PID:1227
  54. spin_lock_sleep_read:prepare to sleep! PID:1227
  55. spin_lock_sleep_write:prepare to get spin_lock! PID:1229
  56. BUG: spinlock cpu recursion on CPU#0, sh/1229
  57. lock: dd511c3c, .magic: dead4ead, .owner: cat/1227, .owner_cpu: 0
  58. Backtrace:
  59. [<c005e9fc>] (dump_backtrace+0x0/0x118) from [<c04335e4>] (dump_stack+0x20/0x24)
  60. r7:00000002 r6:dd511c3c r5:dd511c3c r4:dd7ef000
  61. [<c04335c4>] (dump_stack+0x0/0x24) from [<c02178d0>] (spin_bug+0x94/0xa8)
  62. [<c021783c>] (spin_bug+0x0/0xa8) from [<c0217a58>] (do_raw_spin_lock+0x6c/0x160)
  63. r5:bf04c408 r4:dd75e000
  64. [<c02179ec>] (do_raw_spin_lock+0x0/0x160) from [<c0435ec4>] (_raw_spin_lock+0x18/0x1c)
  65. [<c0435eac>] (_raw_spin_lock+0x0/0x1c) from [<bf04c1a4>] (spin_lock_sleep_write+0xb4/0x190 [spin_lock_sleep])
  66. [<bf04c0f0>] (spin_lock_sleep_write+0x0/0x190 [spin_lock_sleep]) from [<c011ee90>] (vfs_write+0xb8/0xe0)
  67. r6:dd75ff70 r5:400d7000 r4:dd43bf00
  68. [<c011edd8>] (vfs_write+0x0/0xe0) from [<c011ef8c>] (sys_write+0x4c/0x78)
  69. r7:00000002 r6:dd43bf00 r5:00000000 r4:00000000
  70. [<c011ef40>] (sys_write+0x0/0x78) from [<c005a380>] (ret_fast_syscall+0x0/0x48)
  71. r8:c005a5a8 r7:00000004 r6:403295e8 r5:400d7000 r4:00000002


  1. 此時(shí)在另一個(gè)終端(ssh、telnet等)中執(zhí)行命令:
  2. echo 'l' > spin_lock_sleep


  1. BUG: spinlock lockup on CPU#0, sh/1229, dd511c3c
  2. Backtrace:
  3. [<c005e9fc>] (dump_backtrace+0x0/0x118) from [<c04335e4>] (dump_stack+0x20/0x24)
  4. r7:dd75e000 r6:dd511c3c r5:00000000 r4:00000000
  5. [<c04335c4>] (dump_stack+0x0/0x24) from [<c0217b0c>] (do_raw_spin_lock+0x120/0x160)
  6. [<c02179ec>] (do_raw_spin_lock+0x0/0x160) from [<c0435ec4>] (_raw_spin_lock+0x18/0x1c)
  7. [<c0435eac>] (_raw_spin_lock+0x0/0x1c) from [<bf04c1a4>] (spin_lock_sleep_write+0xb4/0x190 [spin_lock_sleep])
  8. [<bf04c0f0>] (spin_lock_sleep_write+0x0/0x190 [spin_lock_sleep]) from [<c011ee90>] (vfs_write+0xb8/0xe0)
  9. r6:dd75ff70 r5:400d7000 r4:dd43bf00
  10. [<c011edd8>] (vfs_write+0x0/0xe0) from [<c011ef8c>] (sys_write+0x4c/0x78)
  11. r7:00000002 r6:dd43bf00 r5:00000000 r4:00000000
  12. [<c011ef40>] (sys_write+0x0/0x78) from [<c005a380>] (ret_fast_syscall+0x0/0x48)
  13. r8:c005a5a8 r7:00000004 r6:403295e8 r5:400d7000 r4:00000002


而你在這樣原子環(huán)境中休眠調(diào)度,,內(nèi)核一旦檢測(cè)到(主要是檢測(cè)到關(guān)閉了搶占),,你可能會(huì)看到如下信息,警告你:

  1. # cat spin_lock_sleep
  2. spin_lock_sleep_read:prepare to get spin_lock! PID:540
  3. spin_lock_sleep_read:have got the spin_lock! PID:540
  4. spin_lock_sleep_read:prepare to sleep! PID:540
  5. BUG: scheduling while atomic: cat/540/0x00000002
  6. Modules linked in: spin_lock_sleep
  7. [<c0070364>] (unwind_backtrace+0x0/0xe4) from [<c03304a4>] (schedule+0x74/0x36c)
  8. [<c03304a4>] (schedule+0x74/0x36c) from [<bf0062bc>] (spin_lock_sleep_read+0xe8/0x1bc [spin_lock_sleep])
  9. [<bf0062bc>] (spin_lock_sleep_read+0xe8/0x1bc [spin_lock_sleep]) from [<c00dd370>] (vfs_read+0xac/0x154)
  10. [<c00dd370>] (vfs_read+0xac/0x154) from [<c00dd454>] (sys_read+0x3c/0x68)
  11. [<c00dd454>] (sys_read+0x3c/0x68) from [<c006ae60>] (ret_fast_syscall+0x0/0x2c)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶(hù)發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買(mǎi)等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多