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