blob: 64975801bec46993c12f6b3e17d758d068281945 [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;
drhf51446a2012-07-21 19:40:42 +000054
mistachkinda0e4712012-07-21 22:49:08 +000055 assert( ppThread!=0 );
56 assert( xTask!=0 );
57 *ppThread = 0;
58 p = sqlite3Malloc(sizeof(*p));
59 if( p==0 ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +000060 memset(p, 0, sizeof(*p));
drh3de4df22014-04-24 12:28:28 +000061 p->xTask = xTask;
62 p->pIn = pIn;
drh6ddecb72012-08-21 17:36:44 +000063 if( sqlite3GlobalConfig.bCoreMutex==0
64 || pthread_create(&p->tid, 0, xTask, pIn)!=0
65 ){
66 p->done = 1;
67 p->pOut = xTask(pIn);
drhf51446a2012-07-21 19:40:42 +000068 }
mistachkinda0e4712012-07-21 22:49:08 +000069 *ppThread = p;
drhf51446a2012-07-21 19:40:42 +000070 return SQLITE_OK;
71}
72
73/* Get the results of the thread */
74int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
75 int rc;
mistachkinda0e4712012-07-21 22:49:08 +000076
77 assert( ppOut!=0 );
drhf51446a2012-07-21 19:40:42 +000078 if( p==0 ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +000079 if( p->done ){
80 *ppOut = p->pOut;
81 rc = SQLITE_OK;
82 }else{
83 rc = pthread_join(p->tid, ppOut);
84 }
drhf51446a2012-07-21 19:40:42 +000085 sqlite3_free(p);
86 return rc ? SQLITE_ERROR : SQLITE_OK;
87}
88
89#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
90/******************************** End Unix Pthreads *************************/
91
92
mistachkinda0e4712012-07-21 22:49:08 +000093/********************************* Win32 Threads ****************************/
drh3c863632014-03-25 14:12:16 +000094#if SQLITE_OS_WIN && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0
mistachkinda0e4712012-07-21 22:49:08 +000095
96#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
97#include <process.h>
98
99/* A running thread */
100struct SQLiteThread {
101 uintptr_t tid; /* The thread handle */
102 void *(*xTask)(void*); /* The routine to run as a thread */
103 void *pIn; /* Argument to xTask */
104 void *pResult; /* Result of xTask */
105};
106
107/* Thread procedure Win32 compatibility shim */
108static void sqlite3ThreadProc(
109 void *pArg /* IN: Pointer to the SQLiteThread structure */
110){
111 SQLiteThread *p = (SQLiteThread *)pArg;
112
113 assert( p!=0 );
114 assert( p->xTask!=0 );
115 p->pResult = p->xTask(p->pIn);
116 _endthread();
117}
118
119/* Create a new thread */
120int sqlite3ThreadCreate(
121 SQLiteThread **ppThread, /* OUT: Write the thread object here */
122 void *(*xTask)(void*), /* Routine to run in a separate thread */
123 void *pIn /* Argument passed into xTask() */
124){
125 SQLiteThread *p;
126
127 assert( ppThread!=0 );
128 assert( xTask!=0 );
129 *ppThread = 0;
130 p = sqlite3Malloc(sizeof(*p));
131 if( p==0 ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +0000132 if( sqlite3GlobalConfig.bCoreMutex==0 ){
133 memset(p, 0, sizeof(*p));
134 }else{
135 p->xTask = xTask;
136 p->pIn = pIn;
137 p->tid = _beginthread(sqlite3ThreadProc, 0, p);
138 if( p->tid==(uintptr_t)-1 ){
139 memset(p, 0, sizeof(*p));
140 }
141 }
142 if( p->xTask==0 ){
143 p->pResult = xTask(pIn);
mistachkinda0e4712012-07-21 22:49:08 +0000144 }
145 *ppThread = p;
146 return SQLITE_OK;
147}
148
149/* Get the results of the thread */
150int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
151 DWORD rc;
152
153 assert( ppOut!=0 );
154 if( p==0 ) return SQLITE_NOMEM;
drh6ddecb72012-08-21 17:36:44 +0000155 if( p->xTask==0 ){
mistachkinf7da5552014-04-04 21:40:38 +0000156 rc = WAIT_OBJECT_0;
drh6ddecb72012-08-21 17:36:44 +0000157 }else{
158 rc = sqlite3Win32Wait((HANDLE)p->tid);
159 assert( rc!=WAIT_IO_COMPLETION );
160 }
mistachkinda0e4712012-07-21 22:49:08 +0000161 if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
162 sqlite3_free(p);
163 return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
164}
165
166#endif /* SQLITE_OS_WIN && !SQLITE_OS_WINRT */
167/******************************** End Win32 Threads *************************/
168
169
drhf51446a2012-07-21 19:40:42 +0000170/********************************* Single-Threaded **************************/
171#ifndef SQLITE_THREADS_IMPLEMENTED
172/*
173** This implementation does not actually create a new thread. It does the
174** work of the thread in the main thread, when either the thread is created
175** or when it is joined
176*/
177
178/* A running thread */
179struct SQLiteThread {
180 void *(*xTask)(void*); /* The routine to run as a thread */
181 void *pIn; /* Argument to xTask */
182 void *pResult; /* Result of xTask */
183};
184
185/* Create a new thread */
186int sqlite3ThreadCreate(
187 SQLiteThread **ppThread, /* OUT: Write the thread object here */
188 void *(*xTask)(void*), /* Routine to run in a separate thread */
189 void *pIn /* Argument passed into xTask() */
190){
191 SQLiteThread *p;
mistachkinda0e4712012-07-21 22:49:08 +0000192
193 assert( ppThread!=0 );
194 assert( xTask!=0 );
195 *ppThread = 0;
196 p = sqlite3Malloc(sizeof(*p));
drhf51446a2012-07-21 19:40:42 +0000197 if( p==0 ) return SQLITE_NOMEM;
198 if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
199 p->xTask = xTask;
200 p->pIn = pIn;
201 }else{
202 p->xTask = 0;
203 p->pResult = xTask(pIn);
204 }
mistachkinda0e4712012-07-21 22:49:08 +0000205 *ppThread = p;
206 return SQLITE_OK;
drhf51446a2012-07-21 19:40:42 +0000207}
208
209/* Get the results of the thread */
210int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
mistachkinda0e4712012-07-21 22:49:08 +0000211 assert( ppOut!=0 );
drhf51446a2012-07-21 19:40:42 +0000212 if( p==0 ) return SQLITE_NOMEM;
213 if( p->xTask ){
mistachkinda0e4712012-07-21 22:49:08 +0000214 *ppOut = p->xTask(p->pIn);
drhf51446a2012-07-21 19:40:42 +0000215 }else{
216 *ppOut = p->pResult;
217 }
218 sqlite3_free(p);
219 return SQLITE_OK;
220}
221
222#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
223/****************************** End Single-Threaded *************************/
danb3f56fd2014-03-31 19:57:34 +0000224#endif /* SQLITE_MAX_WORKER_THREADS>0 */