blob: eeab5379ce891d5ccaff68c4462f0d204b6dd534 [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 {
40 pthread_t tid;
drh6ddecb72012-08-21 17:36:44 +000041 int done;
42 void *pOut;
drhf51446a2012-07-21 19:40:42 +000043};
44
45/* Create a new thread */
46int sqlite3ThreadCreate(
47 SQLiteThread **ppThread, /* OUT: Write the thread object here */
48 void *(*xTask)(void*), /* Routine to run in a separate thread */
49 void *pIn /* Argument passed into xTask() */
50){
51 SQLiteThread *p;
drhf51446a2012-07-21 19:40:42 +000052
mistachkinda0e4712012-07-21 22:49:08 +000053 assert( ppThread!=0 );
54 assert( xTask!=0 );
55 *ppThread = 0;
56 p = sqlite3Malloc(sizeof(*p));
57 if( p==0 ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +000058 memset(p, 0, sizeof(*p));
59 if( sqlite3GlobalConfig.bCoreMutex==0
60 || pthread_create(&p->tid, 0, xTask, pIn)!=0
61 ){
62 p->done = 1;
63 p->pOut = xTask(pIn);
drhf51446a2012-07-21 19:40:42 +000064 }
mistachkinda0e4712012-07-21 22:49:08 +000065 *ppThread = p;
drhf51446a2012-07-21 19:40:42 +000066 return SQLITE_OK;
67}
68
69/* Get the results of the thread */
70int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
71 int rc;
mistachkinda0e4712012-07-21 22:49:08 +000072
73 assert( ppOut!=0 );
drhf51446a2012-07-21 19:40:42 +000074 if( p==0 ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +000075 if( p->done ){
76 *ppOut = p->pOut;
77 rc = SQLITE_OK;
78 }else{
79 rc = pthread_join(p->tid, ppOut);
80 }
drhf51446a2012-07-21 19:40:42 +000081 sqlite3_free(p);
82 return rc ? SQLITE_ERROR : SQLITE_OK;
83}
84
85#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
86/******************************** End Unix Pthreads *************************/
87
88
mistachkinda0e4712012-07-21 22:49:08 +000089/********************************* Win32 Threads ****************************/
drh3c863632014-03-25 14:12:16 +000090#if SQLITE_OS_WIN && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0
mistachkinda0e4712012-07-21 22:49:08 +000091
92#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
93#include <process.h>
94
95/* A running thread */
96struct SQLiteThread {
97 uintptr_t tid; /* The thread handle */
98 void *(*xTask)(void*); /* The routine to run as a thread */
99 void *pIn; /* Argument to xTask */
100 void *pResult; /* Result of xTask */
101};
102
103/* Thread procedure Win32 compatibility shim */
104static void sqlite3ThreadProc(
105 void *pArg /* IN: Pointer to the SQLiteThread structure */
106){
107 SQLiteThread *p = (SQLiteThread *)pArg;
108
109 assert( p!=0 );
110 assert( p->xTask!=0 );
111 p->pResult = p->xTask(p->pIn);
112 _endthread();
113}
114
115/* Create a new thread */
116int sqlite3ThreadCreate(
117 SQLiteThread **ppThread, /* OUT: Write the thread object here */
118 void *(*xTask)(void*), /* Routine to run in a separate thread */
119 void *pIn /* Argument passed into xTask() */
120){
121 SQLiteThread *p;
122
123 assert( ppThread!=0 );
124 assert( xTask!=0 );
125 *ppThread = 0;
126 p = sqlite3Malloc(sizeof(*p));
127 if( p==0 ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +0000128 if( sqlite3GlobalConfig.bCoreMutex==0 ){
129 memset(p, 0, sizeof(*p));
130 }else{
131 p->xTask = xTask;
132 p->pIn = pIn;
133 p->tid = _beginthread(sqlite3ThreadProc, 0, p);
134 if( p->tid==(uintptr_t)-1 ){
135 memset(p, 0, sizeof(*p));
136 }
137 }
138 if( p->xTask==0 ){
139 p->pResult = xTask(pIn);
mistachkinda0e4712012-07-21 22:49:08 +0000140 }
141 *ppThread = p;
142 return SQLITE_OK;
143}
144
145/* Get the results of the thread */
146int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
147 DWORD rc;
148
149 assert( ppOut!=0 );
150 if( p==0 ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +0000151 if( p->xTask==0 ){
mistachkinf7da5552014-04-04 21:40:38 +0000152 rc = WAIT_OBJECT_0;
drh6ddecb72012-08-21 17:36:44 +0000153 }else{
154 rc = sqlite3Win32Wait((HANDLE)p->tid);
155 assert( rc!=WAIT_IO_COMPLETION );
156 }
mistachkinda0e4712012-07-21 22:49:08 +0000157 if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
158 sqlite3_free(p);
159 return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
160}
161
162#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINRT */
163/******************************** End Win32 Threads *************************/
164
165
drhf51446a2012-07-21 19:40:42 +0000166/********************************* Single-Threaded **************************/
167#ifndef SQLITE_THREADS_IMPLEMENTED
168/*
169** This implementation does not actually create a new thread. It does the
170** work of the thread in the main thread, when either the thread is created
171** or when it is joined
172*/
173
174/* A running thread */
175struct SQLiteThread {
176 void *(*xTask)(void*); /* The routine to run as a thread */
177 void *pIn; /* Argument to xTask */
178 void *pResult; /* Result of xTask */
179};
180
181/* Create a new thread */
182int sqlite3ThreadCreate(
183 SQLiteThread **ppThread, /* OUT: Write the thread object here */
184 void *(*xTask)(void*), /* Routine to run in a separate thread */
185 void *pIn /* Argument passed into xTask() */
186){
187 SQLiteThread *p;
mistachkinda0e4712012-07-21 22:49:08 +0000188
189 assert( ppThread!=0 );
190 assert( xTask!=0 );
191 *ppThread = 0;
192 p = sqlite3Malloc(sizeof(*p));
drhf51446a2012-07-21 19:40:42 +0000193 if( p==0 ) return SQLITE_NOMEM;
194 if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
195 p->xTask = xTask;
196 p->pIn = pIn;
197 }else{
198 p->xTask = 0;
199 p->pResult = xTask(pIn);
200 }
mistachkinda0e4712012-07-21 22:49:08 +0000201 *ppThread = p;
202 return SQLITE_OK;
drhf51446a2012-07-21 19:40:42 +0000203}
204
205/* Get the results of the thread */
206int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
mistachkinda0e4712012-07-21 22:49:08 +0000207 assert( ppOut!=0 );
drhf51446a2012-07-21 19:40:42 +0000208 if( p==0 ) return SQLITE_NOMEM;
209 if( p->xTask ){
mistachkinda0e4712012-07-21 22:49:08 +0000210 *ppOut = p->xTask(p->pIn);
drhf51446a2012-07-21 19:40:42 +0000211 }else{
212 *ppOut = p->pResult;
213 }
214 sqlite3_free(p);
215 return SQLITE_OK;
216}
217
218#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
219/****************************** End Single-Threaded *************************/
danb3f56fd2014-03-31 19:57:34 +0000220#endif /* SQLITE_MAX_WORKER_THREADS>0 */