blob: f128d69fc2355512e1014ad63c90f9e198123319 [file] [log] [blame]
/*
** 2012 July 21
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
******************************************************************************
**
** This file presents a simple cross-platform threading interface for
** use internally by SQLite.
**
** A "thread" can be created using sqlite3ThreadCreate(). This thread
** runs independently of its creator until it is joined using
** sqlite3ThreadJoin(), at which point it terminates.
**
** Threads do not have to be real. It could be that the work of the
** "thread" is done by the main thread at either the sqlite3ThreadCreate()
** or sqlite3ThreadJoin() call. This is, in fact, what happens in
** single threaded systems. Nothing in SQLite requires multiple threads.
** This interface exists so that applications that want to take advantage
** of multiple cores can do so, while also allowing applications to stay
** single-threaded if desired.
*/
#include "sqliteInt.h"
#if SQLITE_OS_WIN
# include "os_win.h"
#endif
#if SQLITE_MAX_WORKER_THREADS>0
/********************************* Unix Pthreads ****************************/
#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>0
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
#include <pthread.h>
/* A running thread */
struct SQLiteThread {
pthread_t tid; /* Thread ID */
int done; /* Set to true when thread finishes */
void *pOut; /* Result returned by the thread */
void *(*xTask)(void*); /* The thread routine */
void *pIn; /* Argument to the thread */
};
/* Create a new thread */
int sqlite3ThreadCreate(
SQLiteThread **ppThread, /* OUT: Write the thread object here */
void *(*xTask)(void*), /* Routine to run in a separate thread */
void *pIn /* Argument passed into xTask() */
){
SQLiteThread *p;
int rc;
assert( ppThread!=0 );
assert( xTask!=0 );
/* This routine is never used in single-threaded mode */
assert( sqlite3GlobalConfig.bCoreMutex!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
if( p==0 ) return SQLITE_NOMEM_BKPT;
memset(p, 0, sizeof(*p));
p->xTask = xTask;
p->pIn = pIn;
/* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
** function that returns SQLITE_ERROR when passed the argument 200, that
** forces worker threads to run sequentially and deterministically
** for testing purposes. */
if( sqlite3FaultSim(200) ){
rc = 1;
}else{
rc = pthread_create(&p->tid, 0, xTask, pIn);
}
if( rc ){
p->done = 1;
p->pOut = xTask(pIn);
}
*ppThread = p;
return SQLITE_OK;
}
/* Get the results of the thread */
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
int rc;
assert( ppOut!=0 );
if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
if( p->done ){
*ppOut = p->pOut;
rc = SQLITE_OK;
}else{
rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK;
}
sqlite3_free(p);
return rc;
}
#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */
/******************************** End Unix Pthreads *************************/
/********************************* Win32 Threads ****************************/
#if SQLITE_OS_WIN_THREADS
#define SQLITE_THREADS_IMPLEMENTED 1 /* Prevent the single-thread code below */
#include <process.h>
/* A running thread */
struct SQLiteThread {
void *tid; /* The thread handle */
unsigned id; /* The thread identifier */
void *(*xTask)(void*); /* The routine to run as a thread */
void *pIn; /* Argument to xTask */
void *pResult; /* Result of xTask */
};
/* Thread procedure Win32 compatibility shim */
static unsigned __stdcall sqlite3ThreadProc(
void *pArg /* IN: Pointer to the SQLiteThread structure */
){
SQLiteThread *p = (SQLiteThread *)pArg;
assert( p!=0 );
#if 0
/*
** This assert appears to trigger spuriously on certain
** versions of Windows, possibly due to _beginthreadex()
** and/or CreateThread() not fully setting their thread
** ID parameter before starting the thread.
*/
assert( p->id==GetCurrentThreadId() );
#endif
assert( p->xTask!=0 );
p->pResult = p->xTask(p->pIn);
_endthreadex(0);
return 0; /* NOT REACHED */
}
/* Create a new thread */
int sqlite3ThreadCreate(
SQLiteThread **ppThread, /* OUT: Write the thread object here */
void *(*xTask)(void*), /* Routine to run in a separate thread */
void *pIn /* Argument passed into xTask() */
){
SQLiteThread *p;
assert( ppThread!=0 );
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
if( p==0 ) return SQLITE_NOMEM_BKPT;
/* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a
** function that returns SQLITE_ERROR when passed the argument 200, that
** forces worker threads to run sequentially and deterministically
** (via the sqlite3FaultSim() term of the conditional) for testing
** purposes. */
if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){
memset(p, 0, sizeof(*p));
}else{
p->xTask = xTask;
p->pIn = pIn;
p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id);
if( p->tid==0 ){
memset(p, 0, sizeof(*p));
}
}
if( p->xTask==0 ){
p->id = GetCurrentThreadId();
p->pResult = xTask(pIn);
}
*ppThread = p;
return SQLITE_OK;
}
DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */
/* Get the results of the thread */
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
DWORD rc;
BOOL bRc;
assert( ppOut!=0 );
if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
if( p->xTask==0 ){
/* assert( p->id==GetCurrentThreadId() ); */
rc = WAIT_OBJECT_0;
assert( p->tid==0 );
}else{
assert( p->id!=0 && p->id!=GetCurrentThreadId() );
rc = sqlite3Win32Wait((HANDLE)p->tid);
assert( rc!=WAIT_IO_COMPLETION );
bRc = CloseHandle((HANDLE)p->tid);
assert( bRc );
}
if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;
sqlite3_free(p);
return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;
}
#endif /* SQLITE_OS_WIN_THREADS */
/******************************** End Win32 Threads *************************/
/********************************* Single-Threaded **************************/
#ifndef SQLITE_THREADS_IMPLEMENTED
/*
** This implementation does not actually create a new thread. It does the
** work of the thread in the main thread, when either the thread is created
** or when it is joined
*/
/* A running thread */
struct SQLiteThread {
void *(*xTask)(void*); /* The routine to run as a thread */
void *pIn; /* Argument to xTask */
void *pResult; /* Result of xTask */
};
/* Create a new thread */
int sqlite3ThreadCreate(
SQLiteThread **ppThread, /* OUT: Write the thread object here */
void *(*xTask)(void*), /* Routine to run in a separate thread */
void *pIn /* Argument passed into xTask() */
){
SQLiteThread *p;
assert( ppThread!=0 );
assert( xTask!=0 );
*ppThread = 0;
p = sqlite3Malloc(sizeof(*p));
if( p==0 ) return SQLITE_NOMEM_BKPT;
if( (SQLITE_PTR_TO_INT(p)/17)&1 ){
p->xTask = xTask;
p->pIn = pIn;
}else{
p->xTask = 0;
p->pResult = xTask(pIn);
}
*ppThread = p;
return SQLITE_OK;
}
/* Get the results of the thread */
int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){
assert( ppOut!=0 );
if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;
if( p->xTask ){
*ppOut = p->xTask(p->pIn);
}else{
*ppOut = p->pResult;
}
sqlite3_free(p);
#if defined(SQLITE_TEST)
{
void *pTstAlloc = sqlite3Malloc(10);
if (!pTstAlloc) return SQLITE_NOMEM_BKPT;
sqlite3_free(pTstAlloc);
}
#endif
return SQLITE_OK;
}
#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */
/****************************** End Single-Threaded *************************/
#endif /* SQLITE_MAX_WORKER_THREADS>0 */