SQLite3源码学习(14) 模拟静态变量

本文介绍了当目标平台不支持静态变量和全局变量时,SQLite如何通过Writable Static Data (WSD)机制来替代这些变量的使用。通过将全局变量定义为const,并使用特定宏和函数,SQLite能够在运行时动态分配内存来模拟静态变量的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
** 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值的变量通过链表连接在一起。

clip_image002[4]

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值