OLD | NEW |
| (Empty) |
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. | |
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 #if SQLITE_OS_WIN | |
30 # include "os_win.h" | |
31 #endif | |
32 | |
33 #if SQLITE_MAX_WORKER_THREADS>0 | |
34 | |
35 /********************************* Unix Pthreads ****************************/ | |
36 #if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0 | |
37 | |
38 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ | |
39 #include <pthread.h> | |
40 | |
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 */ | |
48 }; | |
49 | |
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() */ | |
55 ){ | |
56 SQLiteThread *p; | |
57 int rc; | |
58 | |
59 assert( ppThread!=0 ); | |
60 assert( xTask!=0 ); | |
61 /* This routine is never used in single-threaded mode */ | |
62 assert( sqlite3GlobalConfig.bCoreMutex!=0 ); | |
63 | |
64 *ppThread = 0; | |
65 p = sqlite3Malloc(sizeof(*p)); | |
66 if( p==0 ) return SQLITE_NOMEM; | |
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); | |
78 } | |
79 if( rc ){ | |
80 p->done = 1; | |
81 p->pOut = xTask(pIn); | |
82 } | |
83 *ppThread = p; | |
84 return SQLITE_OK; | |
85 } | |
86 | |
87 /* Get the results of the thread */ | |
88 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ | |
89 int rc; | |
90 | |
91 assert( ppOut!=0 ); | |
92 if( NEVER(p==0) ) return SQLITE_NOMEM; | |
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; | |
98 } | |
99 sqlite3_free(p); | |
100 return rc; | |
101 } | |
102 | |
103 #endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */ | |
104 /******************************** End Unix Pthreads *************************/ | |
105 | |
106 | |
107 /********************************* Win32 Threads ****************************/ | |
108 #if SQLITE_OS_WIN_THREADS | |
109 | |
110 #define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */ | |
111 #include <process.h> | |
112 | |
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 */ | |
120 }; | |
121 | |
122 /* Thread procedure Win32 compatibility shim */ | |
123 static unsigned __stdcall sqlite3ThreadProc( | |
124 void *pArg /* IN: Pointer to the SQLiteThread structure */ | |
125 ){ | |
126 SQLiteThread *p = (SQLiteThread *)pArg; | |
127 | |
128 assert( p!=0 ); | |
129 #if 0 | |
130 /* | |
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. | |
135 */ | |
136 assert( p->id==GetCurrentThreadId() ); | |
137 #endif | |
138 assert( p->xTask!=0 ); | |
139 p->pResult = p->xTask(p->pIn); | |
140 | |
141 _endthreadex(0); | |
142 return 0; /* NOT REACHED */ | |
143 } | |
144 | |
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() */ | |
150 ){ | |
151 SQLiteThread *p; | |
152 | |
153 assert( ppThread!=0 ); | |
154 assert( xTask!=0 ); | |
155 *ppThread = 0; | |
156 p = sqlite3Malloc(sizeof(*p)); | |
157 if( p==0 ) return SQLITE_NOMEM; | |
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)); | |
171 } | |
172 } | |
173 if( p->xTask==0 ){ | |
174 p->id = GetCurrentThreadId(); | |
175 p->pResult = xTask(pIn); | |
176 } | |
177 *ppThread = p; | |
178 return SQLITE_OK; | |
179 } | |
180 | |
181 DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */ | |
182 | |
183 /* Get the results of the thread */ | |
184 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ | |
185 DWORD rc; | |
186 BOOL bRc; | |
187 | |
188 assert( ppOut!=0 ); | |
189 if( NEVER(p==0) ) return SQLITE_NOMEM; | |
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 ); | |
200 } | |
201 if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult; | |
202 sqlite3_free(p); | |
203 return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR; | |
204 } | |
205 | |
206 #endif /* SQLITE_OS_WIN_THREADS */ | |
207 /******************************** End Win32 Threads *************************/ | |
208 | |
209 | |
210 /********************************* Single-Threaded **************************/ | |
211 #ifndef SQLITE_THREADS_IMPLEMENTED | |
212 /* | |
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 | |
216 */ | |
217 | |
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 */ | |
223 }; | |
224 | |
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() */ | |
230 ){ | |
231 SQLiteThread *p; | |
232 | |
233 assert( ppThread!=0 ); | |
234 assert( xTask!=0 ); | |
235 *ppThread = 0; | |
236 p = sqlite3Malloc(sizeof(*p)); | |
237 if( p==0 ) return SQLITE_NOMEM; | |
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); | |
244 } | |
245 *ppThread = p; | |
246 return SQLITE_OK; | |
247 } | |
248 | |
249 /* Get the results of the thread */ | |
250 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){ | |
251 | |
252 assert( ppOut!=0 ); | |
253 if( NEVER(p==0) ) return SQLITE_NOMEM; | |
254 if( p->xTask ){ | |
255 *ppOut = p->xTask(p->pIn); | |
256 }else{ | |
257 *ppOut = p->pResult; | |
258 } | |
259 sqlite3_free(p); | |
260 | |
261 #if defined(SQLITE_TEST) | |
262 { | |
263 void *pTstAlloc = sqlite3Malloc(10); | |
264 if (!pTstAlloc) return SQLITE_NOMEM; | |
265 sqlite3_free(pTstAlloc); | |
266 } | |
267 #endif | |
268 | |
269 return SQLITE_OK; | |
270 } | |
271 | |
272 #endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */ | |
273 /****************************** End Single-Threaded *************************/ | |
274 #endif /* SQLITE_MAX_WORKER_THREADS>0 */ | |
OLD | NEW |