/ Check-in [51348b82]
Login

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

Overview
Comment:Fix a segfault in sqlite3OsLock() (CVS 1525)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:51348b82c4d5801091537b80059d770410774905
User & Date: danielk1977 2004-06-02 06:30:16
Context
2004-06-03
16:08
Untested updates to support atomic multi-file transactions (CVS 1526) check-in: d57e5252 user: danielk1977 tags: trunk
2004-06-02
06:30
Fix a segfault in sqlite3OsLock() (CVS 1525) check-in: 51348b82 user: danielk1977 tags: trunk
01:22
Work toward combining the OP_MakeKey, OP_MakeIdxKey, and OP_MakeRecord opcodes into one. The work is incomplete. (CVS 1524) check-in: 165d69a0 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/os_unix.c.

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
...
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
...
711
712
713
714
715
716
717

718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
...
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
...
778
779
780
781
782
783
784

785
786
787

788
789
790
791
792
793
794
...
796
797
798
799
800
801
802

803
804
805
806
807
808
809
810
811
812
813
...
815
816
817
818
819
820
821
822
823
824

825
826
827
828
829
830
831


/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"


/*
** Here is the dirt on POSIX advisory locks:  ANSI STD 1003.1 (1996)
** section 6.5.2.2 lines 483 through 490 specify that when a process
** sets or clears a lock, that operation overrides any prior locks set
** by the same process.  It does not explicitly say so, but this implies
** that it overrides locks set by the same process using a different
** file descriptor.  Consider this test case:
................................................................................
** If the file was read locked, then this acquires a new read lock.
**
** Return SQLITE_OK on success and SQLITE_BUSY on failure.  If this
** library was compiled with large file support (LFS) but LFS is not
** available on the host, then an SQLITE_NOLFS is returned.
*/
int sqlite3OsReadLock(OsFile *id){
  int rc;
  return sqlite3OsLock(id, SHARED_LOCK);
}

/*
** Change the lock status to be an exclusive or write lock.  Return
** SQLITE_OK on success and SQLITE_BUSY on a failure.  If this
** library was compiled with large file support (LFS) but LFS is not
** available on the host, then an SQLITE_NOLFS is returned.
*/
int sqlite3OsWriteLock(OsFile *id){
  int rc;
  return sqlite3OsLock(id, EXCLUSIVE_LOCK);
}

/*
** Lock the file with the lock specified by parameter locktype - one
** of the following:
**
................................................................................
  ** has a SHARED or RESERVED lock, then increment reference counts and
  ** return SQLITE_OK.
  */
  if( locktype==SHARED_LOCK && 
      (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){
    assert( locktype==SHARED_LOCK );
    assert( id->locked==0 );

    id->locked = SHARED_LOCK;
    pLock->cnt++;
    id->pOpen->nLock++;
    goto end_lock;
  }

  lock.l_len = 1L;
  lock.l_whence = SEEK_SET;

  /* If control gets to this point, then actually go ahead and make
  ** operating system calls for the specified lock.
  */
  if( locktype==SHARED_LOCK ){
    assert( pLock->cnt==0 );
    assert( id->pOpen->nLock==0 );
    assert( pLock->locktype==0 );
  
    /* Grab a read-lock on byte 2. This ensures that no other process
    ** has a PENDING lock.
    */
    lock.l_type = F_RDLCK;
    lock.l_start = 2;
................................................................................
    lock.l_start = 2;
    lock.l_type = F_UNLCK;
    fcntl(id->fd, F_SETLK, &lock);
    if( s ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
    }else{
      id->locked = SHARED_LOCK;
      id->pOpen->nLock = 1;
      pLock->cnt = 1;
    }
  }else{
    /* The request was for a RESERVED, PENDING or EXCLUSIVE lock.  It is
    ** assumed that there is a SHARED or greater lock on the file
    ** already.
    */
................................................................................
    }
    s = fcntl(id->fd, F_SETLK, &lock);
    if( s ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
    }
  }
  

  id->locked = locktype;
  pLock->locktype = locktype;
  assert(pLock->locktype==RESERVED_LOCK||(id->pOpen->nLock==1&&pLock->cnt==1));


end_lock:
  sqlite3OsLeaveMutex();
  return rc;
}

/*
................................................................................
** not previously locked, then this routine is a no-op.  If this
** library was compiled with large file support (LFS) but LFS is not
** available on the host, then an SQLITE_NOLFS is returned.
*/
int sqlite3OsUnlock(OsFile *id){
  int rc;
  if( !id->locked ) return SQLITE_OK;

  sqlite3OsEnterMutex();
  assert( id->pLock->cnt!=0 );
  if( id->pLock->cnt>1 ){
    id->locked = 0;
    id->pLock->cnt--;
    rc = SQLITE_OK;
  }else{
    struct flock lock;
    int s;
    lock.l_type = F_UNLCK;
    lock.l_whence = SEEK_SET;
................................................................................
    s = fcntl(id->fd, F_SETLK, &lock);
    if( s!=0 ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
    }else{
      rc = SQLITE_OK;
      id->pLock->cnt = 0;
      id->pLock->locktype = 0;
      id->locked = 0;
    }
  }

  if( rc==SQLITE_OK ){
    /* Decrement the count of locks against this same file.  When the
    ** count reaches zero, close any other file descriptors whose close
    ** was deferred because of outstanding locks.
    */
    struct openCnt *pOpen = id->pOpen;
    pOpen->nLock--;







<







 







<










<







 







>






|







<







 







|







 







>
|
|
|
>







 







>



<







 







<


>







57
58
59
60
61
62
63

64
65
66
67
68
69
70
...
644
645
646
647
648
649
650

651
652
653
654
655
656
657
658
659
660

661
662
663
664
665
666
667
...
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729

730
731
732
733
734
735
736
...
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
...
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
...
795
796
797
798
799
800
801
802
803
804
805

806
807
808
809
810
811
812
...
814
815
816
817
818
819
820

821
822
823
824
825
826
827
828
829
830


/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"


/*
** Here is the dirt on POSIX advisory locks:  ANSI STD 1003.1 (1996)
** section 6.5.2.2 lines 483 through 490 specify that when a process
** sets or clears a lock, that operation overrides any prior locks set
** by the same process.  It does not explicitly say so, but this implies
** that it overrides locks set by the same process using a different
** file descriptor.  Consider this test case:
................................................................................
** If the file was read locked, then this acquires a new read lock.
**
** Return SQLITE_OK on success and SQLITE_BUSY on failure.  If this
** library was compiled with large file support (LFS) but LFS is not
** available on the host, then an SQLITE_NOLFS is returned.
*/
int sqlite3OsReadLock(OsFile *id){

  return sqlite3OsLock(id, SHARED_LOCK);
}

/*
** Change the lock status to be an exclusive or write lock.  Return
** SQLITE_OK on success and SQLITE_BUSY on a failure.  If this
** library was compiled with large file support (LFS) but LFS is not
** available on the host, then an SQLITE_NOLFS is returned.
*/
int sqlite3OsWriteLock(OsFile *id){

  return sqlite3OsLock(id, EXCLUSIVE_LOCK);
}

/*
** Lock the file with the lock specified by parameter locktype - one
** of the following:
**
................................................................................
  ** has a SHARED or RESERVED lock, then increment reference counts and
  ** return SQLITE_OK.
  */
  if( locktype==SHARED_LOCK && 
      (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){
    assert( locktype==SHARED_LOCK );
    assert( id->locked==0 );
    assert( pLock->cnt>0 );
    id->locked = SHARED_LOCK;
    pLock->cnt++;
    id->pOpen->nLock++;
    goto end_lock;
  }

  lock.l_len = 0L;
  lock.l_whence = SEEK_SET;

  /* If control gets to this point, then actually go ahead and make
  ** operating system calls for the specified lock.
  */
  if( locktype==SHARED_LOCK ){
    assert( pLock->cnt==0 );

    assert( pLock->locktype==0 );
  
    /* Grab a read-lock on byte 2. This ensures that no other process
    ** has a PENDING lock.
    */
    lock.l_type = F_RDLCK;
    lock.l_start = 2;
................................................................................
    lock.l_start = 2;
    lock.l_type = F_UNLCK;
    fcntl(id->fd, F_SETLK, &lock);
    if( s ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
    }else{
      id->locked = SHARED_LOCK;
      id->pOpen->nLock++;
      pLock->cnt = 1;
    }
  }else{
    /* The request was for a RESERVED, PENDING or EXCLUSIVE lock.  It is
    ** assumed that there is a SHARED or greater lock on the file
    ** already.
    */
................................................................................
    }
    s = fcntl(id->fd, F_SETLK, &lock);
    if( s ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
    }
  }
  
  if( rc==SQLITE_OK ){
    id->locked = locktype;
    pLock->locktype = locktype;
    assert( pLock->locktype==RESERVED_LOCK || pLock->cnt==1 );
  }

end_lock:
  sqlite3OsLeaveMutex();
  return rc;
}

/*
................................................................................
** not previously locked, then this routine is a no-op.  If this
** library was compiled with large file support (LFS) but LFS is not
** available on the host, then an SQLITE_NOLFS is returned.
*/
int sqlite3OsUnlock(OsFile *id){
  int rc;
  if( !id->locked ) return SQLITE_OK;
  id->locked = 0;
  sqlite3OsEnterMutex();
  assert( id->pLock->cnt!=0 );
  if( id->pLock->cnt>1 ){

    id->pLock->cnt--;
    rc = SQLITE_OK;
  }else{
    struct flock lock;
    int s;
    lock.l_type = F_UNLCK;
    lock.l_whence = SEEK_SET;
................................................................................
    s = fcntl(id->fd, F_SETLK, &lock);
    if( s!=0 ){
      rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
    }else{
      rc = SQLITE_OK;
      id->pLock->cnt = 0;
      id->pLock->locktype = 0;

    }
  }

  if( rc==SQLITE_OK ){
    /* Decrement the count of locks against this same file.  When the
    ** count reaches zero, close any other file descriptors whose close
    ** was deferred because of outstanding locks.
    */
    struct openCnt *pOpen = id->pOpen;
    pOpen->nLock--;

Changes to test/thread1.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
143
144
145
146
147
148
149
150
151
152
153
154
155



156
157
158
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is multithreading behavior
#
# $Id: thread1.test,v 1.3 2004/02/11 02:18:07 drh Exp $


set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Skip this whole file if the thread testing code is not enabled
#
................................................................................
  thread_result B
} SQLITE_OK
do_test thread1-2.9 {
  thread_step C
  thread_result C
} SQLITE_DONE
do_test thread1-2.10 {
  execsql {SELECT * FROM t2}
} {98 99}
do_test thread1-2.11 {
  thread_finalize C
  thread_result C
} SQLITE_OK




thread_halt *   
finish_test







|







 







<
<
<



>
>
>



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
143
144
145
146
147
148
149



150
151
152
153
154
155
156
157
158
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this script is multithreading behavior
#
# $Id: thread1.test,v 1.4 2004/06/02 06:30:18 danielk1977 Exp $


set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Skip this whole file if the thread testing code is not enabled
#
................................................................................
  thread_result B
} SQLITE_OK
do_test thread1-2.9 {
  thread_step C
  thread_result C
} SQLITE_DONE
do_test thread1-2.10 {



  thread_finalize C
  thread_result C
} SQLITE_OK
do_test thread1-2.11 {
  execsql {SELECT * FROM t2}
} {98 99}

thread_halt *   
finish_test