AryaWu/sqlite
0
1/*2** 2012 July 213**4** The author disclaims copyright to this source code. In place of5** a legal notice, here is a blessing:6**7** May you do good and not evil.8** May you find forgiveness for yourself and forgive others.9** May you share freely, never taking more than you give.10**11******************************************************************************12**13** This file presents a simple cross-platform threading interface for14** use internally by SQLite.15**16** A "thread" can be created using sqlite3ThreadCreate(). This thread17** runs independently of its creator until it is joined using18** sqlite3ThreadJoin(), at which point it terminates.19**20** Threads do not have to be real. It could be that the work of the21** "thread" is done by the main thread at either the sqlite3ThreadCreate()22** or sqlite3ThreadJoin() call. This is, in fact, what happens in23** single threaded systems. Nothing in SQLite requires multiple threads.24** This interface exists so that applications that want to take advantage25** of multiple cores can do so, while also allowing applications to stay26** single-threaded if desired.27*/28#include "sqliteInt.h"29#if SQLITE_OS_WIN30# include "os_win.h"31#endif32 33#if SQLITE_MAX_WORKER_THREADS>034 35/********************************* Unix Pthreads ****************************/36#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>037 38#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */39#include <pthread.h>40 41/* A running thread */42struct SQLiteThread {43 pthread_t tid; /* Thread ID */44 int done; /* Set to true when thread finishes */45 void *pOut; /* Result returned by the thread */46 void *(*xTask)(void*); /* The thread routine */47 void *pIn; /* Argument to the thread */48};49 50/* Create a new thread */51int sqlite3ThreadCreate(52 SQLiteThread **ppThread, /* OUT: Write the thread object here */53 void *(*xTask)(void*), /* Routine to run in a separate thread */54 void *pIn /* Argument passed into xTask() */55){56 SQLiteThread *p;57 int rc;58 59 assert( ppThread!=0 );60 assert( xTask!=0 );61 /* This routine is never used in single-threaded mode */62 assert( sqlite3GlobalConfig.bCoreMutex!=0 );63 64 *ppThread = 0;65 p = sqlite3Malloc(sizeof(*p));66 if( p==0 ) return SQLITE_NOMEM_BKPT;67 memset(p, 0, sizeof(*p));68 p->xTask = xTask;69 p->pIn = pIn;70 /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a 71 ** function that returns SQLITE_ERROR when passed the argument 200, that72 ** forces worker threads to run sequentially and deterministically 73 ** for testing purposes. */74 if( sqlite3FaultSim(200) ){75 rc = 1;76 }else{ 77 rc = pthread_create(&p->tid, 0, xTask, pIn);78 }79 if( rc ){80 p->done = 1;81 p->pOut = xTask(pIn);82 }83 *ppThread = p;84 return SQLITE_OK;85}86 87/* Get the results of the thread */88int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){89 int rc;90 91 assert( ppOut!=0 );92 if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;93 if( p->done ){94 *ppOut = p->pOut;95 rc = SQLITE_OK;96 }else{97 rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK;98 }99 sqlite3_free(p);100 return rc;101}102 103#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */104/******************************** End Unix Pthreads *************************/105 106 107/********************************* Win32 Threads ****************************/108#if SQLITE_OS_WIN_THREADS109 110#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */111#include <process.h>112 113/* A running thread */114struct SQLiteThread {115 void *tid; /* The thread handle */116 unsigned id; /* The thread identifier */117 void *(*xTask)(void*); /* The routine to run as a thread */118 void *pIn; /* Argument to xTask */119 void *pResult; /* Result of xTask */120};121 122/* Thread procedure Win32 compatibility shim */123static unsigned __stdcall sqlite3ThreadProc(124 void *pArg /* IN: Pointer to the SQLiteThread structure */125){126 SQLiteThread *p = (SQLiteThread *)pArg;127 128 assert( p!=0 );129#if 0130 /*131 ** This assert appears to trigger spuriously on certain132 ** versions of Windows, possibly due to _beginthreadex()133 ** and/or CreateThread() not fully setting their thread134 ** ID parameter before starting the thread.135 */136 assert( p->id==GetCurrentThreadId() );137#endif138 assert( p->xTask!=0 );139 p->pResult = p->xTask(p->pIn);140 141 _endthreadex(0);142 return 0; /* NOT REACHED */143}144 145/* Create a new thread */146int sqlite3ThreadCreate(147 SQLiteThread **ppThread, /* OUT: Write the thread object here */148 void *(*xTask)(void*), /* Routine to run in a separate thread */149 void *pIn /* Argument passed into xTask() */150){151 SQLiteThread *p;152 153 assert( ppThread!=0 );154 assert( xTask!=0 );155 *ppThread = 0;156 p = sqlite3Malloc(sizeof(*p));157 if( p==0 ) return SQLITE_NOMEM_BKPT;158 /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a 159 ** function that returns SQLITE_ERROR when passed the argument 200, that160 ** forces worker threads to run sequentially and deterministically 161 ** (via the sqlite3FaultSim() term of the conditional) for testing162 ** purposes. */163 if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){164 memset(p, 0, sizeof(*p));165 }else{166 p->xTask = xTask;167 p->pIn = pIn;168 p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id);169 if( p->tid==0 ){170 memset(p, 0, sizeof(*p));171 }172 }173 if( p->xTask==0 ){174 p->id = GetCurrentThreadId();175 p->pResult = xTask(pIn);176 }177 *ppThread = p;178 return SQLITE_OK;179}180 181DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */182 183/* Get the results of the thread */184int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){185 DWORD rc;186 BOOL bRc;187 188 assert( ppOut!=0 );189 if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;190 if( p->xTask==0 ){191 /* assert( p->id==GetCurrentThreadId() ); */192 rc = WAIT_OBJECT_0;193 assert( p->tid==0 );194 }else{195 assert( p->id!=0 && p->id!=GetCurrentThreadId() );196 rc = sqlite3Win32Wait((HANDLE)p->tid);197 assert( rc!=WAIT_IO_COMPLETION );198 bRc = CloseHandle((HANDLE)p->tid);199 assert( bRc );200 }201 if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;202 sqlite3_free(p);203 return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;204}205 206#endif /* SQLITE_OS_WIN_THREADS */207/******************************** End Win32 Threads *************************/208 209 210/********************************* Single-Threaded **************************/211#ifndef SQLITE_THREADS_IMPLEMENTED212/*213** This implementation does not actually create a new thread. It does the214** work of the thread in the main thread, when either the thread is created215** or when it is joined216*/217 218/* A running thread */219struct SQLiteThread {220 void *(*xTask)(void*); /* The routine to run as a thread */221 void *pIn; /* Argument to xTask */222 void *pResult; /* Result of xTask */223};224 225/* Create a new thread */226int sqlite3ThreadCreate(227 SQLiteThread **ppThread, /* OUT: Write the thread object here */228 void *(*xTask)(void*), /* Routine to run in a separate thread */229 void *pIn /* Argument passed into xTask() */230){231 SQLiteThread *p;232 233 assert( ppThread!=0 );234 assert( xTask!=0 );235 *ppThread = 0;236 p = sqlite3Malloc(sizeof(*p));237 if( p==0 ) return SQLITE_NOMEM_BKPT;238 if( (SQLITE_PTR_TO_INT(p)/17)&1 ){239 p->xTask = xTask;240 p->pIn = pIn;241 }else{242 p->xTask = 0;243 p->pResult = xTask(pIn);244 }245 *ppThread = p;246 return SQLITE_OK;247}248 249/* Get the results of the thread */250int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){251 252 assert( ppOut!=0 );253 if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;254 if( p->xTask ){255 *ppOut = p->xTask(p->pIn);256 }else{257 *ppOut = p->pResult;258 }259 sqlite3_free(p);260 261#if defined(SQLITE_TEST)262 {263 void *pTstAlloc = sqlite3Malloc(10);264 if (!pTstAlloc) return SQLITE_NOMEM_BKPT;265 sqlite3_free(pTstAlloc);266 }267#endif268 269 return SQLITE_OK;270}271 272#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */273/****************************** End Single-Threaded *************************/274#endif /* SQLITE_MAX_WORKER_THREADS>0 */275 