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