xref: /sqlite-3.40.0/src/threads.c (revision fad3039c)
1f51446a3Sdrh /*
2f51446a3Sdrh ** 2012 July 21
3f51446a3Sdrh **
4f51446a3Sdrh ** The author disclaims copyright to this source code.  In place of
5f51446a3Sdrh ** a legal notice, here is a blessing:
6f51446a3Sdrh **
7f51446a3Sdrh **    May you do good and not evil.
8f51446a3Sdrh **    May you find forgiveness for yourself and forgive others.
9f51446a3Sdrh **    May you share freely, never taking more than you give.
10f51446a3Sdrh **
11f51446a3Sdrh ******************************************************************************
12f51446a3Sdrh **
13f51446a3Sdrh ** This file presents a simple cross-platform threading interface for
14f51446a3Sdrh ** use internally by SQLite.
15f51446a3Sdrh **
16f51446a3Sdrh ** A "thread" can be created using sqlite3ThreadCreate().  This thread
17f51446a3Sdrh ** runs independently of its creator until it is joined using
18f51446a3Sdrh ** sqlite3ThreadJoin(), at which point it terminates.
19f51446a3Sdrh **
20f51446a3Sdrh ** Threads do not have to be real.  It could be that the work of the
21f51446a3Sdrh ** "thread" is done by the main thread at either the sqlite3ThreadCreate()
22f51446a3Sdrh ** or sqlite3ThreadJoin() call.  This is, in fact, what happens in
23f51446a3Sdrh ** single threaded systems.  Nothing in SQLite requires multiple threads.
24f51446a3Sdrh ** This interface exists so that applications that want to take advantage
25f51446a3Sdrh ** of multiple cores can do so, while also allowing applications to stay
26f51446a3Sdrh ** single-threaded if desired.
27f51446a3Sdrh */
28f51446a3Sdrh #include "sqliteInt.h"
29b13160f7Smistachkin #if SQLITE_OS_WIN
30b13160f7Smistachkin #  include "os_win.h"
31b13160f7Smistachkin #endif
32f51446a3Sdrh 
33b3f56fdbSdan #if SQLITE_MAX_WORKER_THREADS>0
34b3f56fdbSdan 
35f51446a3Sdrh /********************************* Unix Pthreads ****************************/
363c863634Sdrh #if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
37f51446a3Sdrh 
38f51446a3Sdrh #define SQLITE_THREADS_IMPLEMENTED 1  /* Prevent the single-thread code below */
39f51446a3Sdrh #include <pthread.h>
40f51446a3Sdrh 
41f51446a3Sdrh /* A running thread */
42f51446a3Sdrh struct SQLiteThread {
433de4df27Sdrh   pthread_t tid;                 /* Thread ID */
443de4df27Sdrh   int done;                      /* Set to true when thread finishes */
453de4df27Sdrh   void *pOut;                    /* Result returned by the thread */
463de4df27Sdrh   void *(*xTask)(void*);         /* The thread routine */
473de4df27Sdrh   void *pIn;                     /* Argument to the thread */
48f51446a3Sdrh };
49f51446a3Sdrh 
50f51446a3Sdrh /* Create a new thread */
sqlite3ThreadCreate(SQLiteThread ** ppThread,void * (* xTask)(void *),void * pIn)51f51446a3Sdrh int sqlite3ThreadCreate(
52f51446a3Sdrh   SQLiteThread **ppThread,  /* OUT: Write the thread object here */
53f51446a3Sdrh   void *(*xTask)(void*),    /* Routine to run in a separate thread */
54f51446a3Sdrh   void *pIn                 /* Argument passed into xTask() */
55f51446a3Sdrh ){
56f51446a3Sdrh   SQLiteThread *p;
57b92284deSdrh   int rc;
58f51446a3Sdrh 
59da0e4710Smistachkin   assert( ppThread!=0 );
60da0e4710Smistachkin   assert( xTask!=0 );
61cb6effafSdrh   /* This routine is never used in single-threaded mode */
62cb6effafSdrh   assert( sqlite3GlobalConfig.bCoreMutex!=0 );
63cb6effafSdrh 
64da0e4710Smistachkin   *ppThread = 0;
65da0e4710Smistachkin   p = sqlite3Malloc(sizeof(*p));
66*fad3039cSmistachkin   if( p==0 ) return SQLITE_NOMEM_BKPT;
676ddecb75Sdrh   memset(p, 0, sizeof(*p));
683de4df27Sdrh   p->xTask = xTask;
693de4df27Sdrh   p->pIn = pIn;
702ea31b12Sdrh   /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
712ea31b12Sdrh   ** function that returns SQLITE_ERROR when passed the argument 200, that
722ea31b12Sdrh   ** forces worker threads to run sequentially and deterministically
732ea31b12Sdrh   ** for testing purposes. */
74b92284deSdrh   if( sqlite3FaultSim(200) ){
75b92284deSdrh     rc = 1;
76b92284deSdrh   }else{
77b92284deSdrh     rc = pthread_create(&p->tid, 0, xTask, pIn);
78b92284deSdrh   }
79b92284deSdrh   if( rc ){
806ddecb75Sdrh     p->done = 1;
816ddecb75Sdrh     p->pOut = xTask(pIn);
82f51446a3Sdrh   }
83da0e4710Smistachkin   *ppThread = p;
84f51446a3Sdrh   return SQLITE_OK;
85f51446a3Sdrh }
86f51446a3Sdrh 
87f51446a3Sdrh /* Get the results of the thread */
sqlite3ThreadJoin(SQLiteThread * p,void ** ppOut)88f51446a3Sdrh int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
89f51446a3Sdrh   int rc;
90da0e4710Smistachkin 
91da0e4710Smistachkin   assert( ppOut!=0 );
92*fad3039cSmistachkin   if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
936ddecb75Sdrh   if( p->done ){
946ddecb75Sdrh     *ppOut = p->pOut;
956ddecb75Sdrh     rc = SQLITE_OK;
966ddecb75Sdrh   }else{
97cb6effafSdrh     rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK;
986ddecb75Sdrh   }
99f51446a3Sdrh   sqlite3_free(p);
100cb6effafSdrh   return rc;
101f51446a3Sdrh }
102f51446a3Sdrh 
103f51446a3Sdrh #endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
104f51446a3Sdrh /******************************** End Unix Pthreads *************************/
105f51446a3Sdrh 
106f51446a3Sdrh 
107da0e4710Smistachkin /********************************* Win32 Threads ****************************/
10889ea0d37Smistachkin #if SQLITE_OS_WIN_THREADS
109da0e4710Smistachkin 
110da0e4710Smistachkin #define SQLITE_THREADS_IMPLEMENTED 1  /* Prevent the single-thread code below */
111da0e4710Smistachkin #include <process.h>
112da0e4710Smistachkin 
113da0e4710Smistachkin /* A running thread */
114da0e4710Smistachkin struct SQLiteThread {
115ab993380Sdrh   void *tid;               /* The thread handle */
116b1ac2bc8Smistachkin   unsigned id;             /* The thread identifier */
117da0e4710Smistachkin   void *(*xTask)(void*);   /* The routine to run as a thread */
118da0e4710Smistachkin   void *pIn;               /* Argument to xTask */
119da0e4710Smistachkin   void *pResult;           /* Result of xTask */
120da0e4710Smistachkin };
121da0e4710Smistachkin 
122da0e4710Smistachkin /* Thread procedure Win32 compatibility shim */
sqlite3ThreadProc(void * pArg)123b1ac2bc8Smistachkin static unsigned __stdcall sqlite3ThreadProc(
124da0e4710Smistachkin   void *pArg  /* IN: Pointer to the SQLiteThread structure */
125da0e4710Smistachkin ){
126da0e4710Smistachkin   SQLiteThread *p = (SQLiteThread *)pArg;
127da0e4710Smistachkin 
128da0e4710Smistachkin   assert( p!=0 );
1290479c6abSmistachkin #if 0
1300479c6abSmistachkin   /*
1310479c6abSmistachkin   ** This assert appears to trigger spuriously on certain
1320479c6abSmistachkin   ** versions of Windows, possibly due to _beginthreadex()
1330479c6abSmistachkin   ** and/or CreateThread() not fully setting their thread
1340479c6abSmistachkin   ** ID parameter before starting the thread.
1350479c6abSmistachkin   */
136b1ac2bc8Smistachkin   assert( p->id==GetCurrentThreadId() );
1370479c6abSmistachkin #endif
138da0e4710Smistachkin   assert( p->xTask!=0 );
139da0e4710Smistachkin   p->pResult = p->xTask(p->pIn);
140b1ac2bc8Smistachkin 
141b1ac2bc8Smistachkin   _endthreadex(0);
142b1ac2bc8Smistachkin   return 0; /* NOT REACHED */
143da0e4710Smistachkin }
144da0e4710Smistachkin 
145da0e4710Smistachkin /* Create a new thread */
sqlite3ThreadCreate(SQLiteThread ** ppThread,void * (* xTask)(void *),void * pIn)146da0e4710Smistachkin int sqlite3ThreadCreate(
147da0e4710Smistachkin   SQLiteThread **ppThread,  /* OUT: Write the thread object here */
148da0e4710Smistachkin   void *(*xTask)(void*),    /* Routine to run in a separate thread */
149da0e4710Smistachkin   void *pIn                 /* Argument passed into xTask() */
150da0e4710Smistachkin ){
151da0e4710Smistachkin   SQLiteThread *p;
152da0e4710Smistachkin 
153da0e4710Smistachkin   assert( ppThread!=0 );
154da0e4710Smistachkin   assert( xTask!=0 );
155da0e4710Smistachkin   *ppThread = 0;
156da0e4710Smistachkin   p = sqlite3Malloc(sizeof(*p));
157*fad3039cSmistachkin   if( p==0 ) return SQLITE_NOMEM_BKPT;
1582ea31b12Sdrh   /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
1592ea31b12Sdrh   ** function that returns SQLITE_ERROR when passed the argument 200, that
1602ea31b12Sdrh   ** forces worker threads to run sequentially and deterministically
1612ea31b12Sdrh   ** (via the sqlite3FaultSim() term of the conditional) for testing
1622ea31b12Sdrh   ** purposes. */
1632ea31b12Sdrh   if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){
1646ddecb75Sdrh     memset(p, 0, sizeof(*p));
1656ddecb75Sdrh   }else{
1666ddecb75Sdrh     p->xTask = xTask;
1676ddecb75Sdrh     p->pIn = pIn;
168ab993380Sdrh     p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id);
169acd57ea0Smistachkin     if( p->tid==0 ){
1706ddecb75Sdrh       memset(p, 0, sizeof(*p));
1716ddecb75Sdrh     }
1726ddecb75Sdrh   }
1736ddecb75Sdrh   if( p->xTask==0 ){
174b1ac2bc8Smistachkin     p->id = GetCurrentThreadId();
1756ddecb75Sdrh     p->pResult = xTask(pIn);
176da0e4710Smistachkin   }
177da0e4710Smistachkin   *ppThread = p;
178da0e4710Smistachkin   return SQLITE_OK;
179da0e4710Smistachkin }
180da0e4710Smistachkin 
181b1ac2bc8Smistachkin DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */
1822b49327dSdrh 
183da0e4710Smistachkin /* Get the results of the thread */
sqlite3ThreadJoin(SQLiteThread * p,void ** ppOut)184da0e4710Smistachkin int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
185da0e4710Smistachkin   DWORD rc;
186b1ac2bc8Smistachkin   BOOL bRc;
187da0e4710Smistachkin 
188da0e4710Smistachkin   assert( ppOut!=0 );
189*fad3039cSmistachkin   if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
1906ddecb75Sdrh   if( p->xTask==0 ){
19117db155fSdrh     /* assert( p->id==GetCurrentThreadId() ); */
192f7da5555Smistachkin     rc = WAIT_OBJECT_0;
1937c2231cfSmistachkin     assert( p->tid==0 );
1946ddecb75Sdrh   }else{
195b1ac2bc8Smistachkin     assert( p->id!=0 && p->id!=GetCurrentThreadId() );
196da0e4710Smistachkin     rc = sqlite3Win32Wait((HANDLE)p->tid);
197a806475fSmistachkin     assert( rc!=WAIT_IO_COMPLETION );
198b1ac2bc8Smistachkin     bRc = CloseHandle((HANDLE)p->tid);
199b1ac2bc8Smistachkin     assert( bRc );
2006ddecb75Sdrh   }
201da0e4710Smistachkin   if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
202da0e4710Smistachkin   sqlite3_free(p);
203da0e4710Smistachkin   return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
204da0e4710Smistachkin }
205da0e4710Smistachkin 
20689ea0d37Smistachkin #endif /* SQLITE_OS_WIN_THREADS */
207da0e4710Smistachkin /******************************** End Win32 Threads *************************/
208da0e4710Smistachkin 
209da0e4710Smistachkin 
210f51446a3Sdrh /********************************* Single-Threaded **************************/
211f51446a3Sdrh #ifndef SQLITE_THREADS_IMPLEMENTED
212f51446a3Sdrh /*
213f51446a3Sdrh ** This implementation does not actually create a new thread.  It does the
214f51446a3Sdrh ** work of the thread in the main thread, when either the thread is created
215f51446a3Sdrh ** or when it is joined
216f51446a3Sdrh */
217f51446a3Sdrh 
218f51446a3Sdrh /* A running thread */
219f51446a3Sdrh struct SQLiteThread {
220f51446a3Sdrh   void *(*xTask)(void*);   /* The routine to run as a thread */
221f51446a3Sdrh   void *pIn;               /* Argument to xTask */
222f51446a3Sdrh   void *pResult;           /* Result of xTask */
223f51446a3Sdrh };
224f51446a3Sdrh 
225f51446a3Sdrh /* Create a new thread */
sqlite3ThreadCreate(SQLiteThread ** ppThread,void * (* xTask)(void *),void * pIn)226f51446a3Sdrh int sqlite3ThreadCreate(
227f51446a3Sdrh   SQLiteThread **ppThread,  /* OUT: Write the thread object here */
228f51446a3Sdrh   void *(*xTask)(void*),    /* Routine to run in a separate thread */
229f51446a3Sdrh   void *pIn                 /* Argument passed into xTask() */
230f51446a3Sdrh ){
231f51446a3Sdrh   SQLiteThread *p;
232da0e4710Smistachkin 
233da0e4710Smistachkin   assert( ppThread!=0 );
234da0e4710Smistachkin   assert( xTask!=0 );
235da0e4710Smistachkin   *ppThread = 0;
236da0e4710Smistachkin   p = sqlite3Malloc(sizeof(*p));
237*fad3039cSmistachkin   if( p==0 ) return SQLITE_NOMEM_BKPT;
238f51446a3Sdrh   if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
239f51446a3Sdrh     p->xTask = xTask;
240f51446a3Sdrh     p->pIn = pIn;
241f51446a3Sdrh   }else{
242f51446a3Sdrh     p->xTask = 0;
243f51446a3Sdrh     p->pResult = xTask(pIn);
244f51446a3Sdrh   }
245da0e4710Smistachkin   *ppThread = p;
246da0e4710Smistachkin   return SQLITE_OK;
247f51446a3Sdrh }
248f51446a3Sdrh 
249f51446a3Sdrh /* Get the results of the thread */
sqlite3ThreadJoin(SQLiteThread * p,void ** ppOut)250f51446a3Sdrh int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
251d94d4ee7Sdan 
252da0e4710Smistachkin   assert( ppOut!=0 );
253*fad3039cSmistachkin   if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
254f51446a3Sdrh   if( p->xTask ){
255da0e4710Smistachkin     *ppOut = p->xTask(p->pIn);
256f51446a3Sdrh   }else{
257f51446a3Sdrh     *ppOut = p->pResult;
258f51446a3Sdrh   }
259f51446a3Sdrh   sqlite3_free(p);
260d94d4ee7Sdan 
261d94d4ee7Sdan #if defined(SQLITE_TEST)
262d94d4ee7Sdan   {
263d94d4ee7Sdan     void *pTstAlloc = sqlite3Malloc(10);
264*fad3039cSmistachkin     if (!pTstAlloc) return SQLITE_NOMEM_BKPT;
265d94d4ee7Sdan     sqlite3_free(pTstAlloc);
266d94d4ee7Sdan   }
267d94d4ee7Sdan #endif
268d94d4ee7Sdan 
269f51446a3Sdrh   return SQLITE_OK;
270f51446a3Sdrh }
271f51446a3Sdrh 
272f51446a3Sdrh #endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
273f51446a3Sdrh /****************************** End Single-Threaded *************************/
274b3f56fdbSdan #endif /* SQLITE_MAX_WORKER_THREADS>0 */
275