xref: /sqlite-3.40.0/src/threads.c (revision 9edb5ceb)
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( sqlite3FaultSim(200) ){
71     rc = 1;
72   }else{
73     rc = pthread_create(&p->tid, 0, xTask, pIn);
74   }
75   if( rc ){
76     p->done = 1;
77     p->pOut = xTask(pIn);
78   }
79   *ppThread = p;
80   return SQLITE_OK;
81 }
82 
83 /* Get the results of the thread */
84 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
85   int rc;
86 
87   assert( ppOut!=0 );
88   if( NEVER(p==0) ) return SQLITE_NOMEM;
89   if( p->done ){
90     *ppOut = p->pOut;
91     rc = SQLITE_OK;
92   }else{
93     rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK;
94   }
95   sqlite3_free(p);
96   return rc;
97 }
98 
99 #endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
100 /******************************** End Unix Pthreads *************************/
101 
102 
103 /********************************* Win32 Threads ****************************/
104 #if SQLITE_OS_WIN_THREADS
105 
106 #define SQLITE_THREADS_IMPLEMENTED 1  /* Prevent the single-thread code below */
107 #include <process.h>
108 
109 /* A running thread */
110 struct SQLiteThread {
111   void *tid;               /* The thread handle */
112   unsigned id;             /* The thread identifier */
113   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 */
119 static unsigned __stdcall sqlite3ThreadProc(
120   void *pArg  /* IN: Pointer to the SQLiteThread structure */
121 ){
122   SQLiteThread *p = (SQLiteThread *)pArg;
123 
124   assert( p!=0 );
125 #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   */
132   assert( p->id==GetCurrentThreadId() );
133 #endif
134   assert( p->xTask!=0 );
135   p->pResult = p->xTask(p->pIn);
136 
137   _endthreadex(0);
138   return 0; /* NOT REACHED */
139 }
140 
141 /* Create a new thread */
142 int 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;
154   if( sqlite3GlobalConfig.bCoreMutex==0 ){
155     memset(p, 0, sizeof(*p));
156   }else{
157     p->xTask = xTask;
158     p->pIn = pIn;
159     p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id);
160     if( p->tid==0 ){
161       memset(p, 0, sizeof(*p));
162     }
163   }
164   if( p->xTask==0 ){
165     p->id = GetCurrentThreadId();
166     p->pResult = xTask(pIn);
167   }
168   *ppThread = p;
169   return SQLITE_OK;
170 }
171 
172 DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */
173 
174 /* Get the results of the thread */
175 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
176   DWORD rc;
177   BOOL bRc;
178 
179   assert( ppOut!=0 );
180   if( NEVER(p==0) ) return SQLITE_NOMEM;
181   if( p->xTask==0 ){
182     assert( p->id==GetCurrentThreadId() );
183     rc = WAIT_OBJECT_0;
184     assert( p->tid==0 );
185   }else{
186     assert( p->id!=0 && p->id!=GetCurrentThreadId() );
187     rc = sqlite3Win32Wait((HANDLE)p->tid);
188     assert( rc!=WAIT_IO_COMPLETION );
189     bRc = CloseHandle((HANDLE)p->tid);
190     assert( bRc );
191   }
192   if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
193   sqlite3_free(p);
194   return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
195 }
196 
197 #endif /* SQLITE_OS_WIN_THREADS */
198 /******************************** End Win32 Threads *************************/
199 
200 
201 /********************************* 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 */
210 struct 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 */
217 int 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;
223 
224   assert( ppThread!=0 );
225   assert( xTask!=0 );
226   *ppThread = 0;
227   p = sqlite3Malloc(sizeof(*p));
228   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   }
236   *ppThread = p;
237   return SQLITE_OK;
238 }
239 
240 /* Get the results of the thread */
241 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
242 
243   assert( ppOut!=0 );
244   if( NEVER(p==0) ) return SQLITE_NOMEM;
245   if( p->xTask ){
246     *ppOut = p->xTask(p->pIn);
247   }else{
248     *ppOut = p->pResult;
249   }
250   sqlite3_free(p);
251 
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 
260   return SQLITE_OK;
261 }
262 
263 #endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
264 /****************************** End Single-Threaded *************************/
265 #endif /* SQLITE_MAX_WORKER_THREADS>0 */
266