coldfire+linux平台cpu佔用率高跟蹤及解決方案

來源:互聯網
上載者:User
1     現象描述

表面現象是人機程式死機,所有功能不能正常工作。

這個問題已經出現過多次,這次終於花了一周時間把它搞明白了,後面總結了跟蹤過程及分析並給出了3種解決方案。

2     問題跟蹤2.1   跟蹤步驟1——top命令查看線程狀態

狀態如,cpu佔用率hmi-848線程已經達到95%。

2.2   跟蹤步驟2——strace工具載入848線程

輸出資訊如,可以看到系統在不停的調用futex,並且調用出錯(參數無效)。

Process 848 attached - interrupt to quit

SYS_333(0x2, 0x80, 0x2, 0, 0x80)        = 1620625728 <0.000000>

futex(0x8016dc66, FUTEX_WAIT_PRIVATE, 2, NULL) = -1 EINVAL (Invalid argument) <0.000000>

SYS_335(0x2, 0x2, 0x2, 0, 0x80)         = 2 <0.001000>

SYS_333(0x2, 0x80, 0x2, 0, 0x80)        = 1620625728 <0.001000>

futex(0x8016dc66, FUTEX_WAIT_PRIVATE, 2, NULL) = -1 EINVAL (Invalid argument) <0.000000>

SYS_335(0x2, 0x2, 0x2, 0, 0x80)         = 2 <0.000000>

SYS_333(0x2, 0x80, 0x2, 0, 0x80)        = 1620625728 <0.000000>

futex(0x8016dc66, FUTEX_WAIT_PRIVATE, 2, NULL) = -1 EINVAL (Invalid argument) <0.000000>

2.3   跟蹤步驟3——開啟map檔案尋找0x8016dc66地址相關資訊

果然找到了0x8016dc66地址,如。該地址對應著glbsem.c中一個全域變數gs_util_mutex,在glbsem.c找到該變數其定義為“pthread_mutex_t
gs_util_mutex”,為一個線程鎖。

根據上面分析得出結論1:

鎖(或解鎖)時出現了錯誤,並且介面沒有返回一致在調用futex。

根據該結論進行分析,對於線程鎖的操作符合規範沒有問題,進而得出推測1:

導致出錯的原因可能是gs_util_mutex的空間遭到破壞或加鎖(或解鎖)的庫函數實現有錯誤。

2.4   跟蹤步驟4——確認gs_util_mutex空間有沒有被破壞

懷疑別人之前先確認一下自己,還是先看看自己的gs_util_mutex空間有沒有被破壞。開啟map檔案,看看與0x8016dc66相鄰地址是些什麼,可以看,仔細分析周圍這些變數操作會不會破壞gs_util_mutex資料,當我看到gs_currSemFreeFile相關操作時眼前一亮(哈哈!問題終於解決了),代碼。第8行條件不滿足fname得不到初始化之後在第27行將fname中內容複寫到gs_currSemFreeFile,此時複製的是什麼內容長度是多少就是個不確定的了,這就可能會破壞gs_util_mutex資料。再仔細分析除此之外沒發現其它問題。

 

ST_VOID gs_free_semx (SD_CONST ST_CHAR *srcFile, ST_INT srcLineNum)

{

ST_CHAR fname[SLOG_MAX_FNAME+1] ;

ST_INT idx;

 

    if (gs_track)

    {

        if (gs_debug_sel & GS_LOG_FLOW)

        {

            if (srcFile != NULL)

                slogTrimFileName (fname, srcFile);

            else

                strcpy (fname, "Unknown");

        }

 

       idx = gs_currSemOwnerIndex;

       --gs_currSemOwnerIndex;

       if (gs_currSemOwnerIndex == -1)

       {

           GLBSEM_LOG_CFLOW0 ("        The semaphore should now be free");

       }

       else if (gs_currSemOwnerIndex >= 0 && gs_currSemOwnerIndex < MAX_SEM_NEST_TRACK)

       {

           GLBSEM_LOG_CFLOW2 ("        File %s, Line %d now has  the semaphore",

                 gs_currSemOwnerFile[gs_currSemOwnerIndex],

                 gs_currSemOwnerLine[gs_currSemOwnerIndex]);

           strcpy (gs_currSemFreeFile[idx], fname);

           gs_currSemFreeLine[idx] = srcLineNum;

           if (strcmpi (gs_currSemFreeFile[idx], gs_currSemOwnerFile[idx]))

           {

               GLBSEM_LOG_ERR2  ("Possible problem: %s (%d)", gs_currSemOwnerFile[idx],

                                                     gs_currSemOwnerLine[idx]);

            }

      }

      else if (gs_currSemOwnerIndex >= 0 && gs_currSemOwnerIndex >= MAX_SEM_NEST_TRACK)

      {

           GLBSEM_LOG_CFLOW0  ("        Nested too deep to track");

      }

      else if (gs_currSemOwnerIndex < -1)

      {

          GLBSEM_LOG_ERR0 ("GLBSEM gs_free_semx error: Sem track index negative");

          gs_currSemOwnerIndex = -1;

      }

    }

 

    gs_mutex_free (&gs_glb_mutex);      

}

 

2.5   跟蹤步驟5——修改並驗證

上面代碼第3行修改為“ST_CHAR fname[SLOG_MAX_FNAME+1] = {0};”並編譯驗證。令人沮喪的是問題依然存在。

2.6   跟蹤步驟6——編寫簡單代碼驗證線程鎖

按照原程式中線程鎖的使用編寫驗證代碼,結果程式跑了24小時也沒什麼問題,這下可是丈二和尚摸不著頭了。難道真的不是線程鎖的問題?

2.7   跟蹤步驟7——理理思路從頭再來

還是從最初的資訊切入吧,對就從“futex(0x8016dc66, FUTEX_WAIT_PRIVATE, 2, NULL) = -1 EINVAL (Invalid argument)”入手。閱讀了futex的協助文檔、相關的文章以及對應源碼,當根據參數分析futex的時候發現:根據第2個參數futex會調用get_futex_key,而get_futex_key中有如下代碼:

if (unlikely((address % sizeof(u32)) != 0))

              return -EINVAL;

這兩行代碼的意思是address對4求餘不為0就返回EINVAL (Invalid
argument),address又恰恰是futex的第1個參數0x8016dc66(即gs_util_mutex的地址),恰恰0x8016dc66不能被4整除。嗯,這就是問題的所在了!

結論2:線程鎖變數的首地址必須是4的倍數。

2.8   跟蹤步驟8——再次使用步驟6的代碼驗證結論2

開啟步驟6的map檔案發現線程鎖變數的首地址是4的倍數,修改源檔案並編譯確保線程鎖變數的首地址不是4的倍數,運行程式。果然不一會兒就卡死了。

3     原理分析3.1   應用背景

線程屬性設定為PTHREAD_MUTEX_RECURSIVE

3.2   失效機理3.2.1 線程鎖基於futex

futex的使用手冊有如下描述:

(註:參考於http://www.kernel.org/doc/man-pages/online/pages/man2/futex.2.html)

long futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,

           u32 __user *uaddr2, u32 val2, u32 val3)

The uaddr argument needs to point to an aligned integer which stores the

       counter.  The operation to execute is passed via the op argument, along with a

       value val

3.2.2 libc中線程鎖的對齊機制

線程鎖的屬性定義如下,其為一聯合體,成員__align用於保障聲明該類型變數時變數首地址是sizeof(long int)的整數倍。(註:參考於libc2.10.1)

typedef union

{

  struct __pthread_mutex_s

  {

    int __lock;

    unsigned int __count;

    int __owner;

    /* KIND must stay at this position in the structure to maintain

       binary compatibility.  */

    int __kind;

    unsigned int __nusers;

    __extension__ union

    {

      int __spins;

      __pthread_slist_t __list;

    };

  } __data;

  char __size[__SIZEOF_PTHREAD_MUTEX_T];

  long int __align;

} pthread_mutex_t;

M68k預設使用兩位元組對齊,普通gcc編譯器預設使用4位元組對齊,即使用普通gcc編譯器時__align成員保證了線程鎖屬性變數的首地址是4的倍數,而使用m68k編譯時間__align成員就不能保證線程鎖屬性變數的首地址是4的倍數了(實際是2的倍數)。

3.2.3 參數錯誤問什麼會引起cpu佔用率高

假設有兩個線程pthr1和pthr2共用一個鎖,當pthr1已經加鎖還未解鎖時切換至pthr2運行,pthr2此時加鎖則會調用futex,futex繼續調用futex_wait試圖阻塞pthr2,utex_wait在調用get_futex_key時返回了參數無效,而pthread_mutex_lock的實現又沒有恰當處理futex的傳回值,發現lock的值沒有變化就進入到futex調用的死迴圈了,線程而的cpu佔用率一下就高了。

4     解決方案

1、 
從飛思卡爾擷取libc等所有庫的源碼,自己編譯4位元組對齊的庫,這樣應用也能按4位元組對齊進行編譯了。這樣可以解決這個問題,還可以解決訊號量等對齊的問題。(強烈建議按這種方式解決,因為我們不知道和對齊相關的問題還有多少潛藏在我們的應用中)

2、 
我們自己封裝線程鎖變數建立及銷毀介面、使用malloc和free為線程鎖變數分配和釋放空間,可以保證其首地址是按4直接對齊的。

3、 
聲明線程鎖變數使用__attribute((aligned (4))),以保證其首地址按4位元組對齊。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.