//go:build (linux || darwin) && (386 || arm || amd64 || arm64 || riscv64 || ppc64le || loong64) && !(sqlite3_flock || sqlite3_dotlk)

package vfs

import (
	
	
	
	
	

	

	

	
)

type vfsShm struct {
	*os.File
	path     string
	regions  []*util.MappedRegion
	readOnly bool
	fileLock bool
	blocking bool
	sync.Mutex
}

var _ blockingSharedMemory = &vfsShm{}

func ( *vfsShm) () error {
	if .fileLock {
		return nil
	}
	if .File == nil {
		,  := os.OpenFile(.path,
			os.O_RDWR|os.O_CREATE|_O_NOFOLLOW, 0666)
		if  != nil {
			,  = os.OpenFile(.path,
				os.O_RDONLY|os.O_CREATE|_O_NOFOLLOW, 0666)
			.readOnly = true
		}
		if  != nil {
			return sysError{, _CANTOPEN}
		}
		.fileLock = false
		.File = 
	}

	// Dead man's switch.
	if ,  := osTestLock(.File, _SHM_DMS, 1, _IOERR_LOCK);  != nil {
		return 
	} else if  == unix.F_WRLCK {
		return _BUSY
	} else if  == unix.F_UNLCK {
		if .readOnly {
			return _READONLY_CANTINIT
		}
		// Do not use a blocking lock here.
		// If the lock cannot be obtained immediately,
		// it means some other connection is truncating the file.
		// And after it has done so, it will not release its lock,
		// but only downgrade it to a shared lock.
		// So no point in blocking here.
		// The call below to obtain the shared DMS lock may use a blocking lock.
		if  := osWriteLock(.File, _SHM_DMS, 1, 0);  != nil {
			return 
		}
		if  := .Truncate(0);  != nil {
			return sysError{, _IOERR_SHMOPEN}
		}
	}
	 := osReadLock(.File, _SHM_DMS, 1, time.Millisecond)
	.fileLock =  == nil
	return 
}

func ( *vfsShm) ( context.Context,  api.Module, ,  int32,  bool) (ptr_t, error) {
	// Ensure size is a multiple of the OS page size.
	if int()&(unix.Getpagesize()-1) != 0 {
		return 0, _IOERR_SHMMAP
	}

	if  := .shmOpen();  != nil {
		return 0, 
	}

	// Check if file is big enough.
	,  := .Seek(0, io.SeekEnd)
	if  != nil {
		return 0, sysError{, _IOERR_SHMSIZE}
	}
	if  := (int64() + 1) * int64();  >  {
		if ! {
			return 0, nil
		}
		if .readOnly {
			return 0, _IOERR_SHMSIZE
		}
		if  := osAllocate(.File, );  != nil {
			return 0, sysError{, _IOERR_SHMSIZE}
		}
	}

	,  := util.MapRegion(, , .File, int64()*int64(), , .readOnly)
	if  != nil {
		return 0, 
	}
	.regions = append(.regions, )
	if .readOnly {
		return .Ptr, _READONLY
	}
	return .Ptr, nil
}

func ( *vfsShm) (,  int32,  _ShmFlag) error {
	// Argument check.
	switch {
	case  <= 0:
		panic(util.AssertErr())
	case  < 0 || + > _SHM_NLOCK:
		panic(util.AssertErr())
	case  != 1 && &_SHM_EXCLUSIVE == 0:
		panic(util.AssertErr())
	}
	switch  {
	case
		_SHM_LOCK | _SHM_SHARED,
		_SHM_LOCK | _SHM_EXCLUSIVE,
		_SHM_UNLOCK | _SHM_SHARED,
		_SHM_UNLOCK | _SHM_EXCLUSIVE:
		//
	default:
		panic(util.AssertErr())
	}

	if .File == nil {
		return _IOERR_SHMLOCK
	}

	var  time.Duration
	if .blocking {
		 = time.Millisecond
	}

	switch {
	case &_SHM_UNLOCK != 0:
		return osUnlock(.File, _SHM_BASE+int64(), int64())
	case &_SHM_SHARED != 0:
		return osReadLock(.File, _SHM_BASE+int64(), int64(), )
	case &_SHM_EXCLUSIVE != 0:
		return osWriteLock(.File, _SHM_BASE+int64(), int64(), )
	default:
		panic(util.AssertErr())
	}
}

func ( *vfsShm) ( bool) {
	if .File == nil {
		return
	}

	// Unmap regions.
	for ,  := range .regions {
		.Unmap()
	}
	.regions = nil

	// Close the file.
	if  {
		os.Remove(.path)
	}
	.Close()
	.File = nil
	.fileLock = false
}

func ( *vfsShm) () {
	.Lock()
	//lint:ignore SA2001 memory barrier.
	.Unlock()
}

func ( *vfsShm) ( bool) {
	.blocking = 
}