Implement MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ.

cf. 2a36ab717e8f "rseq/membarrier: Add MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ"

PiperOrigin-RevId: 336186795
This commit is contained in:
Jamie Liu
2020-10-08 16:23:04 -07:00
committed by gVisor bot
parent 6768e6c59e
commit 6bad4851d4
4 changed files with 87 additions and 29 deletions
+8 -1
View File
@@ -14,7 +14,7 @@
package linux
// membarrier(2) commands, from include/uapi/linux/membarrier.h
// membarrier(2) commands, from include/uapi/linux/membarrier.h.
const (
MEMBARRIER_CMD_QUERY = 0
MEMBARRIER_CMD_GLOBAL = (1 << 0)
@@ -24,4 +24,11 @@ const (
MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED = (1 << 4)
MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 5)
MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE = (1 << 6)
MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ = (1 << 7)
MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ = (1 << 8)
)
// membarrier(2) flags, from include/uapi/linux/membarrier.h.
const (
MEMBARRIER_CMD_FLAG_CPU = (1 << 0)
)
+6
View File
@@ -243,6 +243,12 @@ type MemoryManager struct {
//
// membarrierPrivateEnabled is accessed using atomic memory operations.
membarrierPrivateEnabled uint32
// membarrierRSeqEnabled is non-zero if EnableMembarrierRSeq has previously
// been called.
//
// membarrierRSeqEnabled is accessed using atomic memory operations.
membarrierRSeqEnabled uint32
}
// vma represents a virtual memory area.
+12
View File
@@ -1287,3 +1287,15 @@ func (mm *MemoryManager) EnableMembarrierPrivate() {
func (mm *MemoryManager) IsMembarrierPrivateEnabled() bool {
return atomic.LoadUint32(&mm.membarrierPrivateEnabled) != 0
}
// EnableMembarrierRSeq causes future calls to IsMembarrierRSeqEnabled to
// return true.
func (mm *MemoryManager) EnableMembarrierRSeq() {
atomic.StoreUint32(&mm.membarrierRSeqEnabled, 1)
}
// IsMembarrierRSeqEnabled returns true if mm.EnableMembarrierRSeq() has
// previously been called.
func (mm *MemoryManager) IsMembarrierRSeqEnabled() bool {
return atomic.LoadUint32(&mm.membarrierRSeqEnabled) != 0
}
+61 -28
View File
@@ -24,47 +24,80 @@ import (
// Membarrier implements syscall membarrier(2).
func Membarrier(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
cmd := args[0].Int()
flags := args[1].Int()
p := t.Kernel().Platform
if !p.HaveGlobalMemoryBarrier() {
// Event for applications that want membarrier on a configuration that
// doesn't support them.
t.Kernel().EmitUnimplementedEvent(t)
return 0, nil, syserror.ENOSYS
}
if flags != 0 {
return 0, nil, syserror.EINVAL
}
flags := args[1].Uint()
switch cmd {
case linux.MEMBARRIER_CMD_QUERY:
const supportedCommands = linux.MEMBARRIER_CMD_GLOBAL |
linux.MEMBARRIER_CMD_GLOBAL_EXPEDITED |
linux.MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED |
linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED |
linux.MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED
if flags != 0 {
return 0, nil, syserror.EINVAL
}
var supportedCommands uintptr
if t.Kernel().Platform.HaveGlobalMemoryBarrier() {
supportedCommands |= linux.MEMBARRIER_CMD_GLOBAL |
linux.MEMBARRIER_CMD_GLOBAL_EXPEDITED |
linux.MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED |
linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED |
linux.MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED
}
if t.RSeqAvailable() {
supportedCommands |= linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ |
linux.MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ
}
return supportedCommands, nil, nil
case linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED:
if !t.MemoryManager().IsMembarrierPrivateEnabled() {
case linux.MEMBARRIER_CMD_GLOBAL, linux.MEMBARRIER_CMD_GLOBAL_EXPEDITED, linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED:
if flags != 0 {
return 0, nil, syserror.EINVAL
}
if !t.Kernel().Platform.HaveGlobalMemoryBarrier() {
return 0, nil, syserror.EINVAL
}
if cmd == linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED && !t.MemoryManager().IsMembarrierPrivateEnabled() {
return 0, nil, syserror.EPERM
}
fallthrough
case linux.MEMBARRIER_CMD_GLOBAL, linux.MEMBARRIER_CMD_GLOBAL_EXPEDITED:
return 0, nil, p.GlobalMemoryBarrier()
return 0, nil, t.Kernel().Platform.GlobalMemoryBarrier()
case linux.MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED:
if flags != 0 {
return 0, nil, syserror.EINVAL
}
if !t.Kernel().Platform.HaveGlobalMemoryBarrier() {
return 0, nil, syserror.EINVAL
}
// no-op
return 0, nil, nil
case linux.MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED:
if flags != 0 {
return 0, nil, syserror.EINVAL
}
if !t.Kernel().Platform.HaveGlobalMemoryBarrier() {
return 0, nil, syserror.EINVAL
}
t.MemoryManager().EnableMembarrierPrivate()
return 0, nil, nil
case linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, linux.MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE:
// We're aware of these, but they aren't implemented since no platform
// supports them yet.
t.Kernel().EmitUnimplementedEvent(t)
fallthrough
case linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ:
if flags&^linux.MEMBARRIER_CMD_FLAG_CPU != 0 {
return 0, nil, syserror.EINVAL
}
if !t.RSeqAvailable() {
return 0, nil, syserror.EINVAL
}
if !t.MemoryManager().IsMembarrierRSeqEnabled() {
return 0, nil, syserror.EPERM
}
// MEMBARRIER_CMD_FLAG_CPU and cpu_id are ignored since we don't have
// the ability to preempt specific CPUs.
return 0, nil, t.Kernel().Platform.PreemptAllCPUs()
case linux.MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ:
if flags != 0 {
return 0, nil, syserror.EINVAL
}
if !t.RSeqAvailable() {
return 0, nil, syserror.EINVAL
}
t.MemoryManager().EnableMembarrierRSeq()
return 0, nil, nil
default:
// Probably a command we don't implement.
t.Kernel().EmitUnimplementedEvent(t)
return 0, nil, syserror.EINVAL
}
}