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 30 #if SQLITE_MAX_WORKER_THREADS>0 31 32 /********************************* Unix Pthreads ****************************/ 33 #if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0 34 35 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ 36 #include <pthread.h> 37 38 /* A running thread */ 39 struct SQLiteThread { 40 pthread_t tid; /* Thread ID */ 41 int done; /* Set to true when thread finishes */ 42 void *pOut; /* Result returned by the thread */ 43 void *(*xTask)(void*); /* The thread routine */ 44 void *pIn; /* Argument to the thread */ 45 }; 46 47 /* Create a new thread */ 48 int sqlite3ThreadCreate( 49 SQLiteThread **ppThread, /* OUT: Write the thread object here */ 50 void *(*xTask)(void*), /* Routine to run in a separate thread */ 51 void *pIn /* Argument passed into xTask() */ 52 ){ 53 SQLiteThread *p; 54 int rc; 55 56 assert( ppThread!=0 ); 57 assert( xTask!=0 ); 58 /* This routine is never used in single-threaded mode */ 59 assert( sqlite3GlobalConfig.bCoreMutex!=0 ); 60 61 *ppThread = 0; 62 p = sqlite3Malloc(sizeof(*p)); 63 if( p==0 ) return SQLITE_NOMEM; 64 memset(p, 0, sizeof(*p)); 65 p->xTask = xTask; 66 p->pIn = pIn; 67 if( sqlite3FaultSim(200) ){ 68 rc = 1; 69 }else{ 70 rc = pthread_create(&p->tid, 0, xTask, pIn); 71 } 72 if( rc ){ 73 p->done = 1; 74 p->pOut = xTask(pIn); 75 } 76 *ppThread = p; 77 return SQLITE_OK; 78 } 79 80 /* Get the results of the thread */ 81 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ 82 int rc; 83 84 assert( ppOut!=0 ); 85 if( NEVER(p==0) ) return SQLITE_NOMEM; 86 if( p->done ){ 87 *ppOut = p->pOut; 88 rc = SQLITE_OK; 89 }else{ 90 rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK; 91 } 92 sqlite3_free(p); 93 return rc; 94 } 95 96 #endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */ 97 /******************************** End Unix Pthreads *************************/ 98 99 100 /********************************* Win32 Threads ****************************/ 101 #if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0 102 103 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ 104 #include <process.h> 105 106 /* A running thread */ 107 struct SQLiteThread { 108 void *tid; /* The thread handle */ 109 unsigned id; /* The thread identifier */ 110 void *(*xTask)(void*); /* The routine to run as a thread */ 111 void *pIn; /* Argument to xTask */ 112 void *pResult; /* Result of xTask */ 113 }; 114 115 /* Thread procedure Win32 compatibility shim */ 116 static unsigned __stdcall sqlite3ThreadProc( 117 void *pArg /* IN: Pointer to the SQLiteThread structure */ 118 ){ 119 SQLiteThread *p = (SQLiteThread *)pArg; 120 121 assert( p!=0 ); 122 #if 0 123 /* 124 ** This assert appears to trigger spuriously on certain 125 ** versions of Windows, possibly due to _beginthreadex() 126 ** and/or CreateThread() not fully setting their thread 127 ** ID parameter before starting the thread. 128 */ 129 assert( p->id==GetCurrentThreadId() ); 130 #endif 131 assert( p->xTask!=0 ); 132 p->pResult = p->xTask(p->pIn); 133 134 _endthreadex(0); 135 return 0; /* NOT REACHED */ 136 } 137 138 /* Create a new thread */ 139 int sqlite3ThreadCreate( 140 SQLiteThread **ppThread, /* OUT: Write the thread object here */ 141 void *(*xTask)(void*), /* Routine to run in a separate thread */ 142 void *pIn /* Argument passed into xTask() */ 143 ){ 144 SQLiteThread *p; 145 146 assert( ppThread!=0 ); 147 assert( xTask!=0 ); 148 *ppThread = 0; 149 p = sqlite3Malloc(sizeof(*p)); 150 if( p==0 ) return SQLITE_NOMEM; 151 if( sqlite3GlobalConfig.bCoreMutex==0 ){ 152 memset(p, 0, sizeof(*p)); 153 }else{ 154 p->xTask = xTask; 155 p->pIn = pIn; 156 p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id); 157 if( p->tid==0 ){ 158 memset(p, 0, sizeof(*p)); 159 } 160 } 161 if( p->xTask==0 ){ 162 p->id = GetCurrentThreadId(); 163 p->pResult = xTask(pIn); 164 } 165 *ppThread = p; 166 return SQLITE_OK; 167 } 168 169 DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */ 170 171 /* Get the results of the thread */ 172 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ 173 DWORD rc; 174 BOOL bRc; 175 176 assert( ppOut!=0 ); 177 if( NEVER(p==0) ) return SQLITE_NOMEM; 178 if( p->xTask==0 ){ 179 assert( p->id==GetCurrentThreadId() ); 180 rc = WAIT_OBJECT_0; 181 assert( p->tid==0 ); 182 }else{ 183 assert( p->id!=0 && p->id!=GetCurrentThreadId() ); 184 rc = sqlite3Win32Wait((HANDLE)p->tid); 185 assert( rc!=WAIT_IO_COMPLETION ); 186 bRc = CloseHandle((HANDLE)p->tid); 187 assert( bRc ); 188 } 189 if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; 190 sqlite3_free(p); 191 return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR; 192 } 193 194 #endif /* SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT */ 195 /******************************** End Win32 Threads *************************/ 196 197 198 /********************************* Single-Threaded **************************/ 199 #ifndef SQLITE_THREADS_IMPLEMENTED 200 /* 201 ** This implementation does not actually create a new thread. It does the 202 ** work of the thread in the main thread, when either the thread is created 203 ** or when it is joined 204 */ 205 206 /* A running thread */ 207 struct SQLiteThread { 208 void *(*xTask)(void*); /* The routine to run as a thread */ 209 void *pIn; /* Argument to xTask */ 210 void *pResult; /* Result of xTask */ 211 }; 212 213 /* Create a new thread */ 214 int sqlite3ThreadCreate( 215 SQLiteThread **ppThread, /* OUT: Write the thread object here */ 216 void *(*xTask)(void*), /* Routine to run in a separate thread */ 217 void *pIn /* Argument passed into xTask() */ 218 ){ 219 SQLiteThread *p; 220 221 assert( ppThread!=0 ); 222 assert( xTask!=0 ); 223 *ppThread = 0; 224 p = sqlite3Malloc(sizeof(*p)); 225 if( p==0 ) return SQLITE_NOMEM; 226 if( (SQLITE_PTR_TO_INT(p)/17)&1 ){ 227 p->xTask = xTask; 228 p->pIn = pIn; 229 }else{ 230 p->xTask = 0; 231 p->pResult = xTask(pIn); 232 } 233 *ppThread = p; 234 return SQLITE_OK; 235 } 236 237 /* Get the results of the thread */ 238 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ 239 240 assert( ppOut!=0 ); 241 if( NEVER(p==0) ) return SQLITE_NOMEM; 242 if( p->xTask ){ 243 *ppOut = p->xTask(p->pIn); 244 }else{ 245 *ppOut = p->pResult; 246 } 247 sqlite3_free(p); 248 249 #if defined(SQLITE_TEST) 250 { 251 void *pTstAlloc = sqlite3Malloc(10); 252 if (!pTstAlloc) return SQLITE_NOMEM; 253 sqlite3_free(pTstAlloc); 254 } 255 #endif 256 257 return SQLITE_OK; 258 } 259 260 #endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */ 261 /****************************** End Single-Threaded *************************/ 262 #endif /* SQLITE_MAX_WORKER_THREADS>0 */ 263