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 /********************************* Unix Pthreads ****************************/ 31 #if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) 32 33 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ 34 #include <pthread.h> 35 36 /* A running thread */ 37 struct SQLiteThread { 38 pthread_t tid; 39 int done; 40 void *pOut; 41 }; 42 43 /* Create a new thread */ 44 int sqlite3ThreadCreate( 45 SQLiteThread **ppThread, /* OUT: Write the thread object here */ 46 void *(*xTask)(void*), /* Routine to run in a separate thread */ 47 void *pIn /* Argument passed into xTask() */ 48 ){ 49 SQLiteThread *p; 50 51 assert( ppThread!=0 ); 52 assert( xTask!=0 ); 53 *ppThread = 0; 54 p = sqlite3Malloc(sizeof(*p)); 55 if( p==0 ) return SQLITE_NOMEM; 56 memset(p, 0, sizeof(*p)); 57 if( sqlite3GlobalConfig.bCoreMutex==0 58 || pthread_create(&p->tid, 0, xTask, pIn)!=0 59 ){ 60 p->done = 1; 61 p->pOut = xTask(pIn); 62 } 63 *ppThread = p; 64 return SQLITE_OK; 65 } 66 67 /* Get the results of the thread */ 68 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ 69 int rc; 70 71 assert( ppOut!=0 ); 72 if( p==0 ) return SQLITE_NOMEM; 73 if( p->done ){ 74 *ppOut = p->pOut; 75 rc = SQLITE_OK; 76 }else{ 77 rc = pthread_join(p->tid, ppOut); 78 } 79 sqlite3_free(p); 80 return rc ? SQLITE_ERROR : SQLITE_OK; 81 } 82 83 #endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */ 84 /******************************** End Unix Pthreads *************************/ 85 86 87 /********************************* Win32 Threads ****************************/ 88 #if SQLITE_OS_WIN && !SQLITE_OS_WINRT 89 90 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ 91 #include <process.h> 92 93 /* A running thread */ 94 struct SQLiteThread { 95 uintptr_t tid; /* The thread handle */ 96 void *(*xTask)(void*); /* The routine to run as a thread */ 97 void *pIn; /* Argument to xTask */ 98 void *pResult; /* Result of xTask */ 99 }; 100 101 /* Thread procedure Win32 compatibility shim */ 102 static void sqlite3ThreadProc( 103 void *pArg /* IN: Pointer to the SQLiteThread structure */ 104 ){ 105 SQLiteThread *p = (SQLiteThread *)pArg; 106 107 assert( p!=0 ); 108 assert( p->xTask!=0 ); 109 p->pResult = p->xTask(p->pIn); 110 _endthread(); 111 } 112 113 /* Create a new thread */ 114 int sqlite3ThreadCreate( 115 SQLiteThread **ppThread, /* OUT: Write the thread object here */ 116 void *(*xTask)(void*), /* Routine to run in a separate thread */ 117 void *pIn /* Argument passed into xTask() */ 118 ){ 119 SQLiteThread *p; 120 121 assert( ppThread!=0 ); 122 assert( xTask!=0 ); 123 *ppThread = 0; 124 p = sqlite3Malloc(sizeof(*p)); 125 if( p==0 ) return SQLITE_NOMEM; 126 if( sqlite3GlobalConfig.bCoreMutex==0 ){ 127 memset(p, 0, sizeof(*p)); 128 }else{ 129 p->xTask = xTask; 130 p->pIn = pIn; 131 p->tid = _beginthread(sqlite3ThreadProc, 0, p); 132 if( p->tid==(uintptr_t)-1 ){ 133 memset(p, 0, sizeof(*p)); 134 } 135 } 136 if( p->xTask==0 ){ 137 p->pResult = xTask(pIn); 138 } 139 *ppThread = p; 140 return SQLITE_OK; 141 } 142 143 /* Get the results of the thread */ 144 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ 145 DWORD rc; 146 147 assert( ppOut!=0 ); 148 if( p==0 ) return SQLITE_NOMEM; 149 if( p->xTask==0 ){ 150 rc = WAIT_OBJECT_O; 151 }else{ 152 rc = sqlite3Win32Wait((HANDLE)p->tid); 153 assert( rc!=WAIT_IO_COMPLETION ); 154 } 155 if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; 156 sqlite3_free(p); 157 return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR; 158 } 159 160 #endif /* SQLITE_OS_WIN && !SQLITE_OS_WINRT */ 161 /******************************** End Win32 Threads *************************/ 162 163 164 /********************************* Single-Threaded **************************/ 165 #ifndef SQLITE_THREADS_IMPLEMENTED 166 /* 167 ** This implementation does not actually create a new thread. It does the 168 ** work of the thread in the main thread, when either the thread is created 169 ** or when it is joined 170 */ 171 172 /* A running thread */ 173 struct SQLiteThread { 174 void *(*xTask)(void*); /* The routine to run as a thread */ 175 void *pIn; /* Argument to xTask */ 176 void *pResult; /* Result of xTask */ 177 }; 178 179 /* Create a new thread */ 180 int sqlite3ThreadCreate( 181 SQLiteThread **ppThread, /* OUT: Write the thread object here */ 182 void *(*xTask)(void*), /* Routine to run in a separate thread */ 183 void *pIn /* Argument passed into xTask() */ 184 ){ 185 SQLiteThread *p; 186 187 assert( ppThread!=0 ); 188 assert( xTask!=0 ); 189 *ppThread = 0; 190 p = sqlite3Malloc(sizeof(*p)); 191 if( p==0 ) return SQLITE_NOMEM; 192 if( (SQLITE_PTR_TO_INT(p)/17)&1 ){ 193 p->xTask = xTask; 194 p->pIn = pIn; 195 }else{ 196 p->xTask = 0; 197 p->pResult = xTask(pIn); 198 } 199 *ppThread = p; 200 return SQLITE_OK; 201 } 202 203 /* Get the results of the thread */ 204 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ 205 assert( ppOut!=0 ); 206 if( p==0 ) return SQLITE_NOMEM; 207 if( p->xTask ){ 208 *ppOut = p->xTask(p->pIn); 209 }else{ 210 *ppOut = p->pResult; 211 } 212 sqlite3_free(p); 213 return SQLITE_OK; 214 } 215 216 #endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */ 217 /****************************** End Single-Threaded *************************/ 218