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.
*/

       如果目标平台不支持静态变量和全局变量,所有变量都需要从栈或堆里分配,这时候全局变量的声明都是constsqlite以变量的地址作为关键字来映射堆中的一片地址空间,从而对这个地址的读写来代替对静态变量的读写。

使用时需要打开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值的变量通过链表连接在一起。

SQLite3源码学习(14) 模拟静态变量_第1张图片

使用时只要调用函数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存在哪里?

你可能感兴趣的:(SQLite)