github.com/ooni/psiphon/tunnel-core@v0.0.0-20230105123940-fe12a24c96ee/oovendor/bolt/bolt_unix.go (about) 1 // +build !windows,!plan9,!solaris,!aix 2 3 package bolt 4 5 import ( 6 "fmt" 7 "syscall" 8 "time" 9 "unsafe" 10 ) 11 12 // flock acquires an advisory lock on a file descriptor. 13 func flock(db *DB, exclusive bool, timeout time.Duration) error { 14 var t time.Time 15 if timeout != 0 { 16 t = time.Now() 17 } 18 fd := db.file.Fd() 19 flag := syscall.LOCK_NB 20 if exclusive { 21 flag |= syscall.LOCK_EX 22 } else { 23 flag |= syscall.LOCK_SH 24 } 25 for { 26 // Attempt to obtain an exclusive lock. 27 err := syscall.Flock(int(fd), flag) 28 if err == nil { 29 return nil 30 } else if err != syscall.EWOULDBLOCK { 31 return err 32 } 33 34 // If we timed out then return an error. 35 if timeout != 0 && time.Since(t) > timeout-flockRetryTimeout { 36 return ErrTimeout 37 } 38 39 // Wait for a bit and try again. 40 time.Sleep(flockRetryTimeout) 41 } 42 } 43 44 // funlock releases an advisory lock on a file descriptor. 45 func funlock(db *DB) error { 46 return syscall.Flock(int(db.file.Fd()), syscall.LOCK_UN) 47 } 48 49 // mmap memory maps a DB's data file. 50 func mmap(db *DB, sz int) error { 51 // Map the data file to memory. 52 b, err := syscall.Mmap(int(db.file.Fd()), 0, sz, syscall.PROT_READ, syscall.MAP_SHARED|db.MmapFlags) 53 if err != nil { 54 return err 55 } 56 57 // Advise the kernel that the mmap is accessed randomly. 58 err = madvise(b, syscall.MADV_RANDOM) 59 if err != nil && err != syscall.ENOSYS { 60 // Ignore not implemented error in kernel because it still works. 61 return fmt.Errorf("madvise: %s", err) 62 } 63 64 // Save the original byte slice and convert to a byte array pointer. 65 db.dataref = b 66 db.data = (*[maxMapSize]byte)(unsafe.Pointer(&b[0])) 67 db.datasz = sz 68 return nil 69 } 70 71 // munmap unmaps a DB's data file from memory. 72 func munmap(db *DB) error { 73 // Ignore the unmap if we have no mapped data. 74 if db.dataref == nil { 75 return nil 76 } 77 78 // Unmap using the original byte slice. 79 err := syscall.Munmap(db.dataref) 80 db.dataref = nil 81 db.data = nil 82 db.datasz = 0 83 return err 84 } 85 86 // NOTE: This function is copied from stdlib because it is not available on darwin. 87 func madvise(b []byte, advice int) (err error) { 88 _, _, e1 := syscall.Syscall(syscall.SYS_MADVISE, uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), uintptr(advice)) 89 if e1 != 0 { 90 err = e1 91 } 92 return 93 }