SQLite3源碼學習(14) 模擬靜態變量
/*
** When SQLITE_OMIT_WSD is defined, it means that the target platform does
** not support Writable Static Data (WSD) such as global and static variables.
** All variables must either be on the stack or dynamically allocated from
** the heap. When WSD is unsupported, the variable declarations scattered
** throughout the SQLite code must become constants instead. The SQLITE_WSD
** macro is used for this purpose. And instead of referencing the variable
** directly, we use its constant as a key to lookup the run-time allocated
** buffer that holds real variable. The constant is also the initializer
** for the run-time allocated buffer.
**
** In the usual case where WSD is supported, the SQLITE_WSD and GLOBAL
** macros become no-ops and have zero performance impact.
*/
如果目標平臺不支持靜態變量和全局變量,所有變量都需要從棧或堆里分配,這時候全局變量的聲明都是const,sqlite以變量的地址作為關鍵字來映射堆中的一片地址空間,從而對這個地址的讀寫來代替對靜態變量的讀寫。
使用時需要打開SQLITE_OMIT_WSD宏定義,以全局變量sqlite3Config為例,首先把sqlite3Config定義成const變量,再傳入變量的地址和變量的長度,返回堆中映射的地址。
#ifdef SQLITE_OMIT_WSD
#define SQLITE_WSD const
#define GLOBAL(t,v) (*(t*)sqlite3_wsd_find((void*)&(v), sizeof(v)))//傳入地址和長度
#define sqlite3GlobalConfig GLOBAL(struct Sqlite3Config, sqlite3Config)
int sqlite3_wsd_init(int N, int J);
void *sqlite3_wsd_find(void *K, int L);
#else
#define SQLITE_WSD
#define GLOBAL(t,v) v
#define sqlite3GlobalConfig sqlite3Config
#endif
SQLITE_WSD struct Sqlite3Config sqlite3Config//定義const變量
實現時,首先要有一個pGlobal來管理堆中申請的空間,pGlobal的類型是ProcessLocalStorage,結構定義如下:
#define PLS_HASHSIZE 43
typedef struct ProcessLocalStorage ProcessLocalStorage;
typedef struct ProcessLocalVar ProcessLocalVar;
struct ProcessLocalStorage {
ProcessLocalVar *aData[PLS_HASHSIZE];
int nFree;
u8 *pFree;
};
struct ProcessLocalVar {
void *pKey;
ProcessLocalVar *pNext;
};
static ProcessLocalStorage *pGlobal = 0;
其中pGlobal-> aData映射傳進來的靜態變量的實際地址。
初始化時首先申請總的空間N + sizeof(ProcessLocalStorage) + J*sizeof(ProcessLocalVar);其中N是變量的總空間,J是變量的個數
int sqlite3_wsd_init(int N, int J){
if( !pGlobal ){
int nMalloc = N + sizeof(ProcessLocalStorage) + J*sizeof(ProcessLocalVar);
pGlobal = (ProcessLocalStorage *)malloc(nMalloc);
if( pGlobal ){
memset(pGlobal, 0, sizeof(ProcessLocalStorage));
pGlobal->nFree = nMalloc - sizeof(ProcessLocalStorage);
pGlobal->pFree = (u8 *)&pGlobal[1];
}
}
return pGlobal ? SQLITE_OK : SQLITE_NOMEM;
}
其中pGlobal->pFree是未使用的空間,已經使用的空間作為靜態變量的映射存在hash表里,相同hash值的變量通過鏈表連接在一起。
使用時只要調用函數void *sqlite3_wsd_find(void *K, int L)就可以了,其中K是變量的原始地址,L是變量所占的空間長度。
void *sqlite3_wsd_find(void *K, int L){
int i;
int iHash = 0;
ProcessLocalVar *pVar;
/* Calculate a hash of K */
/*把變量的地址K通過一定的算法得到hash值 iHash */
for(i=0; i<sizeof(void*); i++){
iHash = (iHash<<3) + ((unsigned char *)&K)[i];
}
iHash = iHash%PLS_HASHSIZE;
/* Search the hash table for K. */
/*在iHash的hash元素鏈表里查找關鍵字是K的元素*/
for(pVar=pGlobal->aData[iHash]; pVar && pVar->pKey!=K; pVar=pVar->pNext);
/* If no entry for K was found, create and populate a new one. */
if( !pVar ){
int nByte = ROUND8(sizeof(ProcessLocalVar) + L);//申請的空間總長度
assert( pGlobal->nFree>=nByte );
pVar = (ProcessLocalVar *)pGlobal->pFree;//在pFree里獲取
pVar->pKey = K;
pVar->pNext = pGlobal->aData[iHash];//插入到hash值是iHash的鏈表中
pGlobal->aData[iHash] = pVar;//更新頭結點
pGlobal->nFree -= nByte;
pGlobal->pFree += nByte;//未使用的空間地址向后移動
memcpy(&pVar[1], K, L);//得到初始值
}
return (void *)&pVar[1];// 去除頭部ProcessLocalVar,返回映射地址
}
最后有一個疑問:既然沒有靜態存儲區,那么pGlobal存在哪里?
智能推薦
python類靜態變量
轉自:https://www.cnblogs.com/Alexzzzz/p/10795227.html 作者:Alexzzzz python的類靜態變量直接定義在類中即可,不需要修飾符,如: 在類Test中,stc_attr是屬于類Test的靜態變量,attr1和attr2是屬于對象的變量。并且通過類名和對象實例訪問stc_attr都是合法的。 可以看到類Test,對象obj1和對象obj2中st...
kotlin 定義靜態變量
Kotlin 取消了關鍵字static,也就無法直接聲明靜態成員, 在kotlin中定義靜態變量需要使用伴生類 companion 先看看下java 的定義 如果直接復制粘貼過去如下 但是這些卻不是靜態變量 我們如下寫法即可 為什么要添加注解 官方的語言:在 JVM 平臺,如果使用 @JvmStatic...
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
猜你喜歡
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...
統計學習方法 - 樸素貝葉斯
引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...