aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2024-11-27 11:15:15 +0100
committerRon Evans <[email protected]>2024-11-27 12:16:10 +0100
commit392a709b77c82bfa98ce669ae6f781cf93835967 (patch)
treed4eb50ee542182ab2868e30c9a975115da9c8968 /src
parentee6fcd76f461543c67849a3b5b6cd5f8d16914d8 (diff)
downloadtinygo-392a709b77c82bfa98ce669ae6f781cf93835967.tar.gz
tinygo-392a709b77c82bfa98ce669ae6f781cf93835967.zip
runtime: use uint32 for the channel state and select index
This uses uint32 instead of uint64. The reason for this is that uint64 atomic operations aren't universally available (especially on 32-bit architectures). We could also use uintptr, but that seems needlessly complicated: it's unlikely real-world programs will use more than a billion select states (2^30).
Diffstat (limited to 'src')
-rw-r--r--src/internal/task/task.go12
-rw-r--r--src/runtime/chan.go34
2 files changed, 29 insertions, 17 deletions
diff --git a/src/internal/task/task.go b/src/internal/task/task.go
index bce65b582..587c67526 100644
--- a/src/internal/task/task.go
+++ b/src/internal/task/task.go
@@ -26,6 +26,18 @@ type Task struct {
DeferFrame unsafe.Pointer
}
+// DataUint32 returns the Data field as a uint32. The value is only valid after
+// setting it through SetDataUint32.
+func (t *Task) DataUint32() uint32 {
+ return *(*uint32)(unsafe.Pointer(&t.Data))
+}
+
+// SetDataUint32 updates the uint32 portion of the Data field (which could be
+// the first 4 or last 4 bytes depending on the architecture endianness).
+func (t *Task) SetDataUint32(val uint32) {
+ *(*uint32)(unsafe.Pointer(&t.Data)) = val
+}
+
// getGoroutineStackSize is a compiler intrinsic that returns the stack size for
// the given function and falls back to the default stack size. It is replaced
// with a load from a special section just before codegen.
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index c62685700..0d0cbf06a 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -83,7 +83,7 @@ func (q *chanQueue) push(node *channelOp) {
// waiting (for example, when they're part of a select operation) will be
// skipped.
// This function must be called with interrupts disabled.
-func (q *chanQueue) pop(chanOp uint64) *channelOp {
+func (q *chanQueue) pop(chanOp uint32) *channelOp {
for {
if q.first == nil {
return nil
@@ -96,11 +96,11 @@ func (q *chanQueue) pop(chanOp uint64) *channelOp {
// The new value for the 'data' field will be a combination of the
// channel operation and the select index. (The select index is 0 for
// non-select channel operations).
- newDataValue := chanOp | uint64(popped.index<<2)
+ newDataValue := chanOp | popped.index<<2
// Try to be the first to proceed with this goroutine.
- if popped.task.Data == chanOperationWaiting {
- popped.task.Data = newDataValue
+ if popped.task.DataUint32() == chanOperationWaiting {
+ popped.task.SetDataUint32(newDataValue)
return popped
}
}
@@ -123,7 +123,7 @@ func (q *chanQueue) remove(remove *channelOp) {
type channelOp struct {
next *channelOp
task *task.Task
- index uintptr // select index, 0 for non-select operation
+ index uint32 // select index, 0 for non-select operation
value unsafe.Pointer // if this is a sender, this is the value to send
}
@@ -239,7 +239,7 @@ func chanSend(ch *channel, value unsafe.Pointer, op *channelOp) {
// Can't proceed. Add us to the list of senders and wait until we're awoken.
t := task.Current()
- t.Data = chanOperationWaiting
+ t.SetDataUint32(chanOperationWaiting)
op.task = t
op.index = 0
op.value = value
@@ -251,7 +251,7 @@ func chanSend(ch *channel, value unsafe.Pointer, op *channelOp) {
// Check whether the sent happened normally (not because the channel was
// closed while sending).
- if t.Data == chanOperationClosed {
+ if t.DataUint32() == chanOperationClosed {
// Oops, this channel was closed while sending!
runtimePanic("send on closed channel")
}
@@ -313,7 +313,7 @@ func chanRecv(ch *channel, value unsafe.Pointer, op *channelOp) bool {
// until we're awoken.
t := task.Current()
t.Ptr = value
- t.Data = chanOperationWaiting
+ t.SetDataUint32(chanOperationWaiting)
op.task = t
op.index = 0
ch.receivers.push(op)
@@ -323,7 +323,7 @@ func chanRecv(ch *channel, value unsafe.Pointer, op *channelOp) bool {
task.Pause()
// Return whether the receive happened from a closed channel.
- return t.Data != chanOperationClosed
+ return t.DataUint32() != chanOperationClosed
}
// chanClose closes the given channel. If this channel has a receiver or is
@@ -375,10 +375,10 @@ func chanClose(ch *channel) {
// chanSelect implements blocking or non-blocking select operations.
// The 'ops' slice must be set if (and only if) this is a blocking select.
-func chanSelect(recvbuf unsafe.Pointer, states []chanSelectState, ops []channelOp) (uintptr, bool) {
+func chanSelect(recvbuf unsafe.Pointer, states []chanSelectState, ops []channelOp) (uint32, bool) {
mask := interrupt.Disable()
- const selectNoIndex = ^uintptr(0)
+ const selectNoIndex = ^uint32(0)
selectIndex := selectNoIndex
selectOk := true
@@ -393,13 +393,13 @@ func chanSelect(recvbuf unsafe.Pointer, states []chanSelectState, ops []channelO
if state.value == nil { // chan receive
if received, ok := state.ch.tryRecv(recvbuf); received {
- selectIndex = uintptr(i)
+ selectIndex = uint32(i)
selectOk = ok
break
}
} else { // chan send
if state.ch.trySend(state.value) {
- selectIndex = uintptr(i)
+ selectIndex = uint32(i)
break
}
}
@@ -421,14 +421,14 @@ func chanSelect(recvbuf unsafe.Pointer, states []chanSelectState, ops []channelO
// will be able to "take" this select operation.
t := task.Current()
t.Ptr = recvbuf
- t.Data = chanOperationWaiting
+ t.SetDataUint32(chanOperationWaiting)
for i, state := range states {
if state.ch == nil {
continue
}
op := &ops[i]
op.task = t
- op.index = uintptr(i)
+ op.index = uint32(i)
if state.value == nil { // chan receive
state.ch.receivers.push(op)
} else { // chan send
@@ -460,8 +460,8 @@ func chanSelect(recvbuf unsafe.Pointer, states []chanSelectState, ops []channelO
}
// Pull the return values out of t.Data (which contains two bitfields).
- selectIndex = uintptr(t.Data) >> 2
- selectOk = t.Data&chanOperationMask != chanOperationClosed
+ selectIndex = t.DataUint32() >> 2
+ selectOk = t.DataUint32()&chanOperationMask != chanOperationClosed
return selectIndex, selectOk
}