1 /* 2 ** 2012 July 21 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** 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 for 14 ** use internally by SQLite. 15 ** 16 ** A "thread" can be created using sqlite3ThreadCreate(). This thread 17 ** runs independently of its creator until it is joined using 18 ** sqlite3ThreadJoin(), at which point it terminates. 19 ** 20 ** Threads do not have to be real. It could be that the work of the 21 ** "thread" is done by the main thread at either the sqlite3ThreadCreate() 22 ** or sqlite3ThreadJoin() call. This is, in fact, what happens in 23 ** single threaded systems. Nothing in SQLite requires multiple threads. 24 ** This interface exists so that applications that want to take advantage 25 ** of multiple cores can do so, while also allowing applications to stay 26 ** single-threaded if desired. 27 */ 28 #include "sqliteInt.h" 29 #if SQLITE_OS_WIN 30 # include "os_win.h" 31 #endif 32 33 #if SQLITE_MAX_WORKER_THREADS>0 34 35 /********************************* Unix Pthreads ****************************/ 36 #if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0 37 38 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ 39 #include <pthread.h> 40 41 /* A running thread */ 42 struct 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 */ 51 int 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, that 72 ** 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 */ 88 int 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_THREADS 109 110 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ 111 #include <process.h> 112 113 /* A running thread */ 114 struct 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 */ 123 static 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 0 130 /* 131 ** This assert appears to trigger spuriously on certain 132 ** versions of Windows, possibly due to _beginthreadex() 133 ** and/or CreateThread() not fully setting their thread 134 ** ID parameter before starting the thread. 135 */ 136 assert( p->id==GetCurrentThreadId() ); 137 #endif 138 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 */ 146 int 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, that 160 ** forces worker threads to run sequentially and deterministically 161 ** (via the sqlite3FaultSim() term of the conditional) for testing 162 ** 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 181 DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */ 182 183 /* Get the results of the thread */ 184 int 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_IMPLEMENTED 212 /* 213 ** This implementation does not actually create a new thread. It does the 214 ** work of the thread in the main thread, when either the thread is created 215 ** or when it is joined 216 */ 217 218 /* A running thread */ 219 struct 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 */ 226 int 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 */ 250 int 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 #endif 268 269 return SQLITE_OK; 270 } 271 272 #endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */ 273 /****************************** End Single-Threaded *************************/ 274 #endif /* SQLITE_MAX_WORKER_THREADS>0 */ 275