Reputation: 1011
In the standard library, src/time/sleep.go
has the following:
// Interface to timers implemented in package runtime.
// Must be in sync with ../runtime/runtime.h:/^struct.Timer$
type runtimeTimer struct {
i int
when int64
period int64
f func(interface{}, uintptr) // NOTE: must not be closure
arg interface{}
seq uintptr
}
func startTimer(*runtimeTimer)
The parameter type of startTimer
is *runtimeTimer
. startTimer
implementation is in the src/runtime/time.go
, as follows:
// Package time knows the layout of this structure.
// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
// For GOOS=nacl, package syscall knows the layout of this structure.
// If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer.
type timer struct {
i int // heap index
// Timer wakes up at when, and then at when+period, ... (period > 0 only)
// each time calling f(arg, now) in the timer goroutine, so f must be
// a well-behaved function and not block.
when int64
period int64
f func(interface{}, uintptr)
arg interface{}
seq uintptr
}
// startTimer adds t to the timer heap.
//go:linkname startTimer time.startTimer
func startTimer(t *timer) {
if raceenabled {
racerelease(unsafe.Pointer(t))
}
addtimer(t)
}
Here the parameter type of startTimer
is *timer
.
*timer
and *runtimeTimer
are different types. Because according to golang spec:
Two pointer types are identical if they have identical base types
And
A defined type is always different from any other type
timer
and runtimeTimer
are both defined types, so *timer
and *runtimeTimer
are different types.
According to assignability rule, assignment of argumetns in the function call shouldn't work either.
Can anybody explain this to me?
Thanks
Upvotes: 3
Views: 514
Reputation: 120941
The runtime package function is:
//go:linkname startTimer time.startTimer
func startTimer(t *timer) {
if raceenabled {
racerelease(unsafe.Pointer(t))
}
addtimer(t)
}
The //go:linkname
comment is a compiler directive:
//go:linkname localname importpath.name
The //go:linkname directive instructs the compiler to use “importpath.name” as the object file symbol name for the variable or function declared as “localname” in the source code. Because this directive can subvert the type system and package modularity, it is only enabled in files that have imported "unsafe".
This directive tells the compiler to use time.startTimer
as the object file symbol for this function.
The time package function is a declaration only. At link time, the time.startTimer name is bound to the function implemented in the runtime package. This match by name ignores type safety and modularity.
The purpose of these shenanigans is to allow the time package to call a runtime package function without exporting that function from the runtime package.
Upvotes: 4