Team Ai
Modelpublic

AryaWu/sqlite

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
threads.c275 linesDownload Raw Back to src
1/*2** 2012 July 213**4** The author disclaims copyright to this source code.  In place of5** 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 for14** use internally by SQLite.15**16** A "thread" can be created using sqlite3ThreadCreate().  This thread17** runs independently of its creator until it is joined using18** sqlite3ThreadJoin(), at which point it terminates.19**20** Threads do not have to be real.  It could be that the work of the21** "thread" is done by the main thread at either the sqlite3ThreadCreate()22** or sqlite3ThreadJoin() call.  This is, in fact, what happens in23** single threaded systems.  Nothing in SQLite requires multiple threads.24** This interface exists so that applications that want to take advantage25** of multiple cores can do so, while also allowing applications to stay26** single-threaded if desired.27*/28#include "sqliteInt.h"29#if SQLITE_OS_WIN30#  include "os_win.h"31#endif32 33#if SQLITE_MAX_WORKER_THREADS>034 35/********************************* Unix Pthreads ****************************/36#if SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) && SQLITE_THREADSAFE>037 38#define SQLITE_THREADS_IMPLEMENTED 1  /* Prevent the single-thread code below */39#include <pthread.h>40 41/* A running thread */42struct SQLiteThread {43  pthread_t tid;                 /* Thread ID */44  int done;                      /* Set to true when thread finishes */45  void *pOut;                    /* Result returned by the thread */46  void *(*xTask)(void*);         /* The thread routine */47  void *pIn;                     /* Argument to the thread */48};49 50/* Create a new thread */51int sqlite3ThreadCreate(52  SQLiteThread **ppThread,  /* OUT: Write the thread object here */53  void *(*xTask)(void*),    /* Routine to run in a separate thread */54  void *pIn                 /* Argument passed into xTask() */55){56  SQLiteThread *p;57  int rc;58 59  assert( ppThread!=0 );60  assert( xTask!=0 );61  /* This routine is never used in single-threaded mode */62  assert( sqlite3GlobalConfig.bCoreMutex!=0 );63 64  *ppThread = 0;65  p = sqlite3Malloc(sizeof(*p));66  if( p==0 ) return SQLITE_NOMEM_BKPT;67  memset(p, 0, sizeof(*p));68  p->xTask = xTask;69  p->pIn = pIn;70  /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a 71  ** function that returns SQLITE_ERROR when passed the argument 200, that72  ** forces worker threads to run sequentially and deterministically 73  ** for testing purposes. */74  if( sqlite3FaultSim(200) ){75    rc = 1;76  }else{    77    rc = pthread_create(&p->tid, 0, xTask, pIn);78  }79  if( rc ){80    p->done = 1;81    p->pOut = xTask(pIn);82  }83  *ppThread = p;84  return SQLITE_OK;85}86 87/* Get the results of the thread */88int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){89  int rc;90 91  assert( ppOut!=0 );92  if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;93  if( p->done ){94    *ppOut = p->pOut;95    rc = SQLITE_OK;96  }else{97    rc = pthread_join(p->tid, ppOut) ? SQLITE_ERROR : SQLITE_OK;98  }99  sqlite3_free(p);100  return rc;101}102 103#endif /* SQLITE_OS_UNIX && defined(SQLITE_MUTEX_PTHREADS) */104/******************************** End Unix Pthreads *************************/105 106 107/********************************* Win32 Threads ****************************/108#if SQLITE_OS_WIN_THREADS109 110#define SQLITE_THREADS_IMPLEMENTED 1  /* Prevent the single-thread code below */111#include <process.h>112 113/* A running thread */114struct SQLiteThread {115  void *tid;               /* The thread handle */116  unsigned id;             /* The thread identifier */117  void *(*xTask)(void*);   /* The routine to run as a thread */118  void *pIn;               /* Argument to xTask */119  void *pResult;           /* Result of xTask */120};121 122/* Thread procedure Win32 compatibility shim */123static unsigned __stdcall sqlite3ThreadProc(124  void *pArg  /* IN: Pointer to the SQLiteThread structure */125){126  SQLiteThread *p = (SQLiteThread *)pArg;127 128  assert( p!=0 );129#if 0130  /*131  ** This assert appears to trigger spuriously on certain132  ** versions of Windows, possibly due to _beginthreadex()133  ** and/or CreateThread() not fully setting their thread134  ** ID parameter before starting the thread.135  */136  assert( p->id==GetCurrentThreadId() );137#endif138  assert( p->xTask!=0 );139  p->pResult = p->xTask(p->pIn);140 141  _endthreadex(0);142  return 0; /* NOT REACHED */143}144 145/* Create a new thread */146int sqlite3ThreadCreate(147  SQLiteThread **ppThread,  /* OUT: Write the thread object here */148  void *(*xTask)(void*),    /* Routine to run in a separate thread */149  void *pIn                 /* Argument passed into xTask() */150){151  SQLiteThread *p;152 153  assert( ppThread!=0 );154  assert( xTask!=0 );155  *ppThread = 0;156  p = sqlite3Malloc(sizeof(*p));157  if( p==0 ) return SQLITE_NOMEM_BKPT;158  /* If the SQLITE_TESTCTRL_FAULT_INSTALL callback is registered to a 159  ** function that returns SQLITE_ERROR when passed the argument 200, that160  ** forces worker threads to run sequentially and deterministically 161  ** (via the sqlite3FaultSim() term of the conditional) for testing162  ** purposes. */163  if( sqlite3GlobalConfig.bCoreMutex==0 || sqlite3FaultSim(200) ){164    memset(p, 0, sizeof(*p));165  }else{166    p->xTask = xTask;167    p->pIn = pIn;168    p->tid = (void*)_beginthreadex(0, 0, sqlite3ThreadProc, p, 0, &p->id);169    if( p->tid==0 ){170      memset(p, 0, sizeof(*p));171    }172  }173  if( p->xTask==0 ){174    p->id = GetCurrentThreadId();175    p->pResult = xTask(pIn);176  }177  *ppThread = p;178  return SQLITE_OK;179}180 181DWORD sqlite3Win32Wait(HANDLE hObject); /* os_win.c */182 183/* Get the results of the thread */184int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){185  DWORD rc;186  BOOL bRc;187 188  assert( ppOut!=0 );189  if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;190  if( p->xTask==0 ){191    /* assert( p->id==GetCurrentThreadId() ); */192    rc = WAIT_OBJECT_0;193    assert( p->tid==0 );194  }else{195    assert( p->id!=0 && p->id!=GetCurrentThreadId() );196    rc = sqlite3Win32Wait((HANDLE)p->tid);197    assert( rc!=WAIT_IO_COMPLETION );198    bRc = CloseHandle((HANDLE)p->tid);199    assert( bRc );200  }201  if( rc==WAIT_OBJECT_0 ) *ppOut = p->pResult;202  sqlite3_free(p);203  return (rc==WAIT_OBJECT_0) ? SQLITE_OK : SQLITE_ERROR;204}205 206#endif /* SQLITE_OS_WIN_THREADS */207/******************************** End Win32 Threads *************************/208 209 210/********************************* Single-Threaded **************************/211#ifndef SQLITE_THREADS_IMPLEMENTED212/*213** This implementation does not actually create a new thread.  It does the214** work of the thread in the main thread, when either the thread is created215** or when it is joined216*/217 218/* A running thread */219struct SQLiteThread {220  void *(*xTask)(void*);   /* The routine to run as a thread */221  void *pIn;               /* Argument to xTask */222  void *pResult;           /* Result of xTask */223};224 225/* Create a new thread */226int sqlite3ThreadCreate(227  SQLiteThread **ppThread,  /* OUT: Write the thread object here */228  void *(*xTask)(void*),    /* Routine to run in a separate thread */229  void *pIn                 /* Argument passed into xTask() */230){231  SQLiteThread *p;232 233  assert( ppThread!=0 );234  assert( xTask!=0 );235  *ppThread = 0;236  p = sqlite3Malloc(sizeof(*p));237  if( p==0 ) return SQLITE_NOMEM_BKPT;238  if( (SQLITE_PTR_TO_INT(p)/17)&1 ){239    p->xTask = xTask;240    p->pIn = pIn;241  }else{242    p->xTask = 0;243    p->pResult = xTask(pIn);244  }245  *ppThread = p;246  return SQLITE_OK;247}248 249/* Get the results of the thread */250int sqlite3ThreadJoin(SQLiteThread *p, void **ppOut){251 252  assert( ppOut!=0 );253  if( NEVER(p==0) ) return SQLITE_NOMEM_BKPT;254  if( p->xTask ){255    *ppOut = p->xTask(p->pIn);256  }else{257    *ppOut = p->pResult;258  }259  sqlite3_free(p);260 261#if defined(SQLITE_TEST)262  {263    void *pTstAlloc = sqlite3Malloc(10);264    if (!pTstAlloc) return SQLITE_NOMEM_BKPT;265    sqlite3_free(pTstAlloc);266  }267#endif268 269  return SQLITE_OK;270}271 272#endif /* !defined(SQLITE_THREADS_IMPLEMENTED) */273/****************************** End Single-Threaded *************************/274#endif /* SQLITE_MAX_WORKER_THREADS>0 */275