go:nosplit

1,355 views
Skip to first unread message

Scott Cotton

unread,
Oct 5, 2018, 5:10:09 PM10/5/18
to golang-nuts
Hi all,

I have for the longest time thought of "go:nosplit" as a runtime-specific thing which wasn't available to arbitrary package authors.

Then, I found this from "go doc compile"

```
//go:nosplit

The //go:nosplit directive specifies that the next function declared in the
file must not include a stack overflow check. This is most commonly used by
low-level runtime sources invoked at times when it is unsafe for the calling
goroutine to be preempted.
```

I am interested in knowing
1. Can it indeed be used in arbitrary packages?
2. Does it indeed prevent the emission/addition of pre-emption instructions in the function it annotates?
3. Can it be used with gccgo?

Thanks for any info,
Scott

Ian Lance Taylor

unread,
Oct 5, 2018, 5:26:31 PM10/5/18
to Scott Cotton, golang-nuts
On Fri, Oct 5, 2018 at 2:10 PM, Scott Cotton <w...@iri-labs.com> wrote:
>
> I have for the longest time thought of "go:nosplit" as a runtime-specific
> thing which wasn't available to arbitrary package authors.
>
> Then, I found this from "go doc compile"
>
> ```
> //go:nosplit
>
> The //go:nosplit directive specifies that the next function declared in the
> file must not include a stack overflow check. This is most commonly used by
> low-level runtime sources invoked at times when it is unsafe for the calling
> goroutine to be preempted.
> ```
>
> I am interested in knowing
> 1. Can it indeed be used in arbitrary packages?

Yes.

> 2. Does it indeed prevent the emission/addition of pre-emption instructions
> in the function it annotates?

Well, yes and no. What it does is disable the stack overflow check at
function entry. At present the stack overflow check is also used as
a goroutine-preemption check. So disabling the stack overflow check
disables the goroutine-preemption check at function entry. And in Go
1.11 that is the only preemption check, so in Go 1.11 go:nosplit does
indeed disable preemption for a function. But there are no promises
that there will never be any other sort of preemption check. In fact
we definitely do want to add other preemption checks that occur at
points other than function entry (issues #10958, #24543). And if
there is another preemption check, there are no promises that
go:nosplit will disable that check.

> 3. Can it be used with gccgo?

Yes.

Ian

Scott Cotton

unread,
Oct 5, 2018, 5:47:15 PM10/5/18
to Ian Lance Taylor, golang-nuts
Thanks much for the info. 

Do you have any more pointers about how one may assess whether or ensure that a stack overflow check
is not necessary in order to safely use this directive?

Scott

--

Tyler Compton

unread,
Oct 5, 2018, 6:07:08 PM10/5/18
to Scott Cotton, Ian Lance Taylor, golang-nuts
I'm also surprised to hear that go:nosplit can be used in arbitrary packages. I would be curious to know if these directives are covered under the compatibility promise within the limited guarantees they provide.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Scott Cotton

unread,
Oct 5, 2018, 6:22:22 PM10/5/18
to Ian Lance Taylor, golang-nuts
On Fri, 5 Oct 2018 at 23:46, Scott Cotton <w...@iri-labs.com> wrote:
Thanks much for the info. 

Do you have any more pointers about how one may assess whether or ensure that a stack overflow check
is not necessary in order to safely use this directive?

Perhaps the compiler automatically accounts for the lack of stack overflow check in the functions which call
a function annotation with go:nosplit?  

Ian Lance Taylor

unread,
Oct 5, 2018, 8:06:07 PM10/5/18
to Scott Cotton, golang-nuts
On Fri, Oct 5, 2018 at 2:46 PM, Scott Cotton <w...@iri-labs.com> wrote:
>
> Do you have any more pointers about how one may assess whether or ensure
> that a stack overflow check
> is not necessary in order to safely use this directive?

You basically have to know what you're doing. In the general case,
whether go:nosplit is safe is going to depend on details of compiler
code generation that may vary from release to release. In practice,
go:nosplit is safe enough for a leaf function that has no large local
variables.

Ian

Ian Lance Taylor

unread,
Oct 5, 2018, 8:09:15 PM10/5/18
to Tyler Compton, Scott Cotton, golang-nuts
On Fri, Oct 5, 2018 at 3:06 PM, Tyler Compton <xav...@gmail.com> wrote:
>
> I'm also surprised to hear that go:nosplit can be used in arbitrary
> packages. I would be curious to know if these directives are covered under
> the compatibility promise within the limited guarantees they provide.

Directives like //go:nosplit are are not covered by the Go 1
compatibility guarantee. They are not specified by the language
specification or library documentation, so they fall under the
"unspecified behavior" clause of the guarantee. In particular future
releases may simply ignore these directives by treating them as the
comments that they are. Obviously that's not our intent, but we
really can't make any promises about how these directives behave.

Ian

Ian Lance Taylor

unread,
Oct 5, 2018, 8:10:34 PM10/5/18
to Scott Cotton, golang-nuts
On Fri, Oct 5, 2018 at 3:21 PM, Scott Cotton <w...@iri-labs.com> wrote:
>
> On Fri, 5 Oct 2018 at 23:46, Scott Cotton <w...@iri-labs.com> wrote:
>>
>> Thanks much for the info.
>>
>> Do you have any more pointers about how one may assess whether or ensure
>> that a stack overflow check
>> is not necessary in order to safely use this directive?
>
>
> Perhaps the compiler automatically accounts for the lack of stack overflow
> check in the functions which call
> a function annotation with go:nosplit?

If the linker detects a possible sequence of go:nosplit calls that
will use up too much stack space, it will issue an error. But the
linker check can be fooled in various ways.

Ian

Scott Cotton

unread,
Oct 6, 2018, 2:40:30 AM10/6/18
to Ian Lance Taylor, golang-nuts
Thanks.

Can you point to the entry point of the linker check in the sources? 
Are they the same for gccgo and gc?

Scott 

Ian

Scott Cotton

unread,
Oct 6, 2018, 2:58:05 AM10/6/18
to Ian Lance Taylor, golang-nuts
From what I understand,  this would
1. enable more faire/balanced scheduling
2. reduce worst case gc latency
3. eliminate problems when programmers unintentionally spin with cooperative/stack based 
pre-emption.
4. slow things down a bit when fair/balanced scheduling and gc latency and 3) are not an issue
5. make it impossible to prevent pre-emption in cases that need it or rely on cooperative/stack based pre-emption
6. potentially re-order some sequences of system calls,   so that Go programmer sequences of system calls G1, G2, ...
may have Go runtime system calls inserted in between where they weren't previously.

I don't think anyone wants 4,5 and 6 is frightening.

Maybe I don't know what I'm doing, so perhaps others can give opinions?  

Or should this discussion be on the issue tracker or golang-dev?

Scott




Scott Cotton

unread,
Oct 6, 2018, 3:10:27 AM10/6/18
to Ian Lance Taylor, golang-nuts
On Sat, 6 Oct 2018 at 08:57, Scott Cotton <w...@iri-labs.com> wrote:


On Fri, 5 Oct 2018 at 23:26, Ian Lance Taylor <ia...@golang.org> wrote:
On Fri, Oct 5, 2018 at 2:10 PM, Scott Cotton <w...@iri-labs.com> wrote:
 
In fact
we definitely do want to add other preemption checks that occur at
points other than function entry (issues #10958, #24543).  And if
there is another preemption check, there are no promises that
go:nosplit will disable that check.

From what I understand,  this would
1. enable more faire/balanced scheduling
2. reduce worst case gc latency
3. eliminate problems when programmers unintentionally spin with cooperative/stack based 
pre-emption.
4. slow things down a bit when fair/balanced scheduling and gc latency and 3) are not an issue
5. make it impossible to prevent pre-emption in cases that need it or rely on cooperative/stack based pre-emption

or go:nosplit
 
6. potentially re-order some sequences of system calls,   so that Go programmer sequences of system calls G1, G2, ...
may have Go runtime system calls inserted in between where they weren't previously.

I don't think anyone wants 4,5 and 6 is frightening.

Maybe I don't know what I'm doing, so perhaps others can give opinions?  

Or should this discussion be on the issue tracker or golang-dev?

Scott




Ian Lance Taylor

unread,
Oct 7, 2018, 11:59:40 PM10/7/18
to Scott Cotton, golang-nuts
On Fri, Oct 5, 2018 at 11:40 PM, Scott Cotton <w...@iri-labs.com> wrote:
>
> On Sat, 6 Oct 2018 at 02:10, Ian Lance Taylor <ia...@golang.org> wrote:
>>
>> On Fri, Oct 5, 2018 at 3:21 PM, Scott Cotton <w...@iri-labs.com> wrote:
>> >
>> > On Fri, 5 Oct 2018 at 23:46, Scott Cotton <w...@iri-labs.com> wrote:
>> >>
>> >> Thanks much for the info.
>> >>
>> >> Do you have any more pointers about how one may assess whether or
>> >> ensure
>> >> that a stack overflow check
>> >> is not necessary in order to safely use this directive?
>> >
>> >
>> > Perhaps the compiler automatically accounts for the lack of stack
>> > overflow
>> > check in the functions which call
>> > a function annotation with go:nosplit?
>>
>> If the linker detects a possible sequence of go:nosplit calls that
>> will use up too much stack space, it will issue an error. But the
>> linker check can be fooled in various ways.
>
>
> Thanks.
>
> Can you point to the entry point of the linker check in the sources?

The method (*Link).dostkcheck in cmd/link/internal/ld/lib.go.


> Are they the same for gccgo and gc?

Only the gc toolchain does the check, because gccgo uses the standard
system linker.

Ian

Ian Lance Taylor

unread,
Oct 8, 2018, 12:02:13 AM10/8/18
to Scott Cotton, golang-nuts
See the discussion at issue #24543. With that scheme 4 should not be
an issue. 5 and 6 could be problems in principle, but note that there
is no guaranteed way to do that today either.

Ian

Scott Cotton

unread,
Oct 8, 2018, 7:50:11 AM10/8/18
to golang-nuts
Thanks.  Continuing the discussion here since there re no responses there for some time.

There are many different ways to interpret "guaranteed" above.  The two that come to mind
are

a) A single given go release implementation, such as go1.11 actually may randomly pre-empt outside
of cooperative/stack based premption.  My understanding is no, you do not mean this.  And that 
cooperative/stack based pre-emption has been an established norm for a long time even if it falls outside the formal language specification.   I call it a language "semantic" because to me it's not really the same level of abstraction as say whether the compiler does loop unrolling.  It has qualitative program I/O implications.

b) If, by "guaranteed" you mean that the language does not formally specify it, then I take it on faith that you know the specification better than I, so ok.  However, I wanted to state that if the language doesn't specify this, and the language also doesn't specify what sys-calls are used on what platforms in what circumstances, then one can readily conclude that any Go program that relies on sequences of sys-calls longer than length one is in fact not guaranteed to work either.  While I appreciate being conservative about the language spec and compatibility, I find this conundrum quite impractical.

Scott
 

 

Ian

Jan Mercl

unread,
Oct 8, 2018, 7:54:26 AM10/8/18
to Scott Cotton, golang-nuts
On Mon, Oct 8, 2018 at 1:50 PM Scott Cotton <w...@iri-labs.com> wrote:

> However, I wanted to state that if the language doesn't specify this, and the language also doesn't specify what sys-calls are used on what platforms in what circumstances, then one can readily conclude that any Go program that relies on sequences of sys-calls longer than length one is in fact not guaranteed to work either. 

--

-j

Scott Cotton

unread,
Oct 8, 2018, 8:08:11 AM10/8/18
to golang-nuts
Thanks,

This doesn't however really address what I was pointing out.  Maybe I was too vague, let me try to clarify.

Suppose you are working on an operating system port of something and you use sys calls.  You check the syscall package, the OS docs, and you need to execute a sequence of sys calls of length two.  The syscall package supports your sys calls.  You follow the OS guidelines.  Then, the way things are today, you are STILL not guaranteed that it will work because the runtime might be implemented in a way that uses sys calls which interfere with what you are doing.  And the runtime doesn't specify what sys calls it might or might not use.  

So it is not really a question of whether you are using the syscall package correctly or its organisation w.r.t. operating systems.

Scott

Ian Lance Taylor

unread,
Oct 8, 2018, 10:31:16 AM10/8/18
to Scott Cotton, golang-nuts
I think that you are correct: given a sequence of system calls, the Go
language does not guarantee that there will be no intervening system
call. That is true today and it will be true in the future. For
example, today, the Go language makes no specific guarantees about
when memory will be allocated, and therefore makes no specific
guarantees about when the mmap system call will be called (on Unix
systems).

But the concern about a sequence of system calls that admits no
intervening system call seems rather abstract to me. When does that
issue ever arise? That's not your real concern. Your real concern
has to do with running audio code without interruption. That concern,
too, is abstract. We don't know how well it works today and we don't
know how well it will work in the future. Let's focus on real
problems. The lack of cooperative preemption is giving us real
problems in real Go programs today. That is why we are trying to fix
it. If the fix causes problems for audio code, then we'll try to fix
that. But let's not get ahead of ourselves; let's first see if there
is a problem.

Ian

Scott Cotton

unread,
Oct 8, 2018, 12:46:30 PM10/8/18
to Ian Lance Taylor, golang-nuts
There is documentation about the "reality" of the problem is on the issue tracker.
If there is disagreement about that I would find it more productive to address why in light of the arguments 
and documentation present on the issue tracker, rather than simply to assume that it is
not real here (and well after the fact).  In any event, I take my experience, research, and interactions with
others as sufficient to assess they are real.

I also find that all assessments directly to the contrary or responses which ignore the problem to come from people with far less experience in the matter (at least as far as I know) than  those other sources I have consulted and probably also myself. 

That said, I too took your stance about a year ago, said to myself, let's wait and see if it's a real problem. It is quite reasonable and really the only practical entry point into tackling the problem anyway.

But asserting a priori that well established guidelines from the field are not to be treated as "real" 
without backing up that position is in my opinion a risk with long term consequences.  
Reply all
Reply to author
Forward
0 new messages