2021SC@SDUSC
接着上次的winVfsAppData结构体继续往下看。
#ifdef SQLITE_WIN32_MALLOC
malloc()是Sqlite在缺省情况下调用C标准库例程来分配内存的。
如果这不是零,则本机Win 32分配器子系统将创建一个孤立的堆;否则,将使用默认的进程堆。此设置在为WinRT编译时没有任何影响。默认情况下,这是启用的,并且将创建一个独立的堆来存储所有分配的数据
此处出现了一个warning:当设置为非零并且调用了winMemShu倒计时函数时,使用隔离堆分配的所有数据都将立即被释放,而任何试图访问已释放的数据会立即导致访问冲突。
#ifndef SQLITE_WIN32_HEAP_MAX_INIT_SIZE
# define SQLITE_WIN32_HEAP_MAX_INIT_SIZE (4294967295U)
#endif
Win32特定堆的最大初始大小
#ifndef SQLITE_WIN32_CACHE_SIZE
# if SQLITE_DEFAULT_CACHE_SIZE>=0
# define SQLITE_WIN32_CACHE_SIZE (SQLITE_DEFAULT_CACHE_SIZE)
# else
# define SQLITE_WIN32_CACHE_SIZE (-(SQLITE_DEFAULT_CACHE_SIZE))
# endif
#endif
计算Win32特定堆的初始大小时所用的缓存大小
#ifndef SQLITE_WIN32_MAX_CACHE_SIZE
# define SQLITE_WIN32_MAX_CACHE_SIZE (((SQLITE_WIN32_HEAP_MAX_INIT_SIZE) - \
(SQLITE_WIN32_HEAP_INIT_EXTRA)) / \
(SQLITE_DEFAULT_PAGE_SIZE))
#endif
根据可能最大的初始堆大小和默认页大小,计算最大合法缓存大小(以页为单位),并预留所需的额外空间。
typedef struct winMemData winMemData;
struct winMemData {
#ifndef NDEBUG
u32 magic1;
#endif
HANDLE hHeap;
BOOL bOwned;
#ifndef NDEBUG
u32 magic2;
#endif
};
#ifndef NDEBUG
#define winMemAssertMagic1() assert( win_mem_data.magic1==WINMEM_MAGIC1 )
#define winMemAssertMagic2() assert( win_mem_data.magic2==WINMEM_MAGIC2 )
#define winMemAssertMagic() winMemAssertMagic1(); winMemAssertMagic2();
#else
#define winMemAssertMagic()
#endif
WinmemData结构存储sqlite3_mem_method实现所需的信息。包含了上面提到的分配方法malloc(),free(),remalloc()
如果定义了NDEBUG,编译器会认为是非DEBUG的模式(虽然编译出来的程序还是很大,而且还可以进行调试),此时trace(),assert()就没有用了,相当于点击了’release’
static struct win_syscall {
const char *zName; /* Name of the system call */
sqlite3_syscall_ptr pCurrent; /* Current value of the system call */
sqlite3_syscall_ptr pDefault; /* Default value */
} aSyscall[] = {
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
{ "AreFileApisANSI", (SYSCALL)AreFileApisANSI, 0 },
#else
{ "AreFileApisANSI", (SYSCALL)0, 0 },
#endif
(省略接下来长达数数数...百行的可重写系统调用)
许多系统调用是通过指针到函数访问的,这样它们在运行阶段可被重写,以便于在测试中进行错误注入。而上面的数组用来保存所有可重写系统调用的名称和指针。
#if defined(InterlockedCompareExchange)
{ "InterlockedCompareExchange", (SYSCALL)0, 0 },
#define osInterlockedCompareExchange InterlockedCompareExchange
#else
{ "InterlockedCompareExchange", (SYSCALL)InterlockedCompareExchange, 0 },
#define osInterlockedCompareExchange ((LONG(WINAPI*)(LONG \
SQLITE_WIN32_VOLATILE*, LONG,LONG))aSyscall[76].pCurrent)
#endif
注意!InterlockedCompareExchange实际上只是一个使用编译器内部的宏。所以不要试图将它变成一个可重新定义的接口。
接来下是很重要的一个方法:sqlite3_VFS的xSetSystemCall()方法,用于所有的WIN32 VFSes.
如果成功地更新系统调用指针,则返回SQLITE_OK;如果没有可配置的系统调用zName,则返回SQLITE_NotFound.
static int winSetSystemCall(
sqlite3_vfs *pNotUsed,
const char *zName,
sqlite3_syscall_ptr pNewFunc
){
unsigned int i;
int rc = SQLITE_NOTFOUND;
UNUSED_PARAMETER(pNotUsed);
if( zName==0 ){
/*如果没有指定zName,则将所有系统调用还原到其默认设置并返回NULL*/
rc = SQLITE_OK;
for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
if( aSyscall[i].pDefault ){
aSyscall[i].pCurrent = aSyscall[i].pDefault;
}
}
}
else{
/*如果指定了zName,则只对指定的一个系统调用进行操作。*/
for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
if( strcmp(zName, aSyscall[i].zName)==0 ){
if( aSyscall[i].pDefault==0 ){
aSyscall[i].pDefault = aSyscall[i].pCurrent;
}
rc = SQLITE_OK;
if( pNewFunc==0 ) pNewFunc = aSyscall[i].pDefault;
aSyscall[i].pCurrent = pNewFunc;
break;
}
}
}
return rc;
}
返回系统调用的值。如果zName不是一个可识别的系统调用名或者系统调用当前未定义,则返回NULL。
static sqlite3_syscall_ptr winGetSystemCall(
sqlite3_vfs *pNotUsed,
const char *zName
){
unsigned int i;
UNUSED_PARAMETER(pNotUsed);
for(i=0; i<sizeof(aSyscall)/sizeof(aSyscall[0]); i++){
if( strcmp(zName, aSyscall[i].zName)==0 ) return aSyscall[i].pCurrent;
}
return 0;
}
在zName之后返回第一个系统调用的名称。
如果zName==NULL,则返回第一个系统调用的名称。如果zName是最后一次系统调用,或者如果zName不是有效系统调用的名称,则返回NULL。
static const char *winNextSystemCall(sqlite3_vfs *p, const char *zName){
int i = -1;
UNUSED_PARAMETER(p);
if( zName ){
for(i=0; i<ArraySize(aSyscall)-1; i++){
if( strcmp(zName, aSyscall[i].zName)==0 ) break;
}
}
for(i++; i<ArraySize(aSyscall); i++){
if( aSyscall[i].pCurrent!=0 ) return aSyscall[i].zName;
}
return 0;
}
下面这个函数将尝试压缩Win32本机堆。如果成功,则返回SQLITE_OK;如果失败,将返回SQLITE_NOMEM、SQLITE_ERROR或SQLITE_NotFound的一个。“pnLargest”参数(如果不是零)将用于返回堆中最大的提交空闲块的大小
#ifdef SQLITE_WIN32_MALLOC
int sqlite3_win32_compact_heap(LPUINT pnLargest){
int rc = SQLITE_OK;
UINT nLargest = 0;
HANDLE hHeap;
winMemAssertMagic();
hHeap = winMemGetHeap();
assert( hHeap!=0 );
assert( hHeap!=INVALID_HANDLE_VALUE );
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
assert( osHeapValidate(hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
#endif
#if !SQLITE_OS_WINCE && !SQLITE_OS_WINRT
if( (nLargest=osHeapCompact(hHeap, SQLITE_WIN32_HEAP_FLAGS))==0 ){
DWORD lastErrno = osGetLastError();
if( lastErrno==NO_ERROR ){
sqlite3_log(SQLITE_NOMEM, "failed to HeapCompact (no space), heap=%p",
(void*)hHeap);
rc = SQLITE_NOMEM_BKPT;
}else{
sqlite3_log(SQLITE_ERROR, "failed to HeapCompact (%lu), heap=%p",
osGetLastError(), (void*)hHeap);
rc = SQLITE_ERROR;
}
}
#else
sqlite3_log(SQLITE_NOTFOUND, "failed to HeapCompact, heap=%p",
(void*)hHeap);
rc = SQLITE_NOTFOUND;
#endif
if( pnLargest ) *pnLargest = nLargest;
return rc;
}
如果配置了Win 32本机堆,此函数将尝试销毁并重新创建它。如果Win 32本机堆未被隔离,并且/或sqlite3_Memory_use()函数不返回零,则将返回SQLITE_SARY,并且不会对Win 32本机堆进行任何更改。
此时,堆上不应该有未完成的内存分配。此外,由于主锁和memsys锁目前都由我们持有,因此没有其他函数能够访问堆。现在尝试销毁和重新创建我们的孤立的Win 32本机堆。