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