/*
** 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; iaData[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存在哪里?