最近在專案中使用了chan_ss7進行中國7號信令的接入,由於在接入過程中,遇到一些問題,需要對源**進行分析,以解決遇到的問題。下面先對chan_ss7進行邏輯分析。
與osi7層模型類似,在ss7中,也是按照層次來進行組織的,從底到上依次是mtp1,mtp2,mtp3,isup/tup/sccp。mtp層主要保證使用者層資料(tup/isup)的可靠端到端傳輸。在chan_ss7中對isup進行了較好的支援,對於tup目前還沒有支援,國內的開源通訊(openvox)對這部分進行了擴充套件,增加了支援。這裡是以isup為例來說明。
chan_ss7編譯後,是以乙個channel模組載入到asterisk中的。在chan_ss7中採用了asterisk較為常見的do_monitor執行緒對收到的訊息進行處理。另外,還有乙個mtp執行緒來負責接收mtp訊息。為了避免死鎖問題,這兩個執行緒之間使用了乙個receivedbuf進行中轉。
mtp執行緒接收到來自mtp層的資料後,將訊息封裝成evet,然後通過mtp_put函式,將event送入到receivedbuf中,然後再通過alert pipe方式通知do_monitor執行緒有新訊息到來需要處理。
在do_monitor執行緒中,從receivedbuf中逐個取出訊息,然後按照訊息的型別不同,分別進行處理。
訊息的處理過程,以isup訊息為例,
對於isup訊息,首先會通過chan_ss7.c中的process_event函式,根據訊息型別,轉到l4isup_event中。在l4isup_event中,首先對event進行解碼,解析出isup訊息,然後根據isup訊息中的cic查詢到對應的pvt結構,然後到process_isup_message根據訊息的型別的不同,呼叫對應的handler進行處理。
在process_isup_message中,根據msg的typ取值不同,向process_circuit_message傳入不同的函式指標,以完成handler的抽象,進行呼叫。
在process_circuit_message中,呼叫具體的handler之前,要完成幾個鎖的訪問問題,乙個是global鎖,乙個是pvt的鎖,乙個是channel的鎖。這三個鎖的訪問順序,是需要仔細注意的,加鎖的順序必須是global->channel->pvt。加鎖完成後,是對應的handler的呼叫。處理結束後,釋放鎖,處理結束。
我的問題:在處理高併發、長呼叫的時候,有些呼入的長呼叫沒有正常掛機。如果被叫不主動掛機,主叫會一直在。並且,此時,所有的呼入/呼出信令全部被阻塞,整個isup層不會再接續處理。
分析:通過上面的執行過程分析來看,訊息的處理過程是在do_monitor執行緒中進行的。如果在處理某個訊息的時候,出現死鎖問題,該執行緒將不會返回,直到死鎖條件解除。特別是在process_circuit_message函式中,需要對三個鎖進行分別處理,極容易引入鎖死。
跟蹤:在實際測試中,對process_circuit_message進行了跟蹤,發現死鎖問題是在ast_channel_lock的時候引起的,此時,通過check_blocking這個巨集判斷看,原來是在ast_write。通道執行緒在往執行緒中寫資料的時候。
進一步分析:作為asterisk中較為核心的channel.c,我堅信不會存在死鎖的問題。既然問題是在ast_write函式中,那麼產生的根源應該是在ss7_write函式中。在這個函式中,直接呼叫了write函式,對話路那個通道直接寫入語音資料。經過做log測試,看出,發生死鎖的時候,是從write函式中沒有返回。此處的write函式是同步的寫,必須等待寫結束後,才進行返回。問題的根源應該是在這裡。
解決方法:既然問題已經找到了,那麼該如何解決?
1.為了避免整個isup層被堵塞,應該避免死鎖的發生。起初的判斷是將處理過程process_circuit_message放到乙個獨立的執行緒中去執行。由於這裡有個global鎖,多執行緒實際上被序列執行了,沒有多少意義。在process_circuit_message進行channel鎖的時候,使用trylock,多檢測幾次,如果仍然沒有鎖住channel,則對本次訊息,不予處理。等待下次重傳的訊息。
2.即便是處理重傳,但是在實際中會一直出現鎖在ast_write中。除非被叫端掛機,否則該通道一直會被占用。為了避免這種情況的發生,在1基礎之上,對於拆線等事件,如果發現trylock失敗,轉而讓bridged通道去掛機。對於這種方案,目前還沒有進行測試。
7Z原始碼分析 7z h
define k7zstartheadersize 0x20 define k7zsignaturesize 6 extern const byte k7zsignature k7zsignaturesize 檔案的開頭處定義了2個巨集,k7zstartheadersize 是7z檔案頭的大小 詳情...
spring原始碼分析 spring原始碼分析
1.spring 執行原理 spring 啟動時讀取應用程式提供的 bean 配置資訊,並在 spring 容器中生成乙份相應的 bean 配置登錄檔,然後根據這張登錄檔例項化 bean,裝配好 bean 之間的依賴關係,為上 層應用提供準備就緒的執行環境。二 spring 原始碼分析 1.1spr...
Leveldb原始碼分析7 資料查詢
leveldb只是單純的在檔案末尾增加,並不改寫原有的內容,那麼如果刪除乙個key,或者更新乙個key應該怎麼辦呢?比如 table liming 18del table liming table liming 20table liming 21 leveldb將每乙個操作變化成如下的格式 user...