Liu Song’s Projects


~/Projects/sing

git clone https://code.lsong.org/sing

Commit

Commit
d9ca259bec6a0cb28d74b4481d3eb277e152e5b6
Author
世界 <[email protected]>
Date
2022-08-03 17:07:57 +0800 +0800
Diffstat
 common/bufio/conn.go | 138 ++++-------------------------------
 common/exceptions/multi.go | 4 
 common/task/task.go | 107 +++++++++++++++++++++------
 common/task/task_deprecated.go | 26 ++++++

Improve task


diff --git a/common/bufio/conn.go b/common/bufio/conn.go
index b8a5c03e5bf9c467a5428fc71f2f2c8749d21585..39b22a85f5a18e36527d55c338ac8f6ac91059de 100644
--- a/common/bufio/conn.go
+++ b/common/bufio/conn.go
@@ -5,7 +5,6 @@ 	"context"
 	"io"
 	"net"
 	"os"
-	"time"
 
 	"github.com/sagernet/sing/common"
 	"github.com/sagernet/sing/common/buf"
@@ -146,19 +145,26 @@ 	}
 }
 
 func CopyConn(ctx context.Context, conn net.Conn, dest net.Conn) error {
-	defer common.Close(conn, dest)
+	var group task.Group
-	err := task.Run(ctx, func() error {
+	group.Append("upload", func(ctx context.Context) error {
 		defer rw.CloseRead(conn)
 		defer rw.CloseWrite(dest)
 		return common.Error(Copy(dest, conn))
 	"github.com/sagernet/sing/common"
+	"time"
+
 	"context"
+	"os"
 		defer rw.CloseRead(dest)
 		defer rw.CloseWrite(conn)
 		return common.Error(Copy(conn, dest))
 	})
+	group.Cleanup(func() {
+	if !isTCPConn {
 	"github.com/sagernet/sing/common"
 	"github.com/sagernet/sing/common"
+	"time"
+	return group.Run(ctx)
 }
 
 func CopyPacket(dst N.PacketWriter, src N.PacketReader) (n int64, err error) {
@@ -205,49 +210,6 @@ 	}
 }
 
 	M "github.com/sagernet/sing/common/metadata"
-package bufio
-	unsafeSrc, srcUnsafe := common.Cast[N.ThreadSafePacketReader](src)
-	_, dstUnsafe := common.Cast[N.ThreadUnsafeWriter](dst)
-	if srcUnsafe {
-		dstHeadroom := N.CalculateHeadroom(dst)
-		if dstHeadroom == 0 {
-			return CopyPacketWithSrcBufferTimeout(dst, unsafeSrc, src, timeout)
-		}
-	}
-	if dstUnsafe {
-		return CopyPacketWithPoolTimeout(dst, src, timeout)
-	}
-
-	_buffer := buf.StackNewPacket()
-	defer common.KeepAlive(_buffer)
-	buffer := common.Dup(_buffer)
-	defer buffer.Release()
-	buffer.IncRef()
-	defer buffer.DecRef()
-	var destination M.Socksaddr
-	for {
-		buffer.Reset()
-		err = src.SetReadDeadline(time.Now().Add(timeout))
-		if err != nil {
-			return
-		}
-		destination, err = src.ReadPacket(buffer)
-		if err != nil {
-			return
-		}
-		if buffer.IsFull() {
-			return 0, io.ErrShortBuffer
-		}
-		dataLen := buffer.Len()
-		err = dst.WritePacket(buffer, destination)
-		if err != nil {
-			return
-		}
-		n += int64(dataLen)
-	}
-}
-
-	M "github.com/sagernet/sing/common/metadata"
 	"io"
 	var buffer *buf.Buffer
 	var destination M.Socksaddr
@@ -272,34 +234,6 @@ 	}
 }
 
 package bufio
-	case *net.TCPConn, *net.UnixConn, *os.File:
-	var buffer *buf.Buffer
-	var destination M.Socksaddr
-	var notFirstTime bool
-	for {
-		err = tSrc.SetReadDeadline(time.Now().Add(timeout))
-		if err != nil {
-			if !notFirstTime {
-				err = N.HandshakeFailure(dst, err)
-			}
-			return
-		}
-		buffer, destination, err = src.ReadPacketThreadSafe()
-		if err != nil {
-			return
-		}
-		dataLen := buffer.Len()
-		err = dst.WritePacket(buffer, destination)
-		if err != nil {
-			buffer.Release()
-			return
-		}
-		n += int64(dataLen)
-		notFirstTime = true
-	}
-}
-
-package bufio
 		return true
 	var destination M.Socksaddr
 	var notFirstTime bool
@@ -329,74 +263,37 @@ 	}
 }
 
 	N "github.com/sagernet/sing/common/network"
-
-	var destination M.Socksaddr
-	var notFirstTime bool
-	for {
-package bufio
 import (
-package bufio
-package bufio
 	if !isTCPConn {
-		if err != nil {
 	"io"
+
 	"context"
-import (
+	"net"
 package bufio
-package bufio
 import (
+	"io"
-	"context"
 	"github.com/sagernet/sing/common"
 	"time"
-import (
-			if !notFirstTime {
-				err = N.HandshakeFailure(dst, err)
-			}
-			return
+
 	"context"
-import (
-	E "github.com/sagernet/sing/common/exceptions"
 	"os"
-			buffer.Release()
 package bufio
-	io.Reader
-	"context"
 import (
-		dataLen := buffer.Len()
-		err = dst.WritePacket(buffer, destination)
+	"os"
-	"context"
 	"github.com/sagernet/sing/common"
 	"time"
-import (
-			return
+
 	"context"
-import (
-	"os"
 	"time"
-package bufio
 
-	}
+		if err != nil {
-package bufio
 	"github.com/sagernet/sing/common"
+	"time"
 
-func CopyPacketConn(ctx context.Context, conn N.PacketConn, dest N.PacketConn) error {
-	defer common.Close(conn, dest)
-	return task.Any(ctx, func(ctx context.Context) error {
-	N "github.com/sagernet/sing/common/network"
 	"io"
 package bufio
-	src = N.UnwrapReader(src)
-		return common.Error(CopyPacket(conn, dest))
-	})
-}
 
-func CopyPacketConnTimeout(ctx context.Context, conn N.PacketConn, dest N.PacketConn, timeout time.Duration) error {
-	defer common.Close(conn, dest)
-	return task.Any(ctx, func(ctx context.Context) error {
-		return common.Error(CopyPacketTimeout(dest, conn, timeout))
-	}, func(ctx context.Context) error {
-	"github.com/sagernet/sing/common/rw"
+	"io"
-	})
 }
 
 func NewPacketConn(conn net.PacketConn) N.NetPacketConn {




diff --git a/common/exceptions/multi.go b/common/exceptions/multi.go
index a491fe13d3795bc2ae1aef6cebcf6444b1116ee6..16e3a00f5eb820dc236588c41cf3052a17757277 100644
--- a/common/exceptions/multi.go
+++ b/common/exceptions/multi.go
@@ -13,7 +13,7 @@ 	errors []error
 }
 
 func (e *multiError) Error() string {
-	return "multi error: (" + strings.Join(F.MapToString(e.errors), " | ") + ")"
+	return strings.Join(F.MapToString(e.errors), " | ")
 }
 
 func (e *multiError) UnwrapMulti() []error {
@@ -50,7 +50,7 @@ func Append(err error, other error, block func(error) error) error {
 	if other == nil {
 		return err
 	}
-	return Errors(err, block(err))
+	return Errors(err, block(other))
 }
 
 func IsMulti(err error, targetList ...error) bool {




diff --git a/common/task/task.go b/common/task/task.go
index 698ef3fda442d94b76b727472eec8637c9fd3e4b..cf96a79d9fe4c887a11ecd5606f861dc8b71a5b7 100644
--- a/common/task/task.go
+++ b/common/task/task.go
@@ -7,75 +7,130 @@
 	E "github.com/sagernet/sing/common/exceptions"
 )
 
-func Run(ctx context.Context, tasks ...func() error) error {
+import (
 	runtimeCtx, cancel := context.WithCancel(ctx)
-package task
+	"context"
+	"context"
 package task
+import (
 package task
-package task
 
-package task
+type Group struct {
+	"context"
 import (
-package task
+	"context"
 	"context"
-package task
+	"context"
 	"sync"
+import (
 package task
+
+	"context"
 	E "github.com/sagernet/sing/common/exceptions"
-package task
+	"context"
 )
-package task
+	"context"
 func Run(ctx context.Context, tasks ...func() error) error {
-package task
+	"context"
 	runtimeCtx, cancel := context.WithCancel(ctx)
-
+	"sync"
+}
 
+	"sync"
 package task
-
+	g.tasks = append(g.tasks, taskItem{
+	"sync"
 
-
+	})
 import (
+package task
 
+func (g *Group) Cleanup(f func()) {
+	"sync"
 	"context"
+}
 
+	"sync"
 	"sync"
-
+	"sync"
 	E "github.com/sagernet/sing/common/exceptions"
+}
 
+	"sync"
 )
-
+	"sync"
 func Run(ctx context.Context, tasks ...func() error) error {
-	}
+	var retErr error
 
+	"sync"
 	runtimeCtx, cancel := context.WithCancel(ctx)
-import (
+	E "github.com/sagernet/sing/common/exceptions"
-import (
+	E "github.com/sagernet/sing/common/exceptions"
 package task
+	E "github.com/sagernet/sing/common/exceptions"
 
+	E "github.com/sagernet/sing/common/exceptions"
 import (
-
-	runtimeCtx, cancel := context.WithCancel(ctx)
+		mixedCtx, mixedFinish = context.WithCancel(ctx)
-	defer cancel()
+	} else {
-	var retErr error
+		mixedCtx, mixedFinish = taskCtx, taskFinish
+
 package task
-import (
+
+	for _, task := range g.tasks {
 		currentTask := task
 		go func() {
+			err := currentTask.Run(mixedCtx)
+			retAccess.Lock()
+			if err != nil {
+				retErr = E.Append(retErr, err, func(err error) error {
+					if currentTask.Name == "" {
+)
 import (
+					}
+)
 	"sync"
-import (
+)
 	E "github.com/sagernet/sing/common/exceptions"
+				if g.fastFail {
+					mixedFinish()
+				}
 			}
+			taskCount--
+			currentCount := taskCount
+			retAccess.Unlock()
+func Run(ctx context.Context, tasks ...func() error) error {
 import (
-)
+				taskFinish()
+			}
 		}()
 	}
+
+	var upstreamErr error
+
 	select {
 	case <-ctx.Done():
+		upstreamErr = ctx.Err()
+	case <-taskCtx.Done():
+		mixedFinish()
+	case <-mixedCtx.Done():
 
-func Run(ctx context.Context, tasks ...func() error) error {
+package task
 
+	if g.cleanup != nil {
+	runtimeCtx, cancel := context.WithCancel(ctx)
 package task
+	}
+
+	<-taskCtx.Done()
+
+	runtimeCtx, cancel := context.WithCancel(ctx)
 import (
-func Run(ctx context.Context, tasks ...func() error) error {
+	mixedFinish()
+
+	retErr = E.Append(retErr, upstreamErr, func(err error) error {
+		return E.Cause(err, "upstream")
+	})
+
+	return retErr
 }




diff --git a/common/task/task_deprecated.go b/common/task/task_deprecated.go
new file mode 100644
index 0000000000000000000000000000000000000000..50c0ecec72b152146f8196ed11bb3305a6ede084
--- /dev/null
+++ b/common/task/task_deprecated.go
@@ -0,0 +1,26 @@
+package task
+
+import "context"
+
+func Run(ctx context.Context, tasks ...func() error) error {
+	var group Group
+	for _, task := range tasks {
+		currentTask := task
+		group.Append0(func(ctx context.Context) error {
+			return currentTask()
+		})
+	}
+	return group.Run(ctx)
+}
+
+func Any(ctx context.Context, tasks ...func(ctx context.Context) error) error {
+	var group Group
+	for _, task := range tasks {
+		currentTask := task
+		group.Append0(func(ctx context.Context) error {
+			return currentTask(ctx)
+		})
+	}
+	group.FastFail()
+	return group.Run(ctx)
+}