/ Check-in [5360ecb0]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Re-integrate the recent changes from the 'winMutex' branch back into the Win32 mutex subsystem.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 5360ecb0b8891d0c27f3f02d81b6c7b548361a10
User & Date: mistachkin 2014-07-30 23:11:16
Context
2014-07-31
15:44
Deactivate the DISTINCT in a SELECT on the right-hand side of an IN operator, since it should not make any difference in the output but dues consume extra memory and CPU time. check-in: f4cb5365 user: drh tags: trunk
2014-07-30
23:11
Re-integrate the recent changes from the 'winMutex' branch back into the Win32 mutex subsystem. check-in: 5360ecb0 user: mistachkin tags: trunk
21:10
Add three new static mutexes for use by the application. This is a partial import of changes from the threads branch. check-in: 3aad0196 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/mutex_w32.c.

     5      5   ** a legal notice, here is a blessing:
     6      6   **
     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12         -** This file contains the C functions that implement mutexes for win32
           12  +** This file contains the C functions that implement mutexes for Win32.
    13     13   */
    14     14   #include "sqliteInt.h"
    15     15   
    16     16   #if SQLITE_OS_WIN
           17  +/*
           18  +** Include code that is common to all os_*.c files
           19  +*/
           20  +#include "os_common.h"
           21  +
    17     22   /*
    18     23   ** Include the header file for the Windows VFS.
    19     24   */
    20     25   #include "os_win.h"
    21     26   #endif
    22     27   
    23     28   /*
    24     29   ** The code in this file is only used if we are compiling multithreaded
    25         -** on a win32 system.
           30  +** on a Win32 system.
    26     31   */
    27     32   #ifdef SQLITE_MUTEX_W32
    28     33   
    29     34   /*
    30     35   ** Each recursive mutex is an instance of the following structure.
    31     36   */
    32     37   struct sqlite3_mutex {
    33     38     CRITICAL_SECTION mutex;    /* Mutex controlling the lock */
    34     39     int id;                    /* Mutex type */
    35     40   #ifdef SQLITE_DEBUG
    36     41     volatile int nRef;         /* Number of enterances */
    37     42     volatile DWORD owner;      /* Thread holding this mutex */
    38         -  int trace;                 /* True to trace changes */
           43  +  volatile int trace;        /* True to trace changes */
    39     44   #endif
    40     45   };
    41         -#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
    42         -#ifdef SQLITE_DEBUG
    43         -#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, 0L, (DWORD)0, 0 }
    44         -#else
    45         -#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
    46         -#endif
    47     46   
    48     47   /*
    49         -** Return true (non-zero) if we are running under WinNT, Win2K, WinXP,
    50         -** or WinCE.  Return false (zero) for Win95, Win98, or WinME.
    51         -**
    52         -** Here is an interesting observation:  Win95, Win98, and WinME lack
    53         -** the LockFileEx() API.  But we can still statically link against that
    54         -** API as long as we don't call it win running Win95/98/ME.  A call to
    55         -** this routine is used to determine if the host is Win95/98/ME or
    56         -** WinNT/2K/XP so that we will know whether or not we can safely call
    57         -** the LockFileEx() API.
    58         -**
    59         -** mutexIsNT() is only used for the TryEnterCriticalSection() API call,
    60         -** which is only available if your application was compiled with 
    61         -** _WIN32_WINNT defined to a value >= 0x0400.  Currently, the only
    62         -** call to TryEnterCriticalSection() is #ifdef'ed out, so #ifdef 
    63         -** this out as well.
           48  +** These are the initializer values used when declaring a "static" mutex
           49  +** on Win32.  It should be noted that all mutexes require initialization
           50  +** on the Win32 platform.
    64     51   */
    65         -#if 0
    66         -#if SQLITE_OS_WINCE || SQLITE_OS_WINRT
    67         -# define mutexIsNT()  (1)
           52  +#define SQLITE_W32_MUTEX_INITIALIZER { 0 }
           53  +
           54  +#ifdef SQLITE_DEBUG
           55  +#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0, \
           56  +                                    0L, (DWORD)0, 0 }
    68     57   #else
    69         -  static int mutexIsNT(void){
    70         -    static int osType = 0;
    71         -    if( osType==0 ){
    72         -      OSVERSIONINFO sInfo;
    73         -      sInfo.dwOSVersionInfoSize = sizeof(sInfo);
    74         -      GetVersionEx(&sInfo);
    75         -      osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
    76         -    }
    77         -    return osType==2;
    78         -  }
    79         -#endif /* SQLITE_OS_WINCE || SQLITE_OS_WINRT */
           58  +#define SQLITE3_MUTEX_INITIALIZER { SQLITE_W32_MUTEX_INITIALIZER, 0 }
    80     59   #endif
    81     60   
    82     61   #ifdef SQLITE_DEBUG
    83     62   /*
    84     63   ** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routine are
    85     64   ** intended for use only inside assert() statements.
    86     65   */
    87     66   static int winMutexHeld(sqlite3_mutex *p){
    88     67     return p->nRef!=0 && p->owner==GetCurrentThreadId();
    89     68   }
           69  +
    90     70   static int winMutexNotheld2(sqlite3_mutex *p, DWORD tid){
    91     71     return p->nRef==0 || p->owner!=tid;
    92     72   }
           73  +
    93     74   static int winMutexNotheld(sqlite3_mutex *p){
    94         -  DWORD tid = GetCurrentThreadId(); 
           75  +  DWORD tid = GetCurrentThreadId();
    95     76     return winMutexNotheld2(p, tid);
    96     77   }
    97     78   #endif
    98         -
    99     79   
   100     80   /*
   101     81   ** Initialize and deinitialize the mutex subsystem.
   102     82   */
   103     83   static sqlite3_mutex winMutex_staticMutexes[] = {
   104     84     SQLITE3_MUTEX_INITIALIZER,
   105     85     SQLITE3_MUTEX_INITIALIZER,
................................................................................
   107     87     SQLITE3_MUTEX_INITIALIZER,
   108     88     SQLITE3_MUTEX_INITIALIZER,
   109     89     SQLITE3_MUTEX_INITIALIZER,
   110     90     SQLITE3_MUTEX_INITIALIZER,
   111     91     SQLITE3_MUTEX_INITIALIZER,
   112     92     SQLITE3_MUTEX_INITIALIZER
   113     93   };
           94  +
   114     95   static int winMutex_isInit = 0;
   115         -/* As winMutexInit() and winMutexEnd() are called as part
   116         -** of the sqlite3_initialize and sqlite3_shutdown()
   117         -** processing, the "interlocked" magic is probably not
   118         -** strictly necessary.
           96  +
           97  +/* As the winMutexInit() and winMutexEnd() functions are called as part
           98  +** of the sqlite3_initialize() and sqlite3_shutdown() processing, the
           99  +** "interlocked" magic used here is probably not strictly necessary.
   119    100   */
   120    101   static LONG winMutex_lock = 0;
   121    102   
          103  +int sqlite3_win32_is_nt(void); /* os_win.c */
   122    104   void sqlite3_win32_sleep(DWORD milliseconds); /* os_win.c */
   123    105   
   124         -static int winMutexInit(void){ 
          106  +static int winMutexInit(void){
   125    107     /* The first to increment to 1 does actual initialization */
   126    108     if( InterlockedCompareExchange(&winMutex_lock, 1, 0)==0 ){
   127    109       int i;
   128    110       for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
   129    111   #if SQLITE_OS_WINRT
   130    112         InitializeCriticalSectionEx(&winMutex_staticMutexes[i].mutex, 0, 0);
   131    113   #else
   132    114         InitializeCriticalSection(&winMutex_staticMutexes[i].mutex);
   133    115   #endif
   134    116       }
   135    117       winMutex_isInit = 1;
   136    118     }else{
   137         -    /* Someone else is in the process of initing the static mutexes */
          119  +    /* Another thread is (in the process of) initializing the static
          120  +    ** mutexes */
   138    121       while( !winMutex_isInit ){
   139    122         sqlite3_win32_sleep(1);
   140    123       }
   141    124     }
   142         -  return SQLITE_OK; 
          125  +  return SQLITE_OK;
   143    126   }
   144    127   
   145         -static int winMutexEnd(void){ 
   146         -  /* The first to decrement to 0 does actual shutdown 
          128  +static int winMutexEnd(void){
          129  +  /* The first to decrement to 0 does actual shutdown
   147    130     ** (which should be the last to shutdown.) */
   148    131     if( InterlockedCompareExchange(&winMutex_lock, 0, 1)==1 ){
   149    132       if( winMutex_isInit==1 ){
   150    133         int i;
   151    134         for(i=0; i<ArraySize(winMutex_staticMutexes); i++){
   152    135           DeleteCriticalSection(&winMutex_staticMutexes[i].mutex);
   153    136         }
   154    137         winMutex_isInit = 0;
   155    138       }
   156    139     }
   157         -  return SQLITE_OK; 
          140  +  return SQLITE_OK;
   158    141   }
   159    142   
   160    143   /*
   161    144   ** The sqlite3_mutex_alloc() routine allocates a new
   162    145   ** mutex and returns a pointer to it.  If it returns NULL
   163    146   ** that means that a mutex could not be allocated.  SQLite
   164    147   ** will unwind its stack and return an error.  The argument
................................................................................
   194    177   ** may add additional static mutexes.  Static mutexes are for internal
   195    178   ** use by SQLite only.  Applications that use SQLite mutexes should
   196    179   ** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
   197    180   ** SQLITE_MUTEX_RECURSIVE.
   198    181   **
   199    182   ** Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
   200    183   ** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
   201         -** returns a different mutex on every call.  But for the static 
          184  +** returns a different mutex on every call.  But for the static
   202    185   ** mutex types, the same mutex is returned on every call that has
   203    186   ** the same type number.
   204    187   */
   205    188   static sqlite3_mutex *winMutexAlloc(int iType){
   206    189     sqlite3_mutex *p;
   207    190   
   208    191     switch( iType ){
   209    192       case SQLITE_MUTEX_FAST:
   210    193       case SQLITE_MUTEX_RECURSIVE: {
   211    194         p = sqlite3MallocZero( sizeof(*p) );
   212         -      if( p ){  
          195  +      if( p ){
   213    196   #ifdef SQLITE_DEBUG
   214    197           p->id = iType;
          198  +#ifdef SQLITE_WIN32_MUTEX_TRACE_DYNAMIC
          199  +        p->trace = 1;
          200  +#endif
   215    201   #endif
   216    202   #if SQLITE_OS_WINRT
   217    203           InitializeCriticalSectionEx(&p->mutex, 0, 0);
   218    204   #else
   219    205           InitializeCriticalSection(&p->mutex);
   220    206   #endif
   221    207         }
   222    208         break;
   223    209       }
   224    210       default: {
   225         -      assert( winMutex_isInit==1 );
   226    211         assert( iType-2 >= 0 );
   227    212         assert( iType-2 < ArraySize(winMutex_staticMutexes) );
          213  +      assert( winMutex_isInit==1 );
   228    214         p = &winMutex_staticMutexes[iType-2];
   229    215   #ifdef SQLITE_DEBUG
   230    216         p->id = iType;
          217  +#ifdef SQLITE_WIN32_MUTEX_TRACE_STATIC
          218  +      p->trace = 1;
          219  +#endif
   231    220   #endif
   232    221         break;
   233    222       }
   234    223     }
   235    224     return p;
   236    225   }
   237    226   
................................................................................
   239    228   /*
   240    229   ** This routine deallocates a previously
   241    230   ** allocated mutex.  SQLite is careful to deallocate every
   242    231   ** mutex that it allocates.
   243    232   */
   244    233   static void winMutexFree(sqlite3_mutex *p){
   245    234     assert( p );
          235  +#ifdef SQLITE_DEBUG
   246    236     assert( p->nRef==0 && p->owner==0 );
   247    237     assert( p->id==SQLITE_MUTEX_FAST || p->id==SQLITE_MUTEX_RECURSIVE );
          238  +#endif
   248    239     assert( winMutex_isInit==1 );
   249    240     DeleteCriticalSection(&p->mutex);
   250    241     sqlite3_free(p);
   251    242   }
   252    243   
   253    244   /*
   254    245   ** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
................................................................................
   258    249   ** upon successful entry.  Mutexes created using SQLITE_MUTEX_RECURSIVE can
   259    250   ** be entered multiple times by the same thread.  In such cases the,
   260    251   ** mutex must be exited an equal number of times before another thread
   261    252   ** can enter.  If the same thread tries to enter any other kind of mutex
   262    253   ** more than once, the behavior is undefined.
   263    254   */
   264    255   static void winMutexEnter(sqlite3_mutex *p){
          256  +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
          257  +  DWORD tid = GetCurrentThreadId();
          258  +#endif
   265    259   #ifdef SQLITE_DEBUG
   266         -  DWORD tid = GetCurrentThreadId(); 
          260  +  assert( p );
   267    261     assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
          262  +#else
          263  +  assert( p );
   268    264   #endif
   269    265     assert( winMutex_isInit==1 );
   270    266     EnterCriticalSection(&p->mutex);
   271    267   #ifdef SQLITE_DEBUG
   272    268     assert( p->nRef>0 || p->owner==0 );
   273         -  p->owner = tid; 
          269  +  p->owner = tid;
   274    270     p->nRef++;
   275    271     if( p->trace ){
   276         -    printf("enter mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
          272  +    OSTRACE(("ENTER-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
          273  +             tid, p, p->trace, p->nRef));
   277    274     }
   278    275   #endif
   279    276   }
          277  +
   280    278   static int winMutexTry(sqlite3_mutex *p){
   281         -#ifndef NDEBUG
   282         -  DWORD tid = GetCurrentThreadId(); 
          279  +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
          280  +  DWORD tid = GetCurrentThreadId();
   283    281   #endif
   284    282     int rc = SQLITE_BUSY;
          283  +  assert( p );
   285    284     assert( p->id==SQLITE_MUTEX_RECURSIVE || winMutexNotheld2(p, tid) );
   286    285     /*
   287    286     ** The sqlite3_mutex_try() routine is very rarely used, and when it
   288    287     ** is used it is merely an optimization.  So it is OK for it to always
   289         -  ** fail.  
          288  +  ** fail.
   290    289     **
   291    290     ** The TryEnterCriticalSection() interface is only available on WinNT.
   292    291     ** And some windows compilers complain if you try to use it without
   293    292     ** first doing some #defines that prevent SQLite from building on Win98.
   294    293     ** For that reason, we will omit this optimization for now.  See
   295    294     ** ticket #2685.
   296    295     */
   297         -#if 0
          296  +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0400
   298    297     assert( winMutex_isInit==1 );
   299         -  if( mutexIsNT() && TryEnterCriticalSection(&p->mutex) ){
          298  +  if( sqlite3_win32_is_nt() && TryEnterCriticalSection(&p->mutex) ){
          299  +#ifdef SQLITE_DEBUG
   300    300       p->owner = tid;
   301    301       p->nRef++;
          302  +#endif
   302    303       rc = SQLITE_OK;
   303    304     }
   304    305   #else
   305    306     UNUSED_PARAMETER(p);
   306    307   #endif
   307    308   #ifdef SQLITE_DEBUG
   308         -  if( rc==SQLITE_OK && p->trace ){
   309         -    printf("try mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
          309  +  if( p->trace ){
          310  +    OSTRACE(("TRY-MUTEX tid=%lu, mutex=%p (%d), owner=%lu, nRef=%d, rc=%s\n",
          311  +             tid, p, p->trace, p->owner, p->nRef, sqlite3ErrName(rc)));
   310    312     }
   311    313   #endif
   312    314     return rc;
   313    315   }
   314    316   
   315    317   /*
   316    318   ** The sqlite3_mutex_leave() routine exits a mutex that was
   317    319   ** previously entered by the same thread.  The behavior
   318    320   ** is undefined if the mutex is not currently entered or
   319    321   ** is not currently allocated.  SQLite will never do either.
   320    322   */
   321    323   static void winMutexLeave(sqlite3_mutex *p){
   322         -#ifndef NDEBUG
          324  +#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
   323    325     DWORD tid = GetCurrentThreadId();
          326  +#endif
          327  +  assert( p );
          328  +#ifdef SQLITE_DEBUG
   324    329     assert( p->nRef>0 );
   325    330     assert( p->owner==tid );
   326    331     p->nRef--;
   327    332     if( p->nRef==0 ) p->owner = 0;
   328    333     assert( p->nRef==0 || p->id==SQLITE_MUTEX_RECURSIVE );
   329    334   #endif
   330    335     assert( winMutex_isInit==1 );
   331    336     LeaveCriticalSection(&p->mutex);
   332    337   #ifdef SQLITE_DEBUG
   333    338     if( p->trace ){
   334         -    printf("leave mutex %p (%d) with nRef=%d\n", p, p->trace, p->nRef);
          339  +    OSTRACE(("LEAVE-MUTEX tid=%lu, mutex=%p (%d), nRef=%d\n",
          340  +             tid, p, p->trace, p->nRef));
   335    341     }
   336    342   #endif
   337    343   }
   338    344   
   339    345   sqlite3_mutex_methods const *sqlite3DefaultMutex(void){
   340    346     static const sqlite3_mutex_methods sMutex = {
   341    347       winMutexInit,
................................................................................
   349    355       winMutexHeld,
   350    356       winMutexNotheld
   351    357   #else
   352    358       0,
   353    359       0
   354    360   #endif
   355    361     };
   356         -
   357    362     return &sMutex;
   358    363   }
          364  +
   359    365   #endif /* SQLITE_MUTEX_W32 */