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