password636
password636

Reputation: 1011

Different function parameter types in declaration and definition

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

Answers (1)

Thundercat
Thundercat

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

Related Questions