Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: syscall: extend the interface definition of RawConn to support non-blocking operations #61628

Open
lesismal opened this issue Jul 28, 2023 · 4 comments
Labels
Milestone

Comments

@lesismal
Copy link

Related:
#15735

I think it will be more useful to provide these non-blocking methods by RawConn rather than TCPConn.

These new metheds and the new definition would be like(see the OnRead/OnWrite/EnablePollWrite:

// A RawConn is a raw network connection.
type RawConn interface {
	// Control invokes f on the underlying connection's file
	// descriptor or handle.
	// The file descriptor fd is guaranteed to remain valid while
	// f executes but not after f returns.
	Control(f func(fd uintptr)) error

	// Read invokes f on the underlying connection's file
	// descriptor or handle; f is expected to try to read from the
	// file descriptor.
	// If f returns true, Read returns. Otherwise Read blocks
	// waiting for the connection to be ready for reading and
	// tries again repeatedly.
	// The file descriptor is guaranteed to remain valid while f
	// executes but not after f returns.
	Read(f func(fd uintptr) (done bool)) error

	// Write is like Read but for writing.
	Write(f func(fd uintptr) (done bool)) error

	// This is a new method.
	// OnRead registers a callback to handle the reading event.
	// If this callback is registered, users don't need to use
	// one goroutine for each conn and read it in a for-loop.
	OnRead(func(fd uintptr))

	// This is a new method.
	// OnWrite registers a callback to handle the writing event.
	OnWrite(func(fd uintptr))

	// This is a new method.
	// EnablePollWrite enables write event on the poller.
	// Users should cache the data unsent and call EnablePollWrite(true)
	// to enable the write event when Write fails, then the OnWrite 
	// callback will be called when the fd is writable;
	// Users should  call EnablePollWrite(false) to cancel the write
	// event after cached data has been sent.
	EnablePollWrite(enable bool)
}

After providing these new methods, users will be able to choose how to handle Fd's IO:

  1. Using blocking Read/Write as before
  2. Get RawConn by conn.SyscallConn(), and use RawConn.OnRead/OnWrite/EnablePollWrite to handle IO in a non-blocking way

The old issue #15735 was only for TCPConn, and still no solution to solve the problem of saving goroutines and blocking methods, so I open this new issue.

@gopherbot gopherbot added this to the Proposal milestone Jul 28, 2023
@ianlancetaylor
Copy link
Contributor

  1. We can't add new methods to an existing interface. That would break the compatibility guarantee.
  2. I don't understand what OnRead does. What does "handle the reading event" mean? Note that at least with our current approaches, we can't in general know whether there is any data available to read without attempting to read something.

@lesismal
Copy link
Author

lesismal commented Jul 28, 2023

I don't understand what OnRead does. What does "handle the reading event" mean? Note that at least with our current approaches, we can't in general know whether there is any data available to read without attempting to read something.

OnRead registers a callback, users no longer use for { read } in a goroutine. but when the fd is readable, runtime calls the callback and users can read data in the callback.

It's like Reactor, io events passed to the users' handler.

@ianlancetaylor
Copy link
Contributor

I would want to see an implementation before accepting a proposal like this.

@lesismal
Copy link
Author

It's also like the OnReadable in #15735 (comment)

I have implemented similar features in my lib, an example:

package main

import (
	"fmt"

	"github.com/lesismal/nbio"
)

func main() {
	engine := nbio.NewEngine(nbio.Config{
		Network:            "tcp",
		Addrs:              []string{":8080"},
	})

	engine.OnData(func(c *nbio.Conn, data []byte) {
		c.Write(append([]byte{}, data...))
	})

	err := engine.Start()
	if err != nil {
		fmt.Printf("nbio.Start failed: %v\n", err)
		return
	}
	defer engine.Stop()

	<-make(chan int)
}

I would want to see an implementation before accepting a proposal like this.

I haven't tried to implement these Reactor things in runtime yet, but found that maybe can do it for different Socket Conns when I read go source code.
I'll try it in my spare time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Incoming
Development

No branches or pull requests

3 participants