blob: 213a129c99c5669b463823bdcc679f2dc8f1aca4 [file] [log] [blame]
drhf51446a2012-07-21 19:40:42 +00001/*
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
danb3f56fd2014-03-31 19:57:34 +000030#if SQLITE_MAX_WORKER_THREADS>0
31
drhf51446a2012-07-21 19:40:42 +000032/********************************* Unix Pthreads ****************************/
drh3c863632014-03-25 14:12:16 +000033#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
drhf51446a2012-07-21 19:40:42 +000034
35#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
36#include <pthread.h>
37
38/* A running thread */
39struct SQLiteThread {
drh3de4df22014-04-24 12:28:28 +000040 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 */
drhf51446a2012-07-21 19:40:42 +000045};
46
47/* Create a new thread */
48int 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;
drhb92284d2014-07-29 18:46:30 +000054 int rc;
drhf51446a2012-07-21 19:40:42 +000055
mistachkinda0e4712012-07-21 22:49:08 +000056 assert( ppThread!=0 );
57 assert( xTask!=0 );
drhcb6effa2014-05-20 19:11:50 +000058 /* This routine is never used in single-threaded mode */
59 assert( sqlite3GlobalConfig.bCoreMutex!=0 );
60
mistachkinda0e4712012-07-21 22:49:08 +000061 *ppThread = 0;
62 p = sqlite3Malloc(sizeof(*p));
63 if( p==0 ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +000064 memset(p, 0, sizeof(*p));
drh3de4df22014-04-24 12:28:28 +000065 p->xTask = xTask;
66 p->pIn = pIn;
drhb92284d2014-07-29 18:46:30 +000067 if( sqlite3FaultSim(200) ){
68 rc = 1;
69 }else{
70 rc = pthread_create(&p->tid, 0, xTask, pIn);
71 }
72 if( rc ){
drh6ddecb72012-08-21 17:36:44 +000073 p->done = 1;
74 p->pOut = xTask(pIn);
drhf51446a2012-07-21 19:40:42 +000075 }
mistachkinda0e4712012-07-21 22:49:08 +000076 *ppThread = p;
drhf51446a2012-07-21 19:40:42 +000077 return SQLITE_OK;
78}
79
80/* Get the results of the thread */
81int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
82 int rc;
mistachkinda0e4712012-07-21 22:49:08 +000083
84 assert( ppOut!=0 );
drhb92284d2014-07-29 18:46:30 +000085 if( NEVER(p==0) ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +000086 if( p->done ){
87 *ppOut = p->pOut;
88 rc = SQLITE_OK;
89 }else{
drhcb6effa2014-05-20 19:11:50 +000090 rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK;
drh6ddecb72012-08-21 17:36:44 +000091 }
drhf51446a2012-07-21 19:40:42 +000092 sqlite3_free(p);
drhcb6effa2014-05-20 19:11:50 +000093 return rc;
drhf51446a2012-07-21 19:40:42 +000094}
95
96#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
97/******************************** End Unix Pthreads *************************/
98
99
mistachkinda0e4712012-07-21 22:49:08 +0000100/********************************* Win32 Threads ****************************/
drh3c863632014-03-25 14:12:16 +0000101#if SQLITE_OS_WIN && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0
mistachkinda0e4712012-07-21 22:49:08 +0000102
103#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
104#include <process.h>
105
106/* A running thread */
107struct SQLiteThread {
108 uintptr_t tid; /* The thread handle */
mistachkinb1ac2bc2014-07-29 16:37:53 +0000109 unsigned id; /* The thread identifier */
mistachkinda0e4712012-07-21 22:49:08 +0000110 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 */
mistachkinb1ac2bc2014-07-29 16:37:53 +0000116static unsigned __stdcall sqlite3ThreadProc(
mistachkinda0e4712012-07-21 22:49:08 +0000117 void *pArg /* IN: Pointer to the SQLiteThread structure */
118){
119 SQLiteThread *p = (SQLiteThread *)pArg;
120
121 assert( p!=0 );
mistachkin0479c6a2014-07-29 21:44:13 +0000122#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 */
mistachkinb1ac2bc2014-07-29 16:37:53 +0000129 assert( p->id==GetCurrentThreadId() );
mistachkin0479c6a2014-07-29 21:44:13 +0000130#endif
mistachkinda0e4712012-07-21 22:49:08 +0000131 assert( p->xTask!=0 );
132 p->pResult = p->xTask(p->pIn);
mistachkinb1ac2bc2014-07-29 16:37:53 +0000133
134 _endthreadex(0);
135 return 0; /* NOT REACHED */
mistachkinda0e4712012-07-21 22:49:08 +0000136}
137
138/* Create a new thread */
139int 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;
drh6ddecb72012-08-21 17:36:44 +0000151 if( sqlite3GlobalConfig.bCoreMutex==0 ){
152 memset(p, 0, sizeof(*p));
153 }else{
154 p->xTask = xTask;
155 p->pIn = pIn;
mistachkinb1ac2bc2014-07-29 16:37:53 +0000156 p->tid = _beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id);
mistachkinacd57ea2014-07-29 19:00:43 +0000157 if( p->tid==0 ){
drh6ddecb72012-08-21 17:36:44 +0000158 memset(p, 0, sizeof(*p));
159 }
160 }
161 if( p->xTask==0 ){
mistachkinb1ac2bc2014-07-29 16:37:53 +0000162 p->id = GetCurrentThreadId();
drh6ddecb72012-08-21 17:36:44 +0000163 p->pResult = xTask(pIn);
mistachkinda0e4712012-07-21 22:49:08 +0000164 }
165 *ppThread = p;
166 return SQLITE_OK;
167}
168
mistachkinb1ac2bc2014-07-29 16:37:53 +0000169DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */
drh2b493272014-07-29 00:23:08 +0000170
mistachkinda0e4712012-07-21 22:49:08 +0000171/* Get the results of the thread */
172int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
173 DWORD rc;
mistachkinb1ac2bc2014-07-29 16:37:53 +0000174 BOOL bRc;
mistachkinda0e4712012-07-21 22:49:08 +0000175
176 assert( ppOut!=0 );
drhb92284d2014-07-29 18:46:30 +0000177 if( NEVER(p==0) ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +0000178 if( p->xTask==0 ){
mistachkin7c2231c2014-07-29 18:53:01 +0000179 assert( p->id==GetCurrentThreadId() );
mistachkinf7da5552014-04-04 21:40:38 +0000180 rc = WAIT_OBJECT_0;
mistachkin7c2231c2014-07-29 18:53:01 +0000181 assert( p->tid==0 );
drh6ddecb72012-08-21 17:36:44 +0000182 }else{
mistachkinb1ac2bc2014-07-29 16:37:53 +0000183 assert( p->id!=0 && p->id!=GetCurrentThreadId() );
drh6ddecb72012-08-21 17:36:44 +0000184 rc = sqlite3Win32Wait((HANDLE)p->tid);
185 assert( rc!=WAIT_IO_COMPLETION );
mistachkinb1ac2bc2014-07-29 16:37:53 +0000186 bRc = CloseHandle((HANDLE)p->tid);
187 assert( bRc );
drh6ddecb72012-08-21 17:36:44 +0000188 }
mistachkinda0e4712012-07-21 22:49:08 +0000189 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_WINRT */
195/******************************** End Win32 Threads *************************/
196
197
drhf51446a2012-07-21 19:40:42 +0000198/********************************* 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 */
207struct 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 */
214int 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;
mistachkinda0e4712012-07-21 22:49:08 +0000220
221 assert( ppThread!=0 );
222 assert( xTask!=0 );
223 *ppThread = 0;
224 p = sqlite3Malloc(sizeof(*p));
drhf51446a2012-07-21 19:40:42 +0000225 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 }
mistachkinda0e4712012-07-21 22:49:08 +0000233 *ppThread = p;
234 return SQLITE_OK;
drhf51446a2012-07-21 19:40:42 +0000235}
236
237/* Get the results of the thread */
238int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
dand94d4ee2014-05-05 09:08:54 +0000239
mistachkinda0e4712012-07-21 22:49:08 +0000240 assert( ppOut!=0 );
drhb92284d2014-07-29 18:46:30 +0000241 if( NEVER(p==0) ) return SQLITE_NOMEM;
drhf51446a2012-07-21 19:40:42 +0000242 if( p->xTask ){
mistachkinda0e4712012-07-21 22:49:08 +0000243 *ppOut = p->xTask(p->pIn);
drhf51446a2012-07-21 19:40:42 +0000244 }else{
245 *ppOut = p->pResult;
246 }
247 sqlite3_free(p);
dand94d4ee2014-05-05 09:08:54 +0000248
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
drhf51446a2012-07-21 19:40:42 +0000257 return SQLITE_OK;
258}
259
260#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
261/****************************** End Single-Threaded *************************/
danb3f56fd2014-03-31 19:57:34 +0000262#endif /* SQLITE_MAX_WORKER_THREADS>0 */