xref: /sqlite-3.40.0/src/threads.c (revision bd41d566)
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 
30 #if SQLITE_MAX_WORKER_THREADS>0
31 
32 /********************************* Unix Pthreads ****************************/
33 #if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
34 
35 #define SQLITE_THREADS_IMPLEMENTED 1  /* Prevent the single-thread code below */
36 #include <pthread.h>
37 
38 /* A running thread */
39 struct SQLiteThread {
40   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 */
45 };
46 
47 /* Create a new thread */
48 int 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;
54   int rc;
55 
56   assert( ppThread!=0 );
57   assert( xTask!=0 );
58   /* This routine is never used in single-threaded mode */
59   assert( sqlite3GlobalConfig.bCoreMutex!=0 );
60 
61   *ppThread = 0;
62   p = sqlite3Malloc(sizeof(*p));
63   if( p==0 ) return SQLITE_NOMEM;
64   memset(p, 0, sizeof(*p));
65   p->xTask = xTask;
66   p->pIn = pIn;
67   if( sqlite3FaultSim(200) ){
68     rc = 1;
69   }else{
70     rc = pthread_create(&p->tid, 0, xTask, pIn);
71   }
72   if( rc ){
73     p->done = 1;
74     p->pOut = xTask(pIn);
75   }
76   *ppThread = p;
77   return SQLITE_OK;
78 }
79 
80 /* Get the results of the thread */
81 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
82   int rc;
83 
84   assert( ppOut!=0 );
85   if( NEVER(p==0) ) return SQLITE_NOMEM;
86   if( p->done ){
87     *ppOut = p->pOut;
88     rc = SQLITE_OK;
89   }else{
90     rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK;
91   }
92   sqlite3_free(p);
93   return rc;
94 }
95 
96 #endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
97 /******************************** End Unix Pthreads *************************/
98 
99 
100 /********************************* Win32 Threads ****************************/
101 #if SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT && SQLITE_THREADSAFE>0
102 
103 #define SQLITE_THREADS_IMPLEMENTED 1  /* Prevent the single-thread code below */
104 #include <process.h>
105 
106 /* A running thread */
107 struct SQLiteThread {
108   void *tid;               /* The thread handle */
109   unsigned id;             /* The thread identifier */
110   void *(*xTask)(void*);   /* The routine to run as a thread */
111   void *pIn;               /* Argument to xTask */
112   void *pResult;           /* Result of xTask */
113 };
114 
115 /* Thread procedure Win32 compatibility shim */
116 static unsigned __stdcall sqlite3ThreadProc(
117   void *pArg  /* IN: Pointer to the SQLiteThread structure */
118 ){
119   SQLiteThread *p = (SQLiteThread *)pArg;
120 
121   assert( p!=0 );
122 #if 0
123   /*
124   ** This assert appears to trigger spuriously on certain
125   ** versions of Windows, possibly due to _beginthreadex()
126   ** and/or CreateThread() not fully setting their thread
127   ** ID parameter before starting the thread.
128   */
129   assert( p->id==GetCurrentThreadId() );
130 #endif
131   assert( p->xTask!=0 );
132   p->pResult = p->xTask(p->pIn);
133 
134   _endthreadex(0);
135   return 0; /* NOT REACHED */
136 }
137 
138 /* Create a new thread */
139 int sqlite3ThreadCreate(
140   SQLiteThread **ppThread,  /* OUT: Write the thread object here */
141   void *(*xTask)(void*),    /* Routine to run in a separate thread */
142   void *pIn                 /* Argument passed into xTask() */
143 ){
144   SQLiteThread *p;
145 
146   assert( ppThread!=0 );
147   assert( xTask!=0 );
148   *ppThread = 0;
149   p = sqlite3Malloc(sizeof(*p));
150   if( p==0 ) return SQLITE_NOMEM;
151   if( sqlite3GlobalConfig.bCoreMutex==0 ){
152     memset(p, 0, sizeof(*p));
153   }else{
154     p->xTask = xTask;
155     p->pIn = pIn;
156     p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id);
157     if( p->tid==0 ){
158       memset(p, 0, sizeof(*p));
159     }
160   }
161   if( p->xTask==0 ){
162     p->id = GetCurrentThreadId();
163     p->pResult = xTask(pIn);
164   }
165   *ppThread = p;
166   return SQLITE_OK;
167 }
168 
169 DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */
170 
171 /* Get the results of the thread */
172 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
173   DWORD rc;
174   BOOL bRc;
175 
176   assert( ppOut!=0 );
177   if( NEVER(p==0) ) return SQLITE_NOMEM;
178   if( p->xTask==0 ){
179     assert( p->id==GetCurrentThreadId() );
180     rc = WAIT_OBJECT_0;
181     assert( p->tid==0 );
182   }else{
183     assert( p->id!=0 && p->id!=GetCurrentThreadId() );
184     rc = sqlite3Win32Wait((HANDLE)p->tid);
185     assert( rc!=WAIT_IO_COMPLETION );
186     bRc = CloseHandle((HANDLE)p->tid);
187     assert( bRc );
188   }
189   if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
190   sqlite3_free(p);
191   return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
192 }
193 
194 #endif /* SQLITE_OS_WIN && !SQLITE_OS_WINCE && !SQLITE_OS_WINRT */
195 /******************************** End Win32 Threads *************************/
196 
197 
198 /********************************* Single-Threaded **************************/
199 #ifndef SQLITE_THREADS_IMPLEMENTED
200 /*
201 ** This implementation does not actually create a new thread.  It does the
202 ** work of the thread in the main thread, when either the thread is created
203 ** or when it is joined
204 */
205 
206 /* A running thread */
207 struct SQLiteThread {
208   void *(*xTask)(void*);   /* The routine to run as a thread */
209   void *pIn;               /* Argument to xTask */
210   void *pResult;           /* Result of xTask */
211 };
212 
213 /* Create a new thread */
214 int sqlite3ThreadCreate(
215   SQLiteThread **ppThread,  /* OUT: Write the thread object here */
216   void *(*xTask)(void*),    /* Routine to run in a separate thread */
217   void *pIn                 /* Argument passed into xTask() */
218 ){
219   SQLiteThread *p;
220 
221   assert( ppThread!=0 );
222   assert( xTask!=0 );
223   *ppThread = 0;
224   p = sqlite3Malloc(sizeof(*p));
225   if( p==0 ) return SQLITE_NOMEM;
226   if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
227     p->xTask = xTask;
228     p->pIn = pIn;
229   }else{
230     p->xTask = 0;
231     p->pResult = xTask(pIn);
232   }
233   *ppThread = p;
234   return SQLITE_OK;
235 }
236 
237 /* Get the results of the thread */
238 int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
239 
240   assert( ppOut!=0 );
241   if( NEVER(p==0) ) return SQLITE_NOMEM;
242   if( p->xTask ){
243     *ppOut = p->xTask(p->pIn);
244   }else{
245     *ppOut = p->pResult;
246   }
247   sqlite3_free(p);
248 
249 #if defined(SQLITE_TEST)
250   {
251     void *pTstAlloc = sqlite3Malloc(10);
252     if (!pTstAlloc) return SQLITE_NOMEM;
253     sqlite3_free(pTstAlloc);
254   }
255 #endif
256 
257   return SQLITE_OK;
258 }
259 
260 #endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
261 /****************************** End Single-Threaded *************************/
262 #endif /* SQLITE_MAX_WORKER_THREADS>0 */
263