2021SC@SDUSC
第四篇深入拓展了第三章讲的malloc()方法,详细讲解了VFS的内存分配和共享缓存机制,本篇将继续深入Windows的内存分配。先接着第三篇后面继续看源码。在第三篇末,由于主锁和memsys锁目前都已由我们持有,因此没有其他函数能够访问堆。现在我们尝试销毁和重新创建我们的孤立的Win 32本机堆。
if( winMemGetHeap()!=NULL && winMemGetOwned() && sqlite3_memory_used()==0 ){
assert( winMemGetHeap()!=NULL );
assert( winMemGetOwned() );
assert( sqlite3_memory_used()==0 );
winMemShutdown(winMemGetDataPtr());
assert( winMemGetHeap()==NULL );
assert( !winMemGetOwned() );
assert( sqlite3_memory_used()==0 );
rc = winMemInit(winMemGetDataPtr());
assert( rc!=SQLITE_OK || winMemGetHeap()!=NULL );
assert( rc!=SQLITE_OK || winMemGetOwned() );
assert( rc!=SQLITE_OK || sqlite3_memory_used()==0 );
}else{
rc = SQLITE_BUSY; /*Win32本机堆可能在忙碌中*/
}
sqlite3_mutex_leave(pMem);
sqlite3_mutex_leave(pMainMtx);
return rc;
接来下介绍一个重要函数,将指定的anis字符串输出到Win32调试器中。
void sqlite3_win32_write_debug(const char *zBuf, int nBuf){
char zDbgBuf[SQLITE_WIN32_DBG_BUF_SIZE];
int nMin = MIN(nBuf, (SQLITE_WIN32_DBG_BUF_SIZE - 1)); /*可能是负数*/
if( nMin<-1 ) nMin = -1; /*所有负数变为-1*/
assert( nMin==-1 || nMin==0 || nMin<SQLITE_WIN32_DBG_BUF_SIZE );
#ifdef SQLITE_ENABLE_API_ARMOR
if( !zBuf ){
(void)SQLITE_MISUSE_BKPT;
return;
}
#endif
#if defined(SQLITE_WIN32_HAS_ANSI)
if( nMin>0 ){
memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
memcpy(zDbgBuf, zBuf, nMin);
osOutputDebugStringA(zDbgBuf);
}else{
osOutputDebugStringA(zBuf);
}
#elif defined(SQLITE_WIN32_HAS_WIDE)
memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
if ( osMultiByteToWideChar(
osAreFileApisANSI() ? CP_ACP : CP_OEMCP, 0, zBuf,
nMin, (LPWSTR)zDbgBuf, SQLITE_WIN32_DBG_BUF_SIZE/sizeof(WCHAR))<=0 ){
return;
}
osOutputDebugStringW((LPCWSTR)zDbgBuf);
#else
if( nMin>0 ){
memset(zDbgBuf, 0, SQLITE_WIN32_DBG_BUF_SIZE);
memcpy(zDbgBuf, zBuf, nMin);
fprintf(stderr, "%s", zDbgBuf);
}else{
fprintf(stderr, "%s", zBuf);
}
#endif
}
下面的例程将当前线程挂起至少ms毫秒。这相当于Win 32 Slep()接口。
#if SQLITE_OS_WINRT
static HANDLE sleepObj = NULL;
#endif
void sqlite3_win32_sleep(DWORD milliseconds){
#if SQLITE_OS_WINRT
if ( sleepObj==NULL ){
sleepObj = osCreateEventExW(NULL, NULL, CREATE_EVENT_MANUAL_RESET,
SYNCHRONIZE);
}
assert( sleepObj!=NULL );
osWaitForSingleObjectEx(sleepObj, milliseconds, FALSE);
#else
osSleep(milliseconds);
#endif
}
如果我们在WinNT、Win2K、WinXP、或WinCE下运行,则返回true(非零)。返回Win 95、Win 98或WinME的false(0)。这里有一个有趣的观察:Win 95、Win 98和WinME缺乏LockFileEx()API。但是,只要我们在运行Win 95/98/ME时不调用它,我们仍然可以静态地链接到该API。调用这个例程用于确定主机是Win 95/98/ME还是WinNT/2K/XP,以便我们知道是否可以安全地调用LockFileEx()API。
此函数根据NT内核确定机器是否运行Windows的版本。
int sqlite3_win32_is_nt(void){
#if SQLITE_OS_WINRT /* WinRT子平台被认为是基于NT内核的。*/
return 1;
#elif SQLITE_WIN32_GETVERSIONEX
if( osInterlockedCompareExchange(&sqlite3_os_type, 0, 0)==0 ){
#if defined(SQLITE_WIN32_HAS_ANSI)
OSVERSIONINFOA sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
osGetVersionExA(&sInfo);
osInterlockedCompareExchange(&sqlite3_os_type,
(sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
#elif defined(SQLITE_WIN32_HAS_WIDE)
OSVERSIONINFOW sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
osGetVersionExW(&sInfo);
osInterlockedCompareExchange(&sqlite3_os_type,
(sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) ? 2 : 1, 0);
#endif
}
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#elif SQLITE_TEST
return osInterlockedCompareExchange(&sqlite3_os_type, 2, 2)==2;
#else
/*所有GetVersionEx[AW]函数被废弃的子平台都被假定是基于NT内核的。*/
return 1;
#endif
}
接下来是对Windows版本系统进行的内存分配、初始化模块
分配nBytes内存
#ifdef SQLITE_WIN32_MALLOC
static void *winMemMalloc(int nBytes){
HANDLE hHeap;
void *p;
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
assert( nBytes>=0 );
p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
if( !p ){
sqlite3_log(SQLITE_NOMEM, "failed to HeapAlloc %u bytes (%lu), heap=%p",
nBytes, osGetLastError(), (void*)hHeap);
}
return p;
}
释放内存
static void winMemFree(void *pPrior){
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, pPrior) );
#endif
if( !pPrior ) return; /* Passing NULL to HeapFree is undefined. */
if( !osHeapFree(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior) ){
sqlite3_log(SQLITE_NOMEM, "failed to HeapFree block %p (%lu), heap=%p",
pPrior, osGetLastError(), (void*)hHeap);
}
}
更改现有内存分配的大小
static void *winMemRealloc(void *pPrior, int nBytes){
HANDLE hHeap;
void *p;
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, pPrior) );
#endif
assert( nBytes>=0 );
if( !pPrior ){
p = osHeapAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, (SIZE_T)nBytes);
}else{
p = osHeapReAlloc(hHeap, SQLITE_WIN32_HEAP_FLAGS, pPrior, (SIZE_T)nBytes);
}
if( !p ){
sqlite3_log(SQLITE_NOMEM, "failed to %s %u bytes (%lu), heap=%p",
pPrior ? "HeapReAlloc" : "HeapAlloc", nBytes, osGetLastError(),
(void*)hHeap);
}
return p;
}
返回未执行分配的大小
static int winMemSize(void *p){
HANDLE hHeap;
SIZE_T n;
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, p) );
#endif
if( !p ) return 0;
n = osHeapSize(hHeap, SQLITE_WIN32_HEAP_FLAGS, p);
if( n==(SIZE_T)-1 ){
sqlite3_log(SQLITE_NOMEM, "failed to HeapSize block %p (%lu), heap=%p",
p, osGetLastError(), (void*)hHeap);
return 0;
}
return (int)n;
}
将请求大小舍入到下一个有效分配大小
static int winMemRoundup(int n){
return n;
}
初始化此模块
static int winMemInit(void *pAppData){
winMemData *pWinMemData = (winMemData *)pAppData;
if( !pWinMemData ) return SQLITE_ERROR;
assert( pWinMemData->magic1==WINMEM_MAGIC1 );
assert( pWinMemData->magic2==WINMEM_MAGIC2 ); /*(省略一些)*/
去初始化(deinitialize)
static void winMemShutdown(void *pAppData){
winMemData *pWinMemData = (winMemData *)pAppData;
if( !pWinMemData ) return;
assert( pWinMemData->magic1==WINMEM_MAGIC1 );
assert( pWinMemData->magic2==WINMEM_MAGIC2 );
if( pWinMemData->hHeap ){
assert( pWinMemData->hHeap!=INVALID_HANDLE_VALUE );
#if !SQLITE_OS_WINRT && defined(SQLITE_WIN32_MALLOC_VALIDATE)
assert( osHeapValidate(pWinMemData->hHeap, SQLITE_WIN32_HEAP_FLAGS, NULL) );
#endif
if( pWinMemData->bOwned ){
if( !osHeapDestroy(pWinMemData->hHeap) ){
sqlite3_log(SQLITE_NOMEM, "failed to HeapDestroy (%lu), heap=%p",
osGetLastError(), (void*)pWinMemData->hHeap);
}
pWinMemData->bOwned = FALSE;
}
pWinMemData->hHeap = NULL;
}
}
用指向该文件中例程的指针填充**sqlite3GlobalConfig.m中的低级内存分配函数指针。
const sqlite3_mem_methods *sqlite3MemGetWin32(void){
static const sqlite3_mem_methods winMemMethods = {
winMemMalloc,
winMemFree,
winMemRealloc,
winMemSize,
winMemRoundup,
winMemInit,
winMemShutdown,
&win_mem_data
};
return &winMemMethods;
}
void sqlite3MemSetDefault(void){
sqlite3_config(SQLITE_CONFIG_MALLOC, sqlite3MemGetWin32());
}
#endif