Skip to content

Commit 7f5ea54

Browse files
authored
Windows blocking locks. (#200)
1 parent 5f1d572 commit 7f5ea54

File tree

7 files changed

+52
-23
lines changed

7 files changed

+52
-23
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ as well as direct access to most of the [C SQLite API](https://sqlite.org/cintro
1010

1111
It wraps a [Wasm](https://webassembly.org/) [build](embed/) of SQLite,
1212
and uses [wazero](https://wazero.io/) as the runtime.\
13-
Go, wazero and [`x/sys`](https://pkg.go.dev/golang.org/x/sys) are the _only_ runtime dependencies.
13+
Go, wazero and [`x/sys`](https://pkg.go.dev/golang.org/x/sys) are the _only_ direct dependencies.
1414

1515
### Getting started
1616

go.work.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
1010
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
1111
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
1212
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
13+
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
1314
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
1415
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=

util/osutil/open_windows.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@ func syscallOpen(path string, mode int, perm uint32) (fd Handle, err error) {
101101
const _FILE_FLAG_WRITE_THROUGH = 0x80000000
102102
attrs |= _FILE_FLAG_WRITE_THROUGH
103103
}
104+
if mode&O_NONBLOCK != 0 {
105+
attrs |= FILE_FLAG_OVERLAPPED
106+
}
104107
return CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0)
105108
}
106109

vfs/os_windows.go

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
package vfs
44

55
import (
6-
"math/rand"
76
"os"
87
"time"
98

@@ -46,7 +45,7 @@ func osGetExclusiveLock(file *os.File, state *LockLevel) _ErrorCode {
4645
osUnlock(file, _SHARED_FIRST, _SHARED_SIZE)
4746

4847
// Acquire the EXCLUSIVE lock.
49-
rc := osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, time.Millisecond)
48+
rc := osWriteLock(file, _SHARED_FIRST, _SHARED_SIZE, 0)
5049

5150
if rc != _OK {
5251
// Reacquire the SHARED lock.
@@ -123,29 +122,40 @@ func osLock(file *os.File, flags, start, len uint32, timeout time.Duration, def
123122
var err error
124123
switch {
125124
case timeout == 0:
126-
err = osLockEx(file, flags|windows.LOCKFILE_FAIL_IMMEDIATELY, start, len)
125+
err = osLockEx(file, flags|windows.LOCKFILE_FAIL_IMMEDIATELY, start, len, 0)
127126
case timeout < 0:
128-
err = osLockEx(file, flags, start, len)
127+
err = osLockEx(file, flags, start, len, 0)
129128
default:
130-
before := time.Now()
131-
for {
132-
err = osLockEx(file, flags|windows.LOCKFILE_FAIL_IMMEDIATELY, start, len)
133-
if errno, _ := err.(windows.Errno); errno != windows.ERROR_LOCK_VIOLATION {
134-
break
129+
var event windows.Handle
130+
event, err = windows.CreateEvent(nil, 1, 0, nil)
131+
if err != nil {
132+
break
133+
}
134+
defer windows.CloseHandle(event)
135+
136+
err = osLockEx(file, flags, start, len, event)
137+
if err == windows.ERROR_IO_PENDING {
138+
rc, serr := windows.WaitForSingleObject(event, uint32(timeout/time.Millisecond))
139+
if rc == windows.WAIT_OBJECT_0 {
140+
return _OK
135141
}
136-
if time.Since(before) > timeout {
137-
break
142+
if serr != nil {
143+
err = serr
144+
} else {
145+
err = windows.Errno(rc)
138146
}
139-
const sleepIncrement = 1024*1024 - 1 // power of two, ~1ms
140-
time.Sleep(time.Duration(rand.Int63() & sleepIncrement))
147+
windows.CancelIo(windows.Handle(file.Fd()))
141148
}
142149
}
143150
return osLockErrorCode(err, def)
144151
}
145152

146-
func osLockEx(file *os.File, flags, start, len uint32) error {
153+
func osLockEx(file *os.File, flags, start, len uint32, event windows.Handle) error {
147154
return windows.LockFileEx(windows.Handle(file.Fd()), flags,
148-
0, len, 0, &windows.Overlapped{Offset: start})
155+
0, len, 0, &windows.Overlapped{
156+
Offset: start,
157+
HEvent: event,
158+
})
149159
}
150160

151161
func osReadLock(file *os.File, start, len uint32, timeout time.Duration) _ErrorCode {
@@ -166,7 +176,8 @@ func osLockErrorCode(err error, def _ErrorCode) _ErrorCode {
166176
case
167177
windows.ERROR_LOCK_VIOLATION,
168178
windows.ERROR_IO_PENDING,
169-
windows.ERROR_OPERATION_ABORTED:
179+
windows.ERROR_OPERATION_ABORTED,
180+
windows.WAIT_TIMEOUT:
170181
return _BUSY
171182
}
172183
}

vfs/shm_bsd.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func (s *vfsShm) shmOpen() _ErrorCode {
7373

7474
// Always open file read-write, as it will be shared.
7575
f, err := os.OpenFile(s.path,
76-
unix.O_RDWR|unix.O_CREAT|unix.O_NOFOLLOW, 0666)
76+
os.O_RDWR|os.O_CREATE|_O_NOFOLLOW, 0666)
7777
if err != nil {
7878
return _CANTOPEN
7979
}

vfs/shm_ofd.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type vfsShm struct {
2020
path string
2121
regions []*util.MappedRegion
2222
readOnly bool
23+
fileLock bool
2324
blocking bool
2425
sync.Mutex
2526
}
@@ -29,17 +30,20 @@ var _ blockingSharedMemory = &vfsShm{}
2930
func (s *vfsShm) shmOpen() _ErrorCode {
3031
if s.File == nil {
3132
f, err := os.OpenFile(s.path,
32-
unix.O_RDWR|unix.O_CREAT|unix.O_NOFOLLOW, 0666)
33+
os.O_RDWR|os.O_CREATE|_O_NOFOLLOW, 0666)
3334
if err != nil {
3435
f, err = os.OpenFile(s.path,
35-
unix.O_RDONLY|unix.O_CREAT|unix.O_NOFOLLOW, 0666)
36+
os.O_RDONLY|os.O_CREATE|_O_NOFOLLOW, 0666)
3637
s.readOnly = true
3738
}
3839
if err != nil {
3940
return _CANTOPEN
4041
}
4142
s.File = f
4243
}
44+
if s.fileLock {
45+
return _OK
46+
}
4347

4448
// Dead man's switch.
4549
if lock, rc := osTestLock(s.File, _SHM_DMS, 1); rc != _OK {
@@ -64,7 +68,9 @@ func (s *vfsShm) shmOpen() _ErrorCode {
6468
return _IOERR_SHMOPEN
6569
}
6670
}
67-
return osReadLock(s.File, _SHM_DMS, 1, time.Millisecond)
71+
rc := osReadLock(s.File, _SHM_DMS, 1, time.Millisecond)
72+
s.fileLock = rc == _OK
73+
return rc
6874
}
6975

7076
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (uint32, _ErrorCode) {

vfs/shm_windows.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"io"
88
"os"
99
"sync"
10+
"syscall"
1011
"time"
1112

1213
"github.com/tetratelabs/wazero/api"
@@ -27,6 +28,7 @@ type vfsShm struct {
2728
shadow [][_WALINDEX_PGSZ]byte
2829
ptrs []uint32
2930
stack [1]uint64
31+
fileLock bool
3032
blocking bool
3133
sync.Mutex
3234
}
@@ -46,12 +48,16 @@ func (s *vfsShm) Close() error {
4648

4749
func (s *vfsShm) shmOpen() _ErrorCode {
4850
if s.File == nil {
49-
f, err := osutil.OpenFile(s.path, os.O_RDWR|os.O_CREATE, 0666)
51+
f, err := osutil.OpenFile(s.path,
52+
os.O_RDWR|os.O_CREATE|syscall.O_NONBLOCK, 0666)
5053
if err != nil {
5154
return _CANTOPEN
5255
}
5356
s.File = f
5457
}
58+
if s.fileLock {
59+
return _OK
60+
}
5561

5662
// Dead man's switch.
5763
if rc := osWriteLock(s.File, _SHM_DMS, 1, 0); rc == _OK {
@@ -61,7 +67,9 @@ func (s *vfsShm) shmOpen() _ErrorCode {
6167
return _IOERR_SHMOPEN
6268
}
6369
}
64-
return osReadLock(s.File, _SHM_DMS, 1, time.Millisecond)
70+
rc := osReadLock(s.File, _SHM_DMS, 1, time.Millisecond)
71+
s.fileLock = rc == _OK
72+
return rc
6573
}
6674

6775
func (s *vfsShm) shmMap(ctx context.Context, mod api.Module, id, size int32, extend bool) (_ uint32, rc _ErrorCode) {

0 commit comments

Comments
 (0)