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 */
sqlite3ThreadCreate(SQLiteThread ** ppThread,void * (* xTask)(void *),void * pIn)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_BKPT;
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 */
sqlite3ThreadJoin(SQLiteThread * p,void ** ppOut)88 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
89   int rc;
90 
91   assert( ppOut!=0 );
92   if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
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 */
sqlite3ThreadProc(void * pArg)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 */
sqlite3ThreadCreate(SQLiteThread ** ppThread,void * (* xTask)(void *),void * pIn)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_BKPT;
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 */
sqlite3ThreadJoin(SQLiteThread * p,void ** ppOut)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_BKPT;
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 */
sqlite3ThreadCreate(SQLiteThread ** ppThread,void * (* xTask)(void *),void * pIn)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_BKPT;
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 */
sqlite3ThreadJoin(SQLiteThread * p,void ** ppOut)250 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
251 
252   assert( ppOut!=0 );
253   if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
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_BKPT;
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 */
275