Make the walIndexPage() routine about 3x faster by factoring out the seldom
[sqlite.git] / src / threads.c
blobf128d69fc2355512e1014ad63c90f9e198123319
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.
11 ******************************************************************************
13 ** This file presents a simple cross-platform threading interface for
14 ** use internally by SQLite.
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.
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.
28 #include "sqliteInt.h"
29 #if SQLITE_OS_WIN
30 # include "os_win.h"
31 #endif
33 #if SQLITE_MAX_WORKER_THREADS>0
35 /********************************* Unix Pthreads ****************************/
36 #if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
38 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
39 #include <pthread.h>
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 */
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() */
56 SQLiteThread *p;
57 int rc;
59 assert( ppThread!=0 );
60 assert( xTask!=0 );
61 /* This routine is never used in single-threaded mode */
62 assert( sqlite3GlobalConfig.bCoreMutex!=0 );
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);
79 if( rc ){
80 p->done = 1;
81 p->pOut = xTask(pIn);
83 *ppThread = p;
84 return SQLITE_OK;
87 /* Get the results of the thread */
88 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
89 int rc;
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;
99 sqlite3_free(p);
100 return rc;
103 #endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
104 /******************************** End Unix Pthreads *************************/
107 /********************************* Win32 Threads ****************************/
108 #if SQLITE_OS_WIN_THREADS
110 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
111 #include <process.h>
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 */
122 /* Thread procedure Win32 compatibility shim */
123 static unsigned __stdcall sqlite3ThreadProc(
124 void *pArg /* IN: Pointer to the SQLiteThread structure */
126 SQLiteThread *p = (SQLiteThread *)pArg;
128 assert( p!=0 );
129 #if 0
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.
136 assert( p->id==GetCurrentThreadId() );
137 #endif
138 assert( p->xTask!=0 );
139 p->pResult = p->xTask(p->pIn);
141 _endthreadex(0);
142 return 0; /* NOT REACHED */
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() */
151 SQLiteThread *p;
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));
173 if( p->xTask==0 ){
174 p->id = GetCurrentThreadId();
175 p->pResult = xTask(pIn);
177 *ppThread = p;
178 return SQLITE_OK;
181 DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */
183 /* Get the results of the thread */
184 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
185 DWORD rc;
186 BOOL bRc;
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 );
201 if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
202 sqlite3_free(p);
203 return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
206 #endif /* SQLITE_OS_WIN_THREADS */
207 /******************************** End Win32 Threads *************************/
210 /********************************* Single-Threaded **************************/
211 #ifndef SQLITE_THREADS_IMPLEMENTED
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
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 */
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() */
231 SQLiteThread *p;
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);
245 *ppThread = p;
246 return SQLITE_OK;
249 /* Get the results of the thread */
250 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
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;
259 sqlite3_free(p);
261 #if defined(SQLITE_TEST)
263 void *pTstAlloc = sqlite3Malloc(10);
264 if (!pTstAlloc) return SQLITE_NOMEM_BKPT;
265 sqlite3_free(pTstAlloc);
267 #endif
269 return SQLITE_OK;
272 #endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
273 /****************************** End Single-Threaded *************************/
274 #endif /* SQLITE_MAX_WORKER_THREADS>0 */