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