diff --git a/README.md b/README.md index 9cdcd599a..e4969d391 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ English | [中文](README_ZH.md) `gnet` is an event-driven networking framework that is ultra-fast and lightweight. It is built from scratch by exploiting [epoll](https://man7.org/linux/man-pages/man7/epoll.7.html) and [kqueue](https://en.wikipedia.org/wiki/Kqueue) and it can achieve much higher performance with lower memory consumption than Go [net](https://golang.org/pkg/net/) in many specific scenarios. -`gnet` and [net](https://golang.org/pkg/net/) don't share the same philosophy about network programming. Thus, building network applications with `gnet` can be significantly different from building them with [net](https://golang.org/pkg/net/), and the philosophies can't be reconciled. There are other similar products written in other programming languages in the community, such as [libuv](https://github.com/libuv/libuv), [netty](https://github.com/netty/netty), [twisted](https://github.com/twisted/twisted), [tornado](https://github.com/tornadoweb/tornado), etc. which work in a similar pattern as `gnet` under the hood. +`gnet` and [net](https://golang.org/pkg/net/) don't share the same philosophy in network programming. Thus, building network applications with `gnet` can be significantly different from building them with [net](https://golang.org/pkg/net/), and the philosophies can't be reconciled. There are other similar products written in other programming languages in the community, such as [libuv](https://github.com/libuv/libuv), [netty](https://github.com/netty/netty), [twisted](https://github.com/twisted/twisted), [tornado](https://github.com/tornadoweb/tornado), etc. which work in a similar pattern as `gnet` under the hood. `gnet` is not designed to displace the Go [net](https://golang.org/pkg/net/), but to create an alternative in the Go ecosystem for building performance-critical network services. As a result of which, `gnet` is not as comprehensive as Go [net](https://golang.org/pkg/net/), it provides only the core functionality (via a concise set of APIs) required by a network application and it doesn't plan on becoming a coverall networking framework, as I think Go [net](https://golang.org/pkg/net/) has done a good enough job in that area. diff --git a/README_ZH.md b/README_ZH.md index 533543275..e40c6749e 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -21,7 +21,7 @@ `gnet` 是一个基于事件驱动的高性能和轻量级网络框架。这个框架是基于 [epoll](https://en.wikipedia.org/wiki/Epoll) 和 [kqueue](https://en.wikipedia.org/wiki/Kqueue) 从零开发的,而且相比 Go [net](https://golang.org/pkg/net/),它能以更低的内存占用实现更高的性能。 -`gnet` 和 [net](https://golang.org/pkg/net/) 有着不一样的网络编程模式。因此,用 `gnet` 开发网络应用和用 [net](https://golang.org/pkg/net/) 开发区别很大,而且两者之间不可调和。社区里有其他同类的产品像是 [libuv](https://github.com/libuv/libuv), [netty](https://github.com/netty/netty), [twisted](https://github.com/twisted/twisted), [tornado](https://github.com/tornadoweb/tornado),`gnet` 的底层工作原理和这些框架非常类似。 +`gnet` 和 [net](https://golang.org/pkg/net/) 有着不一样的网络编程范式。因此,用 `gnet` 开发网络应用和用 [net](https://golang.org/pkg/net/) 开发区别很大,而且两者之间不可调和。社区里有其他同类的产品像是 [libuv](https://github.com/libuv/libuv), [netty](https://github.com/netty/netty), [twisted](https://github.com/twisted/twisted), [tornado](https://github.com/tornadoweb/tornado),`gnet` 的底层工作原理和这些框架非常类似。 `gnet` 不是为了取代 [net](https://golang.org/pkg/net/) 而生的,而是在 Go 生态中为开发者提供一个开发性能敏感的网络服务的替代品。也正因如此,`gnet` 在功能全面性上比不了 Go [net](https://golang.org/pkg/net/),它只会提供网络应用所需的最核心的功能和最精简的 APIs,而且 `gnet` 也并没有打算变成一个无所不包的网络框架,因为我觉得 Go [net](https://golang.org/pkg/net/) 在这方面已经做得足够好了。 diff --git a/acceptor_unix.go b/acceptor_unix.go index 7622f1a70..80070bf95 100644 --- a/acceptor_unix.go +++ b/acceptor_unix.go @@ -22,10 +22,10 @@ import ( "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/internal/netpoll" - "github.com/panjf2000/gnet/v2/internal/queue" - "github.com/panjf2000/gnet/v2/internal/socket" "github.com/panjf2000/gnet/v2/pkg/errors" + "github.com/panjf2000/gnet/v2/pkg/netpoll" + "github.com/panjf2000/gnet/v2/pkg/queue" + "github.com/panjf2000/gnet/v2/pkg/socket" ) func (el *eventloop) accept0(fd int, _ netpoll.IOEvent, _ netpoll.IOFlags) error { diff --git a/client_unix.go b/client_unix.go index 728b3b615..e8150217b 100644 --- a/client_unix.go +++ b/client_unix.go @@ -27,13 +27,13 @@ import ( "golang.org/x/sync/errgroup" "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/internal/math" - "github.com/panjf2000/gnet/v2/internal/netpoll" - "github.com/panjf2000/gnet/v2/internal/queue" - "github.com/panjf2000/gnet/v2/internal/socket" "github.com/panjf2000/gnet/v2/pkg/buffer/ring" errorx "github.com/panjf2000/gnet/v2/pkg/errors" "github.com/panjf2000/gnet/v2/pkg/logging" + "github.com/panjf2000/gnet/v2/pkg/math" + "github.com/panjf2000/gnet/v2/pkg/netpoll" + "github.com/panjf2000/gnet/v2/pkg/queue" + "github.com/panjf2000/gnet/v2/pkg/socket" ) // Client of gnet. diff --git a/connection_bsd.go b/connection_bsd.go index 5b2e80cf4..29baa8fde 100644 --- a/connection_bsd.go +++ b/connection_bsd.go @@ -22,7 +22,7 @@ import ( "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/internal/netpoll" + "github.com/panjf2000/gnet/v2/pkg/netpoll" ) func (c *conn) processIO(_ int, filter netpoll.IOEvent, flags netpoll.IOFlags) (err error) { diff --git a/connection_linux.go b/connection_linux.go index 12a57ebca..6f03c4247 100644 --- a/connection_linux.go +++ b/connection_linux.go @@ -22,7 +22,7 @@ import ( "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/internal/netpoll" + "github.com/panjf2000/gnet/v2/pkg/netpoll" ) func (c *conn) processIO(_ int, ev netpoll.IOEvent, _ netpoll.IOFlags) error { diff --git a/connection_unix.go b/connection_unix.go index 7babbeeac..ade55d836 100644 --- a/connection_unix.go +++ b/connection_unix.go @@ -25,16 +25,16 @@ import ( "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/internal/bs" "github.com/panjf2000/gnet/v2/internal/gfd" - gio "github.com/panjf2000/gnet/v2/internal/io" - "github.com/panjf2000/gnet/v2/internal/netpoll" - "github.com/panjf2000/gnet/v2/internal/queue" - "github.com/panjf2000/gnet/v2/internal/socket" + "github.com/panjf2000/gnet/v2/pkg/bs" "github.com/panjf2000/gnet/v2/pkg/buffer/elastic" errorx "github.com/panjf2000/gnet/v2/pkg/errors" + gio "github.com/panjf2000/gnet/v2/pkg/io" "github.com/panjf2000/gnet/v2/pkg/logging" + "github.com/panjf2000/gnet/v2/pkg/netpoll" bsPool "github.com/panjf2000/gnet/v2/pkg/pool/byteslice" + "github.com/panjf2000/gnet/v2/pkg/queue" + "github.com/panjf2000/gnet/v2/pkg/socket" ) type conn struct { diff --git a/engine_unix.go b/engine_unix.go index 0ede0cdca..8613af4a6 100644 --- a/engine_unix.go +++ b/engine_unix.go @@ -27,10 +27,10 @@ import ( "golang.org/x/sync/errgroup" "github.com/panjf2000/gnet/v2/internal/gfd" - "github.com/panjf2000/gnet/v2/internal/netpoll" - "github.com/panjf2000/gnet/v2/internal/queue" errorx "github.com/panjf2000/gnet/v2/pkg/errors" "github.com/panjf2000/gnet/v2/pkg/logging" + "github.com/panjf2000/gnet/v2/pkg/netpoll" + "github.com/panjf2000/gnet/v2/pkg/queue" ) type engine struct { diff --git a/eventloop_unix.go b/eventloop_unix.go index dd43bc172..a0cb77b69 100644 --- a/eventloop_unix.go +++ b/eventloop_unix.go @@ -28,11 +28,11 @@ import ( "golang.org/x/sys/unix" - gio "github.com/panjf2000/gnet/v2/internal/io" - "github.com/panjf2000/gnet/v2/internal/netpoll" - "github.com/panjf2000/gnet/v2/internal/queue" errorx "github.com/panjf2000/gnet/v2/pkg/errors" + gio "github.com/panjf2000/gnet/v2/pkg/io" "github.com/panjf2000/gnet/v2/pkg/logging" + "github.com/panjf2000/gnet/v2/pkg/netpoll" + "github.com/panjf2000/gnet/v2/pkg/queue" ) type eventloop struct { @@ -238,11 +238,11 @@ func (el *eventloop) close(c *conn, err error) error { if len(iov) > iovMax { iov = iov[:iovMax] } - if n, e := gio.Writev(c.fd, iov); e != nil { + n, err := gio.Writev(c.fd, iov) + if err != nil { break - } else { //nolint:revive - _, _ = c.outboundBuffer.Discard(n) } + _, _ = c.outboundBuffer.Discard(n) } c.release() diff --git a/gnet.go b/gnet.go index fe29427fc..64773cf80 100644 --- a/gnet.go +++ b/gnet.go @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package gnet implements a high-performance, lightweight, non-blocking, +// event-driven networking framework written in pure Go. +// +// Visit https://gnet.host/ for more details about gnet. package gnet import ( @@ -23,10 +27,10 @@ import ( "sync" "time" - "github.com/panjf2000/gnet/v2/internal/math" "github.com/panjf2000/gnet/v2/pkg/buffer/ring" "github.com/panjf2000/gnet/v2/pkg/errors" "github.com/panjf2000/gnet/v2/pkg/logging" + "github.com/panjf2000/gnet/v2/pkg/math" ) // Action is an action that occurs after the completion of an event. diff --git a/listener_unix.go b/listener_unix.go index 2e2711df8..a339fbd3b 100644 --- a/listener_unix.go +++ b/listener_unix.go @@ -25,10 +25,10 @@ import ( "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/internal/netpoll" - "github.com/panjf2000/gnet/v2/internal/socket" "github.com/panjf2000/gnet/v2/pkg/errors" "github.com/panjf2000/gnet/v2/pkg/logging" + "github.com/panjf2000/gnet/v2/pkg/netpoll" + "github.com/panjf2000/gnet/v2/pkg/socket" ) type listener struct { diff --git a/load_balancer.go b/load_balancer.go index 4a1f29874..4816afeb4 100644 --- a/load_balancer.go +++ b/load_balancer.go @@ -18,7 +18,7 @@ import ( "hash/crc32" "net" - "github.com/panjf2000/gnet/v2/internal/bs" + "github.com/panjf2000/gnet/v2/pkg/bs" ) // LoadBalancing represents the type of load-balancing algorithm. diff --git a/internal/bs/bs.go b/pkg/bs/bs.go similarity index 94% rename from internal/bs/bs.go rename to pkg/bs/bs.go index 7afb5136e..b901cc25a 100644 --- a/internal/bs/bs.go +++ b/pkg/bs/bs.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package bs provides a few handy bytes/string functions. package bs import ( diff --git a/pkg/buffer/elastic/elastic_ring_buffer.go b/pkg/buffer/elastic/elastic_ring_buffer.go index d637d583d..704a9c9f9 100644 --- a/pkg/buffer/elastic/elastic_ring_buffer.go +++ b/pkg/buffer/elastic/elastic_ring_buffer.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package elastic implements an elastic ring-buffer. package elastic import ( diff --git a/pkg/buffer/linkedlist/linked_list_buffer.go b/pkg/buffer/linkedlist/linked_list_buffer.go index 8916e9182..deb35c45f 100644 --- a/pkg/buffer/linkedlist/linked_list_buffer.go +++ b/pkg/buffer/linkedlist/linked_list_buffer.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package linkedlist implements a memory-reusable linked list of byte slices. package linkedlist import ( diff --git a/pkg/buffer/ring/ring_buffer.go b/pkg/buffer/ring/ring_buffer.go index 733515a98..a81ca1788 100644 --- a/pkg/buffer/ring/ring_buffer.go +++ b/pkg/buffer/ring/ring_buffer.go @@ -18,14 +18,15 @@ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// Package ring implements a memory-efficient circular buffer. package ring import ( "errors" "io" - "github.com/panjf2000/gnet/v2/internal/bs" - "github.com/panjf2000/gnet/v2/internal/math" + "github.com/panjf2000/gnet/v2/pkg/bs" + "github.com/panjf2000/gnet/v2/pkg/math" bsPool "github.com/panjf2000/gnet/v2/pkg/pool/byteslice" ) diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index 3aaf1b6ba..190751228 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package errors defines common errors for gnet. package errors import "errors" diff --git a/pkg/io/io.go b/pkg/io/io.go new file mode 100644 index 000000000..670719725 --- /dev/null +++ b/pkg/io/io.go @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025 The Gnet Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Package io provides some handy network I/O functions. +package io diff --git a/internal/io/io_bsd.go b/pkg/io/io_bsd.go similarity index 100% rename from internal/io/io_bsd.go rename to pkg/io/io_bsd.go diff --git a/internal/io/io_linux.go b/pkg/io/io_linux.go similarity index 100% rename from internal/io/io_linux.go rename to pkg/io/io_linux.go diff --git a/internal/math/math.go b/pkg/math/math.go similarity index 96% rename from internal/math/math.go rename to pkg/math/math.go index bdd29e547..87378db22 100644 --- a/internal/math/math.go +++ b/pkg/math/math.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package math provides a few fast math functions. package math const ( diff --git a/internal/netpoll/defs_bsd_32bit.go b/pkg/netpoll/defs_bsd_32bit.go similarity index 100% rename from internal/netpoll/defs_bsd_32bit.go rename to pkg/netpoll/defs_bsd_32bit.go diff --git a/internal/netpoll/defs_bsd_64bit.go b/pkg/netpoll/defs_bsd_64bit.go similarity index 100% rename from internal/netpoll/defs_bsd_64bit.go rename to pkg/netpoll/defs_bsd_64bit.go diff --git a/internal/netpoll/defs_linux.go b/pkg/netpoll/defs_linux.go similarity index 100% rename from internal/netpoll/defs_linux.go rename to pkg/netpoll/defs_linux.go diff --git a/internal/netpoll/defs_linux_386.go b/pkg/netpoll/defs_linux_386.go similarity index 100% rename from internal/netpoll/defs_linux_386.go rename to pkg/netpoll/defs_linux_386.go diff --git a/internal/netpoll/defs_linux_amd64.go b/pkg/netpoll/defs_linux_amd64.go similarity index 100% rename from internal/netpoll/defs_linux_amd64.go rename to pkg/netpoll/defs_linux_amd64.go diff --git a/internal/netpoll/defs_linux_arm.go b/pkg/netpoll/defs_linux_arm.go similarity index 100% rename from internal/netpoll/defs_linux_arm.go rename to pkg/netpoll/defs_linux_arm.go diff --git a/internal/netpoll/defs_linux_arm64.go b/pkg/netpoll/defs_linux_arm64.go similarity index 100% rename from internal/netpoll/defs_linux_arm64.go rename to pkg/netpoll/defs_linux_arm64.go diff --git a/internal/netpoll/defs_linux_mips64x.go b/pkg/netpoll/defs_linux_mips64x.go similarity index 100% rename from internal/netpoll/defs_linux_mips64x.go rename to pkg/netpoll/defs_linux_mips64x.go diff --git a/internal/netpoll/defs_linux_mipsx.go b/pkg/netpoll/defs_linux_mipsx.go similarity index 100% rename from internal/netpoll/defs_linux_mipsx.go rename to pkg/netpoll/defs_linux_mipsx.go diff --git a/internal/netpoll/defs_linux_ppc64.go b/pkg/netpoll/defs_linux_ppc64.go similarity index 100% rename from internal/netpoll/defs_linux_ppc64.go rename to pkg/netpoll/defs_linux_ppc64.go diff --git a/internal/netpoll/defs_linux_ppc64le.go b/pkg/netpoll/defs_linux_ppc64le.go similarity index 100% rename from internal/netpoll/defs_linux_ppc64le.go rename to pkg/netpoll/defs_linux_ppc64le.go diff --git a/internal/netpoll/defs_linux_riscv64.go b/pkg/netpoll/defs_linux_riscv64.go similarity index 100% rename from internal/netpoll/defs_linux_riscv64.go rename to pkg/netpoll/defs_linux_riscv64.go diff --git a/internal/netpoll/defs_linux_s390x.go b/pkg/netpoll/defs_linux_s390x.go similarity index 100% rename from internal/netpoll/defs_linux_s390x.go rename to pkg/netpoll/defs_linux_s390x.go diff --git a/internal/netpoll/defs_poller.go b/pkg/netpoll/defs_poller.go similarity index 100% rename from internal/netpoll/defs_poller.go rename to pkg/netpoll/defs_poller.go diff --git a/internal/netpoll/defs_poller_bsd.go b/pkg/netpoll/defs_poller_bsd.go similarity index 100% rename from internal/netpoll/defs_poller_bsd.go rename to pkg/netpoll/defs_poller_bsd.go diff --git a/internal/netpoll/defs_poller_epoll.go b/pkg/netpoll/defs_poller_epoll.go similarity index 82% rename from internal/netpoll/defs_poller_epoll.go rename to pkg/netpoll/defs_poller_epoll.go index f6b37feaa..9a07206f7 100644 --- a/internal/netpoll/defs_poller_epoll.go +++ b/pkg/netpoll/defs_poller_epoll.go @@ -40,10 +40,25 @@ const ( WriteEvents = unix.EPOLLOUT // ReadWriteEvents represents both readable and writeable events. ReadWriteEvents = ReadEvents | WriteEvents - // ErrEvents represents exceptional events that occurred on the local side. + // ErrEvents represents exceptional events that occurred. ErrEvents = unix.EPOLLERR | unix.EPOLLHUP ) +// IsReadEvent checks if the event is a read event. +func IsReadEvent(event IOEvent) bool { + return event&ReadEvents != 0 +} + +// IsWriteEvent checks if the event is a write event. +func IsWriteEvent(event IOEvent) bool { + return event&WriteEvents != 0 +} + +// IsErrorEvent checks if the event is an error event. +func IsErrorEvent(event IOEvent, _ IOFlags) bool { + return event&ErrEvents != 0 +} + type eventList struct { size int events []epollevent diff --git a/internal/netpoll/defs_poller_kqueue.go b/pkg/netpoll/defs_poller_kqueue.go similarity index 68% rename from internal/netpoll/defs_poller_kqueue.go rename to pkg/netpoll/defs_poller_kqueue.go index af7b0adda..9ce5f520d 100644 --- a/internal/netpoll/defs_poller_kqueue.go +++ b/pkg/netpoll/defs_poller_kqueue.go @@ -28,8 +28,31 @@ const ( MinPollEventsCap = 16 // MaxAsyncTasksAtOneTime is the maximum amount of asynchronous tasks that the event-loop will process at one time. MaxAsyncTasksAtOneTime = 128 + // ReadEvents represents readable events that are polled by kqueue. + ReadEvents = unix.EVFILT_READ + // WriteEvents represents writeable events that are polled by kqueue. + WriteEvents = unix.EVFILT_WRITE + // ReadWriteEvents represents both readable and writeable events. + ReadWriteEvents = ReadEvents | WriteEvents + // ErrEvents represents exceptional events that occurred. + ErrEvents = unix.EV_EOF | unix.EV_ERROR ) +// IsReadEvent checks if the event is a read event. +func IsReadEvent(event IOEvent) bool { + return event == ReadEvents +} + +// IsWriteEvent checks if the event is a write event. +func IsWriteEvent(event IOEvent) bool { + return event == WriteEvents +} + +// IsErrorEvent checks if the event is an error event. +func IsErrorEvent(_ IOEvent, flags IOFlags) bool { + return flags&ErrEvents != 0 +} + type eventList struct { size int events []unix.Kevent_t diff --git a/internal/netpoll/defs_poller_netbsd.go b/pkg/netpoll/defs_poller_netbsd.go similarity index 100% rename from internal/netpoll/defs_poller_netbsd.go rename to pkg/netpoll/defs_poller_netbsd.go diff --git a/pkg/netpoll/netpoll.go b/pkg/netpoll/netpoll.go new file mode 100644 index 000000000..d192710d5 --- /dev/null +++ b/pkg/netpoll/netpoll.go @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025 The Gnet Authors. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* +Package netpoll provides a portable event-driven interface for network I/O. + +The underlying facility of event notification is OS-specific: + - epoll on Linux - https://man7.org/linux/man-pages/man7/epoll.7.html + - kqueue on *BSD/Darwin - https://man.freebsd.org/cgi/man.cgi?kqueue + +With the help of the netpoll package, you can easily build your own high-performance +event-driven network applications based on epoll/kqueue. + +The Poller represents the event notification facility whose backend is epoll or kqueue. +The OpenPoller function creates a new Poller instance: + + poller, err := netpoll.OpenPoller() + if err != nil { + // handle error + } + + defer poller.Close() + + addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:9090") + if err != nil { + // handle error + } + c, err := net.DialTCP("tcp", nil, addr) + if err != nil { + // handle error + } + + f, err := c.File() + if err != nil { + // handle error + } + + closeClient := func() { + c.Close() + f.Close() + } + +The PollAttachment consists of a file descriptor and its callback function. +PollAttachment is used to register a file descriptor with the Poller. +The callback function is called when an event occurs on the file descriptor: + + pa := netpoll.PollAttachment{ + FD: int(f.Fd()), + Callback: func(i int, event netpoll.IOEvent, flags netpoll.IOFlags) error { + if netpoll.IsErrorEvent(event, flags) { + closeClient() + return errors.ErrEngineShutdown + } + + if netpoll.IsReadEvent(event) { + buf := make([]byte, 64) + _, err := c.Read(buf) + if err != nil { + closeClient() + return errors.ErrEngineShutdown + } + // Process the data... + } + + if netpoll.IsWriteEvent(event) { + // Write data to the connection... + _, err := c.Write([]byte("hello")) + if err != nil { + closeClient() + return errors.ErrEngineShutdown + } + } + + return nil + }} + + if err := poller.AddReadWrite(&pa, false); err != nil { + // handle error + } + +The Poller.Polling function starts the event loop monitoring file descriptors and +waiting for I/O events to occur: + + poller.Polling(func(fd int, event netpoll.IOEvent, flags netpoll.IOFlags) error { + return pa.Callback(fd, event, flags) + }) +*/ +package netpoll diff --git a/internal/netpoll/poller_epoll_default.go b/pkg/netpoll/poller_epoll_default.go similarity index 91% rename from internal/netpoll/poller_epoll_default.go rename to pkg/netpoll/poller_epoll_default.go index 39b6b0c1e..1eadabf1d 100644 --- a/internal/netpoll/poller_epoll_default.go +++ b/pkg/netpoll/poller_epoll_default.go @@ -27,9 +27,9 @@ import ( "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/internal/queue" errorx "github.com/panjf2000/gnet/v2/pkg/errors" "github.com/panjf2000/gnet/v2/pkg/logging" + "github.com/panjf2000/gnet/v2/pkg/queue" ) // Poller represents a poller which is in charge of monitoring file-descriptors. @@ -111,7 +111,8 @@ func (p *Poller) Trigger(priority queue.EventPriority, fn queue.Func, param any) return os.NewSyscallError("write", err) } -// Polling blocks the current goroutine, waiting for network-events. +// Polling blocks the current goroutine, monitoring the registered file descriptors and waiting for network I/O. +// When I/O occurs on any of the file descriptors, the provided callback function is invoked. func (p *Poller) Polling(callback PollEventHandler) error { el := newEventList(InitPollEventsCap) var doChores bool @@ -185,7 +186,7 @@ func (p *Poller) Polling(callback PollEventHandler) error { } } -// AddReadWrite registers the given file-descriptor with readable and writable events to the poller. +// AddReadWrite registers the given file descriptor with readable and writable events to the poller. func (p *Poller) AddReadWrite(pa *PollAttachment, edgeTriggered bool) error { var ev uint32 = ReadWriteEvents if edgeTriggered { @@ -195,7 +196,7 @@ func (p *Poller) AddReadWrite(pa *PollAttachment, edgeTriggered bool) error { unix.EpollCtl(p.fd, unix.EPOLL_CTL_ADD, pa.FD, &unix.EpollEvent{Fd: int32(pa.FD), Events: ev})) } -// AddRead registers the given file-descriptor with readable event to the poller. +// AddRead registers the given file descriptor with readable event to the poller. func (p *Poller) AddRead(pa *PollAttachment, edgeTriggered bool) error { var ev uint32 = ReadEvents if edgeTriggered { @@ -205,7 +206,7 @@ func (p *Poller) AddRead(pa *PollAttachment, edgeTriggered bool) error { unix.EpollCtl(p.fd, unix.EPOLL_CTL_ADD, pa.FD, &unix.EpollEvent{Fd: int32(pa.FD), Events: ev})) } -// AddWrite registers the given file-descriptor with writable event to the poller. +// AddWrite registers the given file descriptor with writable event to the poller. func (p *Poller) AddWrite(pa *PollAttachment, edgeTriggered bool) error { var ev uint32 = WriteEvents if edgeTriggered { @@ -215,7 +216,7 @@ func (p *Poller) AddWrite(pa *PollAttachment, edgeTriggered bool) error { unix.EpollCtl(p.fd, unix.EPOLL_CTL_ADD, pa.FD, &unix.EpollEvent{Fd: int32(pa.FD), Events: ev})) } -// ModRead renews the given file-descriptor with readable event in the poller. +// ModRead modifies the given file descriptor with readable event in the poller. func (p *Poller) ModRead(pa *PollAttachment, edgeTriggered bool) error { var ev uint32 = ReadEvents if edgeTriggered { @@ -225,7 +226,7 @@ func (p *Poller) ModRead(pa *PollAttachment, edgeTriggered bool) error { unix.EpollCtl(p.fd, unix.EPOLL_CTL_MOD, pa.FD, &unix.EpollEvent{Fd: int32(pa.FD), Events: ev})) } -// ModReadWrite renews the given file-descriptor with readable and writable events in the poller. +// ModReadWrite modifies the given file descriptor with readable and writable events in the poller. func (p *Poller) ModReadWrite(pa *PollAttachment, edgeTriggered bool) error { var ev uint32 = ReadWriteEvents if edgeTriggered { @@ -235,7 +236,7 @@ func (p *Poller) ModReadWrite(pa *PollAttachment, edgeTriggered bool) error { unix.EpollCtl(p.fd, unix.EPOLL_CTL_MOD, pa.FD, &unix.EpollEvent{Fd: int32(pa.FD), Events: ev})) } -// Delete removes the given file-descriptor from the poller. +// Delete removes the given file descriptor from the poller. func (p *Poller) Delete(fd int) error { return os.NewSyscallError("epoll_ctl del", unix.EpollCtl(p.fd, unix.EPOLL_CTL_DEL, fd, nil)) } diff --git a/internal/netpoll/poller_epoll_ultimate.go b/pkg/netpoll/poller_epoll_ultimate.go similarity index 91% rename from internal/netpoll/poller_epoll_ultimate.go rename to pkg/netpoll/poller_epoll_ultimate.go index acd3fb7d9..d7dc3369c 100644 --- a/internal/netpoll/poller_epoll_ultimate.go +++ b/pkg/netpoll/poller_epoll_ultimate.go @@ -26,9 +26,9 @@ import ( "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/internal/queue" errorx "github.com/panjf2000/gnet/v2/pkg/errors" "github.com/panjf2000/gnet/v2/pkg/logging" + "github.com/panjf2000/gnet/v2/pkg/queue" ) // Poller represents a poller which is in charge of monitoring file-descriptors. @@ -112,7 +112,8 @@ func (p *Poller) Trigger(priority queue.EventPriority, fn queue.Func, param any) return os.NewSyscallError("write", err) } -// Polling blocks the current goroutine, waiting for network-events. +// Polling blocks the current goroutine, monitoring the registered file descriptors and waiting for network I/O. +// When I/O occurs on any of the file descriptors, the provided callback function is invoked. func (p *Poller) Polling() error { el := newEventList(InitPollEventsCap) var doChores bool @@ -187,7 +188,7 @@ func (p *Poller) Polling() error { } } -// AddReadWrite registers the given file-descriptor with readable and writable events to the poller. +// AddReadWrite registers the given file descriptor with readable and writable events to the poller. func (p *Poller) AddReadWrite(pa *PollAttachment, edgeTriggered bool) error { var ev epollevent ev.events = ReadWriteEvents @@ -198,7 +199,7 @@ func (p *Poller) AddReadWrite(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("epoll_ctl add", epollCtl(p.fd, unix.EPOLL_CTL_ADD, pa.FD, &ev)) } -// AddRead registers the given file-descriptor with readable event to the poller. +// AddRead registers the given file descriptor with readable event to the poller. func (p *Poller) AddRead(pa *PollAttachment, edgeTriggered bool) error { var ev epollevent ev.events = ReadEvents @@ -209,7 +210,7 @@ func (p *Poller) AddRead(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("epoll_ctl add", epollCtl(p.fd, unix.EPOLL_CTL_ADD, pa.FD, &ev)) } -// AddWrite registers the given file-descriptor with writable event to the poller. +// AddWrite registers the given file descriptor with writable event to the poller. func (p *Poller) AddWrite(pa *PollAttachment, edgeTriggered bool) error { var ev epollevent ev.events = WriteEvents @@ -220,7 +221,7 @@ func (p *Poller) AddWrite(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("epoll_ctl add", epollCtl(p.fd, unix.EPOLL_CTL_ADD, pa.FD, &ev)) } -// ModRead renews the given file-descriptor with readable event in the poller. +// ModRead modifies the given file descriptor with readable event in the poller. func (p *Poller) ModRead(pa *PollAttachment, edgeTriggered bool) error { var ev epollevent ev.events = ReadEvents @@ -231,7 +232,7 @@ func (p *Poller) ModRead(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("epoll_ctl mod", epollCtl(p.fd, unix.EPOLL_CTL_MOD, pa.FD, &ev)) } -// ModReadWrite renews the given file-descriptor with readable and writable events in the poller. +// ModReadWrite modifies the given file descriptor with readable and writable events in the poller. func (p *Poller) ModReadWrite(pa *PollAttachment, edgeTriggered bool) error { var ev epollevent ev.events = ReadWriteEvents @@ -242,7 +243,7 @@ func (p *Poller) ModReadWrite(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("epoll_ctl mod", epollCtl(p.fd, unix.EPOLL_CTL_MOD, pa.FD, &ev)) } -// Delete removes the given file-descriptor from the poller. +// Delete removes the given file descriptor from the poller. func (p *Poller) Delete(fd int) error { return os.NewSyscallError("epoll_ctl del", epollCtl(p.fd, unix.EPOLL_CTL_DEL, fd, nil)) } diff --git a/internal/netpoll/poller_kqueue_default.go b/pkg/netpoll/poller_kqueue_default.go similarity index 90% rename from internal/netpoll/poller_kqueue_default.go rename to pkg/netpoll/poller_kqueue_default.go index c0c513c4a..00716e7b6 100644 --- a/internal/netpoll/poller_kqueue_default.go +++ b/pkg/netpoll/poller_kqueue_default.go @@ -26,9 +26,9 @@ import ( "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/internal/queue" errorx "github.com/panjf2000/gnet/v2/pkg/errors" "github.com/panjf2000/gnet/v2/pkg/logging" + "github.com/panjf2000/gnet/v2/pkg/queue" ) // Poller represents a poller which is in charge of monitoring file-descriptors. @@ -92,7 +92,8 @@ func (p *Poller) Trigger(priority queue.EventPriority, fn queue.Func, param any) return os.NewSyscallError("kevent | write", err) } -// Polling blocks the current goroutine, waiting for network-events. +// Polling blocks the current goroutine, monitoring the registered file descriptors and waiting for network I/O. +// When I/O occurs on any of the file descriptors, the provided callback function is invoked. func (p *Poller) Polling(callback PollEventHandler) error { el := newEventList(InitPollEventsCap) @@ -162,7 +163,7 @@ func (p *Poller) Polling(callback PollEventHandler) error { } } -// AddReadWrite registers the given file-descriptor with readable and writable events to the poller. +// AddReadWrite registers the given file descriptor with readable and writable events to the poller. func (p *Poller) AddReadWrite(pa *PollAttachment, edgeTriggered bool) error { var flags IOFlags = unix.EV_ADD if edgeTriggered { @@ -175,7 +176,7 @@ func (p *Poller) AddReadWrite(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("kevent add", err) } -// AddRead registers the given file-descriptor with readable event to the poller. +// AddRead registers the given file descriptor with readable event to the poller. func (p *Poller) AddRead(pa *PollAttachment, edgeTriggered bool) error { var flags IOFlags = unix.EV_ADD if edgeTriggered { @@ -187,7 +188,7 @@ func (p *Poller) AddRead(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("kevent add", err) } -// AddWrite registers the given file-descriptor with writable event to the poller. +// AddWrite registers the given file descriptor with writable event to the poller. func (p *Poller) AddWrite(pa *PollAttachment, edgeTriggered bool) error { var flags IOFlags = unix.EV_ADD if edgeTriggered { @@ -199,7 +200,7 @@ func (p *Poller) AddWrite(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("kevent add", err) } -// ModRead renews the given file-descriptor with readable event in the poller. +// ModRead modifies the given file descriptor with readable event in the poller. func (p *Poller) ModRead(pa *PollAttachment, _ bool) error { _, err := unix.Kevent(p.fd, []unix.Kevent_t{ {Ident: keventIdent(pa.FD), Flags: unix.EV_DELETE, Filter: unix.EVFILT_WRITE}, @@ -207,7 +208,7 @@ func (p *Poller) ModRead(pa *PollAttachment, _ bool) error { return os.NewSyscallError("kevent delete", err) } -// ModReadWrite renews the given file-descriptor with readable and writable events in the poller. +// ModReadWrite modifies the given file descriptor with readable and writable events in the poller. func (p *Poller) ModReadWrite(pa *PollAttachment, edgeTriggered bool) error { var flags IOFlags = unix.EV_ADD if edgeTriggered { @@ -219,7 +220,7 @@ func (p *Poller) ModReadWrite(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("kevent add", err) } -// Delete removes the given file-descriptor from the poller. +// Delete removes the given file descriptor from the poller. func (*Poller) Delete(_ int) error { return nil } diff --git a/internal/netpoll/poller_kqueue_ultimate.go b/pkg/netpoll/poller_kqueue_ultimate.go similarity index 91% rename from internal/netpoll/poller_kqueue_ultimate.go rename to pkg/netpoll/poller_kqueue_ultimate.go index e523d257d..fdfbb06ac 100644 --- a/internal/netpoll/poller_kqueue_ultimate.go +++ b/pkg/netpoll/poller_kqueue_ultimate.go @@ -27,9 +27,9 @@ import ( "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/internal/queue" errorx "github.com/panjf2000/gnet/v2/pkg/errors" "github.com/panjf2000/gnet/v2/pkg/logging" + "github.com/panjf2000/gnet/v2/pkg/queue" ) // Poller represents a poller which is in charge of monitoring file-descriptors. @@ -93,7 +93,8 @@ func (p *Poller) Trigger(priority queue.EventPriority, fn queue.Func, param any) return os.NewSyscallError("kevent | write", err) } -// Polling blocks the current goroutine, waiting for network-events. +// Polling blocks the current goroutine, monitoring the registered file descriptors and waiting for network I/O. +// When I/O occurs on any of the file descriptors, the provided callback function is invoked. func (p *Poller) Polling() error { el := newEventList(InitPollEventsCap) @@ -164,7 +165,7 @@ func (p *Poller) Polling() error { } } -// AddReadWrite registers the given file-descriptor with readable and writable events to the poller. +// AddReadWrite registers the given file descriptor with readable and writable events to the poller. func (p *Poller) AddReadWrite(pa *PollAttachment, edgeTriggered bool) error { var evs [2]unix.Kevent_t evs[0].Ident = keventIdent(pa.FD) @@ -180,7 +181,7 @@ func (p *Poller) AddReadWrite(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("kevent add", err) } -// AddRead registers the given file-descriptor with readable event to the poller. +// AddRead registers the given file descriptor with readable event to the poller. func (p *Poller) AddRead(pa *PollAttachment, edgeTriggered bool) error { var evs [1]unix.Kevent_t evs[0].Ident = keventIdent(pa.FD) @@ -194,7 +195,7 @@ func (p *Poller) AddRead(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("kevent add", err) } -// AddWrite registers the given file-descriptor with writable event to the poller. +// AddWrite registers the given file descriptor with writable event to the poller. func (p *Poller) AddWrite(pa *PollAttachment, edgeTriggered bool) error { var evs [1]unix.Kevent_t evs[0].Ident = keventIdent(pa.FD) @@ -208,7 +209,7 @@ func (p *Poller) AddWrite(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("kevent add", err) } -// ModRead renews the given file-descriptor with readable event in the poller. +// ModRead modifies the given file descriptor with readable event in the poller. func (p *Poller) ModRead(pa *PollAttachment, _ bool) error { var evs [1]unix.Kevent_t evs[0].Ident = keventIdent(pa.FD) @@ -218,7 +219,7 @@ func (p *Poller) ModRead(pa *PollAttachment, _ bool) error { return os.NewSyscallError("kevent delete", err) } -// ModReadWrite renews the given file-descriptor with readable and writable events in the poller. +// ModReadWrite modifies the given file descriptor with readable and writable events in the poller. func (p *Poller) ModReadWrite(pa *PollAttachment, edgeTriggered bool) error { var evs [1]unix.Kevent_t evs[0].Ident = keventIdent(pa.FD) @@ -232,7 +233,7 @@ func (p *Poller) ModReadWrite(pa *PollAttachment, edgeTriggered bool) error { return os.NewSyscallError("kevent add", err) } -// Delete removes the given file-descriptor from the poller. +// Delete removes the given file descriptor from the poller. func (p *Poller) Delete(_ int) error { return nil } diff --git a/internal/netpoll/poller_kqueue_wakeup.go b/pkg/netpoll/poller_kqueue_wakeup.go similarity index 100% rename from internal/netpoll/poller_kqueue_wakeup.go rename to pkg/netpoll/poller_kqueue_wakeup.go diff --git a/internal/netpoll/poller_kqueue_wakeup1.go b/pkg/netpoll/poller_kqueue_wakeup1.go similarity index 100% rename from internal/netpoll/poller_kqueue_wakeup1.go rename to pkg/netpoll/poller_kqueue_wakeup1.go diff --git a/internal/netpoll/poller_unix_ultimate.go b/pkg/netpoll/poller_unix_ultimate.go similarity index 100% rename from internal/netpoll/poller_unix_ultimate.go rename to pkg/netpoll/poller_unix_ultimate.go diff --git a/internal/netpoll/syscall_epoll_generic_linux.go b/pkg/netpoll/syscall_epoll_generic_linux.go similarity index 100% rename from internal/netpoll/syscall_epoll_generic_linux.go rename to pkg/netpoll/syscall_epoll_generic_linux.go diff --git a/internal/netpoll/syscall_epoll_linux.go b/pkg/netpoll/syscall_epoll_linux.go similarity index 100% rename from internal/netpoll/syscall_epoll_linux.go rename to pkg/netpoll/syscall_epoll_linux.go diff --git a/internal/netpoll/syscall_epoll_riscv64_arm64_linux.go b/pkg/netpoll/syscall_epoll_riscv64_arm64_linux.go similarity index 100% rename from internal/netpoll/syscall_epoll_riscv64_arm64_linux.go rename to pkg/netpoll/syscall_epoll_riscv64_arm64_linux.go diff --git a/internal/netpoll/syscall_errors_linux.go b/pkg/netpoll/syscall_errors_linux.go similarity index 100% rename from internal/netpoll/syscall_errors_linux.go rename to pkg/netpoll/syscall_errors_linux.go diff --git a/pkg/pool/bytebuffer/bytebuffer.go b/pkg/pool/bytebuffer/bytebuffer.go index 69f099601..c55b7ff23 100755 --- a/pkg/pool/bytebuffer/bytebuffer.go +++ b/pkg/pool/bytebuffer/bytebuffer.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package bytebuffer is a pool of bytebufferpool.ByteBuffer. package bytebuffer import "github.com/valyala/bytebufferpool" diff --git a/pkg/pool/byteslice/byteslice.go b/pkg/pool/byteslice/byteslice.go index 53397dac6..050534940 100644 --- a/pkg/pool/byteslice/byteslice.go +++ b/pkg/pool/byteslice/byteslice.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package byteslice implements a pool of byte slices consisting of sync.Pool's +// that collect byte slices with different length sizes from 0 to 32 in powers of 2. package byteslice import ( diff --git a/pkg/pool/goroutine/goroutine.go b/pkg/pool/goroutine/goroutine.go index 41ae371a7..eb27f45e3 100644 --- a/pkg/pool/goroutine/goroutine.go +++ b/pkg/pool/goroutine/goroutine.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package goroutine is a wrapper of ants. package goroutine import ( diff --git a/pkg/pool/ringbuffer/ringbuffer.go b/pkg/pool/ringbuffer/ringbuffer.go index 16914e14e..1fe7cfd27 100644 --- a/pkg/pool/ringbuffer/ringbuffer.go +++ b/pkg/pool/ringbuffer/ringbuffer.go @@ -16,6 +16,7 @@ // Use of this source code is governed by a MIT license that can be found // at https://github.com/valyala/bytebufferpool/blob/master/LICENSE +// Package ringbuffer implements a GC-friendly pool of ring buffers. package ringbuffer import ( diff --git a/internal/queue/lock_free_queue.go b/pkg/queue/lock_free_queue.go similarity index 97% rename from internal/queue/lock_free_queue.go rename to pkg/queue/lock_free_queue.go index 16099fecd..c344631f6 100644 --- a/internal/queue/lock_free_queue.go +++ b/pkg/queue/lock_free_queue.go @@ -157,6 +157,7 @@ func (q *lockFreeQueue) IsEmpty() bool { return atomic.LoadInt32(&q.length) == 0 } +// Length returns the number of elements in the queue. func (q *lockFreeQueue) Length() int32 { return atomic.LoadInt32(&q.length) } @@ -165,6 +166,6 @@ func load(p *unsafe.Pointer) (n *node) { return (*node)(atomic.LoadPointer(p)) } -func cas(p *unsafe.Pointer, old, new *node) bool { +func cas(p *unsafe.Pointer, old, new *node) bool { //nolint:revive return atomic.CompareAndSwapPointer(p, unsafe.Pointer(old), unsafe.Pointer(new)) } diff --git a/internal/queue/queue.go b/pkg/queue/queue.go similarity index 95% rename from internal/queue/queue.go rename to pkg/queue/queue.go index a85b0d7b9..24a9a9977 100644 --- a/internal/queue/queue.go +++ b/pkg/queue/queue.go @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package queue implements a lock-free queue for asynchronous tasks. package queue import "sync" diff --git a/internal/queue/queue_test.go b/pkg/queue/queue_test.go similarity index 95% rename from internal/queue/queue_test.go rename to pkg/queue/queue_test.go index c20f05d9d..a7ba855b3 100644 --- a/internal/queue/queue_test.go +++ b/pkg/queue/queue_test.go @@ -5,7 +5,7 @@ import ( "sync/atomic" "testing" - "github.com/panjf2000/gnet/v2/internal/queue" + "github.com/panjf2000/gnet/v2/pkg/queue" ) func TestLockFreeQueue(t *testing.T) { diff --git a/internal/socket/fd_unix.go b/pkg/socket/fd_unix.go similarity index 84% rename from internal/socket/fd_unix.go rename to pkg/socket/fd_unix.go index 7b89591d9..4c5e60efc 100644 --- a/internal/socket/fd_unix.go +++ b/pkg/socket/fd_unix.go @@ -24,18 +24,22 @@ import ( "golang.org/x/sys/unix" ) -// Dup is the wrapper for dupCloseOnExec. +// Dup duplicates the given fd and marks it close-on-exec. func Dup(fd int) (int, error) { return dupCloseOnExec(fd) } // tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used. -// If the kernel doesn't support it, this is set to 0. -var tryDupCloexec = int32(1) +// If the kernel doesn't support it, this is set to false. +var tryDupCloexec atomic.Bool -// dupCloseOnExec dups fd and marks it close-on-exec. +func init() { + tryDupCloexec.Store(true) +} + +// dupCloseOnExec duplicates the given fd and marks it close-on-exec. func dupCloseOnExec(fd int) (int, error) { - if atomic.LoadInt32(&tryDupCloexec) == 1 { + if tryDupCloexec.Load() { r, err := unix.FcntlInt(uintptr(fd), unix.F_DUPFD_CLOEXEC, 0) if err == nil { return r, nil @@ -45,7 +49,7 @@ func dupCloseOnExec(fd int) (int, error) { // Old kernel, or js/wasm (which returns // ENOSYS). Fall back to the portable way from // now on. - atomic.StoreInt32(&tryDupCloexec, 0) + tryDupCloexec.Store(false) default: return -1, err } diff --git a/internal/socket/sock_bsd.go b/pkg/socket/sock_bsd.go similarity index 100% rename from internal/socket/sock_bsd.go rename to pkg/socket/sock_bsd.go diff --git a/internal/socket/sock_cloexec.go b/pkg/socket/sock_cloexec.go similarity index 100% rename from internal/socket/sock_cloexec.go rename to pkg/socket/sock_cloexec.go diff --git a/internal/socket/sock_linux.go b/pkg/socket/sock_linux.go similarity index 100% rename from internal/socket/sock_linux.go rename to pkg/socket/sock_linux.go diff --git a/internal/socket/sock_posix.go b/pkg/socket/sock_posix.go similarity index 100% rename from internal/socket/sock_posix.go rename to pkg/socket/sock_posix.go diff --git a/internal/socket/socket.go b/pkg/socket/socket.go similarity index 78% rename from internal/socket/socket.go rename to pkg/socket/socket.go index 9ddce28a0..e389c9f8e 100644 --- a/internal/socket/socket.go +++ b/pkg/socket/socket.go @@ -16,8 +16,7 @@ //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd // +build darwin dragonfly freebsd linux netbsd openbsd -// Package socket provides functions that return fd and net.Addr based on -// given the protocol and address with a SO_REUSEPORT option set to the socket. +// Package socket provides some handy socket-related functions. package socket import ( @@ -41,17 +40,20 @@ func execSockOpts[T int | string](fd int, opts []Option[T]) error { return nil } -// TCPSocket calls the internal tcpSocket. +// TCPSocket creates a TCP socket and returns a file descriptor that refers to it. +// The given socket options will be set on the returned file descriptor. func TCPSocket(proto, addr string, passive bool, sockOptInts []Option[int], sockOptStrs []Option[string]) (int, net.Addr, error) { return tcpSocket(proto, addr, passive, sockOptInts, sockOptStrs) } -// UDPSocket calls the internal udpSocket. +// UDPSocket creates a UDP socket and returns a file descriptor that refers to it. +// The given socket options will be set on the returned file descriptor. func UDPSocket(proto, addr string, connect bool, sockOptInts []Option[int], sockOptStrs []Option[string]) (int, net.Addr, error) { return udpSocket(proto, addr, connect, sockOptInts, sockOptStrs) } -// UnixSocket calls the internal udsSocket. +// UnixSocket creates a Unix socket and returns a file descriptor that refers to it. +// The given socket options will be set on the returned file descriptor. func UnixSocket(proto, addr string, passive bool, sockOptInts []Option[int], sockOptStrs []Option[string]) (int, net.Addr, error) { return udsSocket(proto, addr, passive, sockOptInts, sockOptStrs) } diff --git a/internal/socket/sockopts_bsd.go b/pkg/socket/sockopts_bsd.go similarity index 100% rename from internal/socket/sockopts_bsd.go rename to pkg/socket/sockopts_bsd.go diff --git a/internal/socket/sockopts_darwin.go b/pkg/socket/sockopts_darwin.go similarity index 90% rename from internal/socket/sockopts_darwin.go rename to pkg/socket/sockopts_darwin.go index 5a2f69217..cffa2f524 100644 --- a/internal/socket/sockopts_darwin.go +++ b/pkg/socket/sockopts_darwin.go @@ -23,8 +23,9 @@ import ( errorx "github.com/panjf2000/gnet/v2/pkg/errors" ) -// SetKeepAlivePeriod sets whether the operating system should send -// keep-alive messages on the connection and sets period between keep-alive's. +// SetKeepAlivePeriod enables the SO_KEEPALIVE option on the socket and sets +// TCP_KEEPIDLE/TCP_KEEPALIVE to the specified duration in seconds, TCP_KEEPCNT +// to 5, and TCP_KEEPINTVL to secs/5. func SetKeepAlivePeriod(fd, secs int) error { if secs <= 0 { return errors.New("invalid time duration") diff --git a/internal/socket/sockopts_freebsd.go b/pkg/socket/sockopts_freebsd.go similarity index 100% rename from internal/socket/sockopts_freebsd.go rename to pkg/socket/sockopts_freebsd.go diff --git a/internal/socket/sockopts_linux.go b/pkg/socket/sockopts_linux.go similarity index 100% rename from internal/socket/sockopts_linux.go rename to pkg/socket/sockopts_linux.go diff --git a/internal/socket/sockopts_openbsd.go b/pkg/socket/sockopts_openbsd.go similarity index 84% rename from internal/socket/sockopts_openbsd.go rename to pkg/socket/sockopts_openbsd.go index 47820e6a0..c2059ddb8 100644 --- a/internal/socket/sockopts_openbsd.go +++ b/pkg/socket/sockopts_openbsd.go @@ -16,8 +16,8 @@ package socket import errorx "github.com/panjf2000/gnet/v2/pkg/errors" -// SetKeepAlivePeriod sets whether the operating system should send -// keep-alive messages on the connection and sets period between TCP keep-alive probes. +// SetKeepAlivePeriod is not implemented on OpenBSD because there are +// no equivalents of Linux's TCP_KEEPIDLE, TCP_KEEPINTVL, and TCP_KEEPCNT. func SetKeepAlivePeriod(_, _ int) error { // OpenBSD has no user-settable per-socket TCP keepalive options. return errorx.ErrUnsupportedOp diff --git a/internal/socket/sockopts_posix.go b/pkg/socket/sockopts_posix.go similarity index 100% rename from internal/socket/sockopts_posix.go rename to pkg/socket/sockopts_posix.go diff --git a/internal/socket/sockopts_unix.go b/pkg/socket/sockopts_unix.go similarity index 88% rename from internal/socket/sockopts_unix.go rename to pkg/socket/sockopts_unix.go index 4b63d8389..e5ef0059b 100644 --- a/internal/socket/sockopts_unix.go +++ b/pkg/socket/sockopts_unix.go @@ -24,8 +24,9 @@ import ( "golang.org/x/sys/unix" ) -// SetKeepAlivePeriod sets whether the operating system should send -// keep-alive messages on the connection and sets period between TCP keep-alive probes. +// SetKeepAlivePeriod enables the SO_KEEPALIVE option on the socket and sets +// TCP_KEEPIDLE/TCP_KEEPALIVE to the specified duration in seconds, TCP_KEEPCNT +// to 5, and TCP_KEEPINTVL to secs/5. func SetKeepAlivePeriod(fd, secs int) error { if secs <= 0 { return errors.New("invalid time duration") diff --git a/internal/socket/sockopts_unix1.go b/pkg/socket/sockopts_unix1.go similarity index 100% rename from internal/socket/sockopts_unix1.go rename to pkg/socket/sockopts_unix1.go diff --git a/internal/socket/socktoaddr.go b/pkg/socket/socktoaddr.go similarity index 92% rename from internal/socket/socktoaddr.go rename to pkg/socket/socktoaddr.go index 068a37213..d9a997e83 100644 --- a/internal/socket/socktoaddr.go +++ b/pkg/socket/socktoaddr.go @@ -22,11 +22,11 @@ import ( "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/internal/bs" + "github.com/panjf2000/gnet/v2/pkg/bs" bsPool "github.com/panjf2000/gnet/v2/pkg/pool/byteslice" ) -// SockaddrToTCPOrUnixAddr converts a Sockaddr to a net.TCPAddr or net.UnixAddr. +// SockaddrToTCPOrUnixAddr converts a unix.Sockaddr to a net.TCPAddr or net.UnixAddr. // Returns nil if conversion fails. func SockaddrToTCPOrUnixAddr(sa unix.Sockaddr) net.Addr { switch sa := sa.(type) { @@ -40,7 +40,7 @@ func SockaddrToTCPOrUnixAddr(sa unix.Sockaddr) net.Addr { return nil } -// SockaddrToUDPAddr converts a Sockaddr to a net.UDPAddr +// SockaddrToUDPAddr converts a unix.Sockaddr to a net.UDPAddr // Returns nil if conversion fails. func SockaddrToUDPAddr(sa unix.Sockaddr) net.Addr { switch sa := sa.(type) { diff --git a/internal/socket/sys_cloexec.go b/pkg/socket/sys_cloexec.go similarity index 100% rename from internal/socket/sys_cloexec.go rename to pkg/socket/sys_cloexec.go diff --git a/internal/socket/tcp_socket.go b/pkg/socket/tcp_socket.go similarity index 89% rename from internal/socket/tcp_socket.go rename to pkg/socket/tcp_socket.go index e086469f2..5ee6abb65 100644 --- a/internal/socket/tcp_socket.go +++ b/pkg/socket/tcp_socket.go @@ -19,12 +19,13 @@ package socket import ( + "errors" "net" "os" "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/pkg/errors" + errorx "github.com/panjf2000/gnet/v2/pkg/errors" ) var listenerBacklogMaxSize = maxListenerBacklog() @@ -54,7 +55,7 @@ func GetTCPSockAddr(proto, addr string) (sa unix.Sockaddr, family int, tcpAddr * family = unix.AF_INET6 sa, err = ipToSockaddr(family, tcpAddr.IP, tcpAddr.Port, tcpAddr.Zone) default: - err = errors.ErrUnsupportedProtocol + err = errorx.ErrUnsupportedProtocol } return @@ -78,11 +79,10 @@ func determineTCPProto(proto string, addr *net.TCPAddr) (string, error) { return proto, nil } - return "", errors.ErrUnsupportedTCPProtocol + return "", errorx.ErrUnsupportedTCPProtocol } // tcpSocket creates an endpoint for communication and returns a file descriptor that refers to that endpoint. -// Argument `reusePort` indicates whether the SO_REUSEPORT flag will be assigned. func tcpSocket(proto, addr string, passive bool, sockOptInts []Option[int], sockOptStrs []Option[string]) (fd int, netAddr net.Addr, err error) { var ( family int @@ -99,9 +99,9 @@ func tcpSocket(proto, addr string, passive bool, sockOptInts []Option[int], sock return } defer func() { - // ignore EINPROGRESS for non-blocking socket connect, should be processed by caller if err != nil { - if err, ok := err.(*os.SyscallError); ok && err.Err == unix.EINPROGRESS { + // Ignore EINPROGRESS for non-blocking socket connect, should be processed by caller + if errors.Is(err, unix.EINPROGRESS) { return } _ = unix.Close(fd) diff --git a/internal/socket/udp_socket.go b/pkg/socket/udp_socket.go similarity index 89% rename from internal/socket/udp_socket.go rename to pkg/socket/udp_socket.go index 0e524457b..28a221532 100644 --- a/internal/socket/udp_socket.go +++ b/pkg/socket/udp_socket.go @@ -19,12 +19,13 @@ package socket import ( + "errors" "net" "os" "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/pkg/errors" + errorx "github.com/panjf2000/gnet/v2/pkg/errors" ) // GetUDPSockAddr the structured addresses based on the protocol and raw address. @@ -52,7 +53,7 @@ func GetUDPSockAddr(proto, addr string) (sa unix.Sockaddr, family int, udpAddr * family = unix.AF_INET6 sa, err = ipToSockaddr(family, udpAddr.IP, udpAddr.Port, udpAddr.Zone) default: - err = errors.ErrUnsupportedProtocol + err = errorx.ErrUnsupportedProtocol } return @@ -76,11 +77,10 @@ func determineUDPProto(proto string, addr *net.UDPAddr) (string, error) { return proto, nil } - return "", errors.ErrUnsupportedUDPProtocol + return "", errorx.ErrUnsupportedUDPProtocol } // udpSocket creates an endpoint for communication and returns a file descriptor that refers to that endpoint. -// Argument `reusePort` indicates whether the SO_REUSEPORT flag will be assigned. func udpSocket(proto, addr string, connect bool, sockOptInts []Option[int], sockOptStrs []Option[string]) (fd int, netAddr net.Addr, err error) { var ( family int @@ -97,9 +97,9 @@ func udpSocket(proto, addr string, connect bool, sockOptInts []Option[int], sock return } defer func() { - // ignore EINPROGRESS for non-blocking socket connect, should be processed by caller if err != nil { - if err, ok := err.(*os.SyscallError); ok && err.Err == unix.EINPROGRESS { + // Ignore EINPROGRESS for non-blocking socket connect, should be processed by caller + if errors.Is(err, unix.EINPROGRESS) { return } _ = unix.Close(fd) diff --git a/internal/socket/unix_socket.go b/pkg/socket/unix_socket.go similarity index 84% rename from internal/socket/unix_socket.go rename to pkg/socket/unix_socket.go index 87cc889b4..992ded2b8 100644 --- a/internal/socket/unix_socket.go +++ b/pkg/socket/unix_socket.go @@ -18,12 +18,13 @@ package socket import ( + "errors" "net" "os" "golang.org/x/sys/unix" - "github.com/panjf2000/gnet/v2/pkg/errors" + errorx "github.com/panjf2000/gnet/v2/pkg/errors" ) // GetUnixSockAddr the structured addresses based on the protocol and raw address. @@ -37,14 +38,13 @@ func GetUnixSockAddr(proto, addr string) (sa unix.Sockaddr, family int, unixAddr case "unix": sa, family = &unix.SockaddrUnix{Name: unixAddr.Name}, unix.AF_UNIX default: - err = errors.ErrUnsupportedUDSProtocol + err = errorx.ErrUnsupportedUDSProtocol } return } // udsSocket creates an endpoint for communication and returns a file descriptor that refers to that endpoint. -// Argument `reusePort` indicates whether the SO_REUSEPORT flag will be assigned. func udsSocket(proto, addr string, passive bool, sockOptInts []Option[int], sockOptStrs []Option[string]) (fd int, netAddr net.Addr, err error) { var ( family int @@ -60,10 +60,10 @@ func udsSocket(proto, addr string, passive bool, sockOptInts []Option[int], sock return } defer func() { - // ignore EINPROGRESS for non-blocking socket connect, should be processed by caller - // though there is less situation for EINPROGRESS when using unix socket if err != nil { - if err, ok := err.(*os.SyscallError); ok && err.Err == unix.EINPROGRESS { + // Ignore EINPROGRESS for non-blocking socket connect, should be processed by caller + // though there is less situation for EINPROGRESS when using unix socket + if errors.Is(err, unix.EINPROGRESS) { return } _ = unix.Close(fd) diff --git a/reactor_default.go b/reactor_default.go index 8927f471e..ea468a4ff 100644 --- a/reactor_default.go +++ b/reactor_default.go @@ -22,8 +22,8 @@ import ( "errors" "runtime" - "github.com/panjf2000/gnet/v2/internal/netpoll" errorx "github.com/panjf2000/gnet/v2/pkg/errors" + "github.com/panjf2000/gnet/v2/pkg/netpoll" ) func (el *eventloop) rotate() error {