blob: 4ce6122274ce3ebfd48d247d1a624e4eecb1ffab [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"
mistachkinb13160f2015-01-07 18:11:29 +000029#if SQLITE_OS_WIN
30# include "os_win.h"
31#endif
drhf51446a2012-07-21 19:40:42 +000032
danb3f56fd2014-03-31 19:57:34 +000033#if SQLITE_MAX_WORKER_THREADS>0
34
drhf51446a2012-07-21 19:40:42 +000035/********************************* Unix Pthreads ****************************/
drh3c863632014-03-25 14:12:16 +000036#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
drhf51446a2012-07-21 19:40:42 +000037
38#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
39#include <pthread.h>
40
41/* A running thread */
42struct SQLiteThread {
drh3de4df22014-04-24 12:28:28 +000043 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 */
drhf51446a2012-07-21 19:40:42 +000048};
49
50/* Create a new thread */
51int 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;
drhb92284d2014-07-29 18:46:30 +000057 int rc;
drhf51446a2012-07-21 19:40:42 +000058
mistachkinda0e4712012-07-21 22:49:08 +000059 assert( ppThread!=0 );
60 assert( xTask!=0 );
drhcb6effa2014-05-20 19:11:50 +000061 /* This routine is never used in single-threaded mode */
62 assert( sqlite3GlobalConfig.bCoreMutex!=0 );
63
mistachkinda0e4712012-07-21 22:49:08 +000064 *ppThread = 0;
65 p = sqlite3Malloc(sizeof(*p));
66 if( p==0 ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +000067 memset(p, 0, sizeof(*p));
drh3de4df22014-04-24 12:28:28 +000068 p->xTask = xTask;
69 p->pIn = pIn;
drhb92284d2014-07-29 18:46:30 +000070 if( sqlite3FaultSim(200) ){
71 rc = 1;
72 }else{
73 rc = pthread_create(&p->tid, 0, xTask, pIn);
74 }
75 if( rc ){
drh6ddecb72012-08-21 17:36:44 +000076 p->done = 1;
77 p->pOut = xTask(pIn);
drhf51446a2012-07-21 19:40:42 +000078 }
mistachkinda0e4712012-07-21 22:49:08 +000079 *ppThread = p;
drhf51446a2012-07-21 19:40:42 +000080 return SQLITE_OK;
81}
82
83/* Get the results of the thread */
84int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
85 int rc;
mistachkinda0e4712012-07-21 22:49:08 +000086
87 assert( ppOut!=0 );
drhb92284d2014-07-29 18:46:30 +000088 if( NEVER(p==0) ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +000089 if( p->done ){
90 *ppOut = p->pOut;
91 rc = SQLITE_OK;
92 }else{
drhcb6effa2014-05-20 19:11:50 +000093 rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK;
drh6ddecb72012-08-21 17:36:44 +000094 }
drhf51446a2012-07-21 19:40:42 +000095 sqlite3_free(p);
drhcb6effa2014-05-20 19:11:50 +000096 return rc;
drhf51446a2012-07-21 19:40:42 +000097}
98
99#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
100/******************************** End Unix Pthreads *************************/
101
102
mistachkinda0e4712012-07-21 22:49:08 +0000103/********************************* Win32 Threads ****************************/
mistachkin89ea0d32015-01-19 20:05:53 +0000104#if SQLITE_OS_WIN_THREADS
mistachkinda0e4712012-07-21 22:49:08 +0000105
106#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
107#include <process.h>
108
109/* A running thread */
110struct SQLiteThread {
drhab993382014-10-10 18:09:52 +0000111 void *tid; /* The thread handle */
mistachkinb1ac2bc2014-07-29 16:37:53 +0000112 unsigned id; /* The thread identifier */
mistachkinda0e4712012-07-21 22:49:08 +0000113 void *(*xTask)(void*); /* The routine to run as a thread */
114 void *pIn; /* Argument to xTask */
115 void *pResult; /* Result of xTask */
116};
117
118/* Thread procedure Win32 compatibility shim */
mistachkinb1ac2bc2014-07-29 16:37:53 +0000119static unsigned __stdcall sqlite3ThreadProc(
mistachkinda0e4712012-07-21 22:49:08 +0000120 void *pArg /* IN: Pointer to the SQLiteThread structure */
121){
122 SQLiteThread *p = (SQLiteThread *)pArg;
123
124 assert( p!=0 );
mistachkin0479c6a2014-07-29 21:44:13 +0000125#if 0
126 /*
127 ** This assert appears to trigger spuriously on certain
128 ** versions of Windows, possibly due to _beginthreadex()
129 ** and/or CreateThread() not fully setting their thread
130 ** ID parameter before starting the thread.
131 */
mistachkinb1ac2bc2014-07-29 16:37:53 +0000132 assert( p->id==GetCurrentThreadId() );
mistachkin0479c6a2014-07-29 21:44:13 +0000133#endif
mistachkinda0e4712012-07-21 22:49:08 +0000134 assert( p->xTask!=0 );
135 p->pResult = p->xTask(p->pIn);
mistachkinb1ac2bc2014-07-29 16:37:53 +0000136
137 _endthreadex(0);
138 return 0; /* NOT REACHED */
mistachkinda0e4712012-07-21 22:49:08 +0000139}
140
141/* Create a new thread */
142int sqlite3ThreadCreate(
143 SQLiteThread **ppThread, /* OUT: Write the thread object here */
144 void *(*xTask)(void*), /* Routine to run in a separate thread */
145 void *pIn /* Argument passed into xTask() */
146){
147 SQLiteThread *p;
148
149 assert( ppThread!=0 );
150 assert( xTask!=0 );
151 *ppThread = 0;
152 p = sqlite3Malloc(sizeof(*p));
153 if( p==0 ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +0000154 if( sqlite3GlobalConfig.bCoreMutex==0 ){
155 memset(p, 0, sizeof(*p));
156 }else{
157 p->xTask = xTask;
158 p->pIn = pIn;
drhab993382014-10-10 18:09:52 +0000159 p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id);
mistachkinacd57ea2014-07-29 19:00:43 +0000160 if( p->tid==0 ){
drh6ddecb72012-08-21 17:36:44 +0000161 memset(p, 0, sizeof(*p));
162 }
163 }
164 if( p->xTask==0 ){
mistachkinb1ac2bc2014-07-29 16:37:53 +0000165 p->id = GetCurrentThreadId();
drh6ddecb72012-08-21 17:36:44 +0000166 p->pResult = xTask(pIn);
mistachkinda0e4712012-07-21 22:49:08 +0000167 }
168 *ppThread = p;
169 return SQLITE_OK;
170}
171
mistachkinb1ac2bc2014-07-29 16:37:53 +0000172DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */
drh2b493272014-07-29 00:23:08 +0000173
mistachkinda0e4712012-07-21 22:49:08 +0000174/* Get the results of the thread */
175int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
176 DWORD rc;
mistachkinb1ac2bc2014-07-29 16:37:53 +0000177 BOOL bRc;
mistachkinda0e4712012-07-21 22:49:08 +0000178
179 assert( ppOut!=0 );
drhb92284d2014-07-29 18:46:30 +0000180 if( NEVER(p==0) ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +0000181 if( p->xTask==0 ){
mistachkin7c2231c2014-07-29 18:53:01 +0000182 assert( p->id==GetCurrentThreadId() );
mistachkinf7da5552014-04-04 21:40:38 +0000183 rc = WAIT_OBJECT_0;
mistachkin7c2231c2014-07-29 18:53:01 +0000184 assert( p->tid==0 );
drh6ddecb72012-08-21 17:36:44 +0000185 }else{
mistachkinb1ac2bc2014-07-29 16:37:53 +0000186 assert( p->id!=0 && p->id!=GetCurrentThreadId() );
drh6ddecb72012-08-21 17:36:44 +0000187 rc = sqlite3Win32Wait((HANDLE)p->tid);
188 assert( rc!=WAIT_IO_COMPLETION );
mistachkinb1ac2bc2014-07-29 16:37:53 +0000189 bRc = CloseHandle((HANDLE)p->tid);
190 assert( bRc );
drh6ddecb72012-08-21 17:36:44 +0000191 }
mistachkinda0e4712012-07-21 22:49:08 +0000192 if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
193 sqlite3_free(p);
194 return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
195}
196
mistachkin89ea0d32015-01-19 20:05:53 +0000197#endif /* SQLITE_OS_WIN_THREADS */
mistachkinda0e4712012-07-21 22:49:08 +0000198/******************************** End Win32 Threads *************************/
199
200
drhf51446a2012-07-21 19:40:42 +0000201/********************************* Single-Threaded **************************/
202#ifndef SQLITE_THREADS_IMPLEMENTED
203/*
204** This implementation does not actually create a new thread. It does the
205** work of the thread in the main thread, when either the thread is created
206** or when it is joined
207*/
208
209/* A running thread */
210struct SQLiteThread {
211 void *(*xTask)(void*); /* The routine to run as a thread */
212 void *pIn; /* Argument to xTask */
213 void *pResult; /* Result of xTask */
214};
215
216/* Create a new thread */
217int sqlite3ThreadCreate(
218 SQLiteThread **ppThread, /* OUT: Write the thread object here */
219 void *(*xTask)(void*), /* Routine to run in a separate thread */
220 void *pIn /* Argument passed into xTask() */
221){
222 SQLiteThread *p;
mistachkinda0e4712012-07-21 22:49:08 +0000223
224 assert( ppThread!=0 );
225 assert( xTask!=0 );
226 *ppThread = 0;
227 p = sqlite3Malloc(sizeof(*p));
drhf51446a2012-07-21 19:40:42 +0000228 if( p==0 ) return SQLITE_NOMEM;
229 if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
230 p->xTask = xTask;
231 p->pIn = pIn;
232 }else{
233 p->xTask = 0;
234 p->pResult = xTask(pIn);
235 }
mistachkinda0e4712012-07-21 22:49:08 +0000236 *ppThread = p;
237 return SQLITE_OK;
drhf51446a2012-07-21 19:40:42 +0000238}
239
240/* Get the results of the thread */
241int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
dand94d4ee2014-05-05 09:08:54 +0000242
mistachkinda0e4712012-07-21 22:49:08 +0000243 assert( ppOut!=0 );
drhb92284d2014-07-29 18:46:30 +0000244 if( NEVER(p==0) ) return SQLITE_NOMEM;
drhf51446a2012-07-21 19:40:42 +0000245 if( p->xTask ){
mistachkinda0e4712012-07-21 22:49:08 +0000246 *ppOut = p->xTask(p->pIn);
drhf51446a2012-07-21 19:40:42 +0000247 }else{
248 *ppOut = p->pResult;
249 }
250 sqlite3_free(p);
dand94d4ee2014-05-05 09:08:54 +0000251
252#if defined(SQLITE_TEST)
253 {
254 void *pTstAlloc = sqlite3Malloc(10);
255 if (!pTstAlloc) return SQLITE_NOMEM;
256 sqlite3_free(pTstAlloc);
257 }
258#endif
259
drhf51446a2012-07-21 19:40:42 +0000260 return SQLITE_OK;
261}
262
263#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
264/****************************** End Single-Threaded *************************/
danb3f56fd2014-03-31 19:57:34 +0000265#endif /* SQLITE_MAX_WORKER_THREADS>0 */