Go標準庫plugin原始碼分析 動態庫使用

2021-08-18 20:35:03 字數 2478 閱讀 6249

go通常都是編譯打包成乙個可執行檔案,好處是不需要考慮依賴庫,乙個可執行檔案,拷貝就可以直接執行。

但還有些場景,如需要以外掛程式形式載入,方便動態更新,熱重啟等情況。這些場景的需求,就帶來了plugin庫,動態庫載入。

那麼先看看plguin這個庫的文件。文件為1.10版本

編譯命令和普通的編譯不一樣,增加了引數-buildmode=plugin

另外plugin第一次載入時候,init函式會呼叫。(後面的原始碼分析中會分析)

注意:1、plugin只init一次,並且不能closed。

2、目前只實現了linux平台和macos平台

檔案很少,就只有兩個(其實原始碼裡有三個檔案)

只提供了兩個介面

open:載入so庫檔案

lookup:查詢對應符號(包括func,var等)

文件中的示例

其中值得注意的是package是main

兩個介面的使用,open載入庫檔案,lookup查詢符號

示例中,有乙個var,有乙個func

那麼再看下例子

這個裡面多了乙個init

使用

好了,下面看原始碼

原始碼目錄

pluginpath:庫的path

err:用於記錄過程中的err

loaded:這個用於防止併發載入同乙個庫時候用

syms:這個記錄的是庫中所有的符號和其對應的值(可能是var、func等)

open函式,封裝了open函式

lookup函式封裝了lookup函式

src/plugin/plugin_stubs.go

這裡是針對不支援平台的空實現,!linux,!darwin !cgo。可以看出,和文件中說的一樣,非linux,非darwin平台的時候編譯成空實現。當然還有乙個cgo,如果不支援cgo的話,也是無法實現plugin的。

那麼看最後乙個檔案

src/plugin/plugin_dlopen.go

編譯命令中,顯示支援linux 和 darwin平台,當然要求是要支援cgo。

然後就是乙個cgo的**。其中封裝了兩個函式dlopen,dlsym。

其實看到這兩個函式,就應該很熟悉了。

這個是linux種標準的動態鏈結載入介面。

當然plugin只實現了封裝了dlopen,dlsym,兩個函式。這個和文件中所提供的介面和描述是符合的。

只提供了載入,並沒有提供關閉。

繼續看原始碼

全域性變數

pluginsmu:全域性鎖

plugins:儲存載入的動態庫

open

進入函式,一開始是一些字串的轉換。

重點是加鎖後,會判斷是否已經在載入,或者已經載入過的plugin。

這個時候,如果剛好plugin還在載入中,

這種方式就是合併載入

這裡就是呼叫了cgo**pluginopen,載入so庫

初始化plugin結構體,並將其放入到全域性的plugins這個map中。然後unlock全域性鎖。

繼續,呼叫了cgo**pluginlookup,查詢init函式,並執行。

接著就是迴圈讀取所有的符號,並將符號與其對應的值儲存下來。儲存在p.syms中。

最後close p.loaded,表示載入過程結束了。

lookup

所有的符號都儲存在p.syms中,這個時候的查詢,就只需要直接查詢syms就可以了。

龔浩華月牙寂道長

qq 29185807

2023年04月16日

Go 標準庫 context 原始碼解析

context 主要用來在goroutine 之間傳遞上下文資訊,包括取消訊號 超時時間 截止時間 k v等。標準庫的許多介面加上了 context 引數,來實現併發控制和超時控制。type context inte ce err error value key inte ce inte ce 該介...

Go 原始碼學習 log 庫

log 包實現了乙個簡單的日誌功能。logger 結構體作為日誌物件,生成文字行到 io.writer。每次記錄日誌的操作都生成一行日誌,即便是log.printf也不用包含 n。結構體中有sync.metex鎖,保證了在多 goroutine 情況時的順序寫入。type logger struct...

Go 筆記三 庫原始碼檔案

庫原始碼檔案不能被直接執行,它僅用於存放程式實體。只要遵從 go 語言規範,這些程式實體就可以被其他 使用。在 go 語言中,它是變數 常量 函式 結構體和介面的統稱。第一條規則,同目錄下的原始碼檔案的 包宣告語句要一致。也就是說,它們要同屬於乙個 包。這對於所有原始碼檔案都是適用的。第二條規則,原...