refactor(c/libuv): general fixes & optimize code

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(c/libuv): optimize functions

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(c/libuv): mv name

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(c/libuv): modify libs

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(c/libuv): use new buffer arg

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(c/libuv/demo): optimize code style with go style

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(c/libuv): optimize code and add comment

Signed-off-by: hackerchai <i@hackerchai.com>

fix(c/libuv): fix TranslateSysError

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(c/libuv): remove go wrapper

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(c/libuv/demo): refactor c style

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(c/liobuv/demo): Some adjustments after removing go wrapper

refactor(c/libuv/demo): add print in echo_server

Signed-off-by: hackerchai <i@hackerchai.com>

doc(c/libuv): add README.md for c/libuv

Signed-off-by: hackerchai <i@hackerchai.com>

feat(c/libuv): implement poll_init_socket

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(c/libuv): mv poll_init_socket function

Signed-off-by: hackerchai <i@hackerchai.com>

refactor(demo): remove libuv demo

Signed-off-by: hackerchai <i@hackerchai.com>
This commit is contained in:
hackerchai
2024-07-23 11:43:02 +08:00
parent c63580ee38
commit c27c654180
11 changed files with 378 additions and 578 deletions

View File

@@ -0,0 +1,97 @@
package main
import (
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/libuv"
"github.com/goplus/llgo/c/os"
)
const BUFFER_SIZE = 1024
var (
loop *libuv.Loop
openReq libuv.Fs
readReq libuv.Fs
closeReq libuv.Fs
buffer [BUFFER_SIZE]c.Char
iov libuv.Buf
)
func main() {
// Print the libuv version
c.Printf(c.Str("libuv version: %d\n"), libuv.Version())
// Initialize the loop
loop = libuv.DefaultLoop()
// Open the file
libuv.FsOpen(loop, &openReq, c.Str("example.txt"), os.O_RDONLY, 0, onOpen)
// Run the loop
libuv.Run(loop, libuv.RUN_DEFAULT)
// Cleanup
defer cleanup()
}
func onOpen(req *libuv.Fs) {
// Check for errors
if libuv.FsGetResult(req) < 0 {
c.Fprintf(c.Stderr, c.Str("Error opening file: %s\n"), libuv.Strerror(libuv.LoopClose(loop)))
libuv.LoopClose(loop)
return
}
// Init buffer
iov = libuv.InitBuf((*c.Char)(unsafe.Pointer(&buffer[0])), c.Uint(unsafe.Sizeof(buffer)))
// Read the file
readRes := libuv.FsRead(loop, &readReq, libuv.UvFile(libuv.FsGetResult(req)), &iov, 1, -1, onRead)
if readRes != 0 {
c.Printf(c.Str("Error in FsRead: %s (code: %d)\n"), libuv.Strerror(c.Int(readRes)), readRes)
libuv.LoopClose(loop)
return
}
}
func onRead(req *libuv.Fs) {
// Check for errors
if libuv.FsGetResult(req) < 0 {
c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror(libuv.FsGetResult(req)))
libuv.LoopClose(loop)
} else if libuv.FsGetResult(req) == 0 {
c.Printf(c.Str("EOF\n"))
// Close the file
closeRes := libuv.FsClose(loop, &closeReq, libuv.UvFile(libuv.FsGetResult(&openReq)), onClose)
if closeRes != 0 {
// Print the content
c.Printf(c.Str("Error in FsClose: %s (code: %d)\n"), libuv.Strerror(c.Int(closeRes)), closeRes)
libuv.LoopClose(loop)
return
}
} else {
c.Printf(c.Str("Read %d bytes\n"), libuv.FsGetResult(req))
c.Printf(c.Str("Read content: %.*s\n"), libuv.FsGetResult(req), (*c.Char)(unsafe.Pointer(&buffer[0])))
libuv.LoopClose(loop)
}
}
func onClose(req *libuv.Fs) {
// Check for errors
if libuv.FsGetResult(req) < 0 {
c.Fprintf(c.Stderr, c.Str("Error closing file: %s\n"), libuv.Strerror(libuv.FsGetResult(req)))
} else {
c.Printf(c.Str("\nFile closed successfully.\n"))
}
libuv.LoopClose(loop)
}
func cleanup() {
// Cleanup the requests
libuv.FsReqCleanup(&openReq)
libuv.FsReqCleanup(&readReq)
libuv.FsReqCleanup(&closeReq)
// Close the loop
libuv.LoopClose(loop)
}

View File

@@ -0,0 +1 @@
123

View File

@@ -1,10 +1,11 @@
package main
import (
"unsafe"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/libuv"
"github.com/goplus/llgo/c/net"
"unsafe"
)
var DEFAULT_PORT c.Int = 8080
@@ -13,75 +14,8 @@ var DEFAULT_BACKLOG c.Int = 128
var loop *libuv.Loop
type WriteReq struct {
req libuv.Write
buf libuv.Buf
}
func FreeWriteReq(req *libuv.Write) {
wr := (*WriteReq)(c.Pointer(req))
c.Free(c.Pointer(wr.buf.Base))
c.Free(c.Pointer(wr))
}
func AllocBuffer(handle *libuv.Handle, suggestedSize uintptr, buf *libuv.Buf) {
buf.Base = (*c.Char)(c.Malloc(suggestedSize))
buf.Len = suggestedSize
}
func EchoWrite(req *libuv.Write, status c.Int) {
if status != 0 {
c.Fprintf(c.Stderr, c.Str("write error: %s\n"), libuv.Strerror(status))
}
defer FreeWriteReq(req)
}
func EchoRead(client *libuv.Stream, nread c.Long, buf *libuv.Buf) {
if nread > 0 {
req := (*WriteReq)(c.Malloc(unsafe.Sizeof(WriteReq{})))
if req == nil {
c.Fprintf(c.Stderr, c.Str("Failed to allocate memory for write request\n"))
defer c.Free(c.Pointer(buf.Base))
return
}
req.buf = libuv.InitBuf(buf.Base, c.Uint(nread))
(*libuv.Write)(c.Pointer(req)).Write(client, []libuv.Buf{req.buf}, 1, EchoWrite)
return
}
if nread < 0 {
if (libuv.Errno)(nread) != libuv.EOF {
c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror(c.Int(nread)))
}
(*libuv.Handle)(client).Close(nil)
}
if buf.Base != nil {
c.Free(c.Pointer(buf.Base))
}
}
func OnNewConnection(server *libuv.Stream, status c.Int) {
if status < 0 {
c.Fprintf(c.Stderr, c.Str("New connection error: %s\n"), libuv.Strerror(status))
return
}
client := (*libuv.Tcp)(c.Malloc(unsafe.Sizeof(libuv.Tcp{})))
if client == nil {
c.Fprintf(c.Stderr, c.Str("Failed to allocate memory for client\n"))
return
}
if libuv.InitTcp(loop, client) < 0 {
c.Fprintf(c.Stderr, c.Str("Failed to initialize client\n"))
c.Free(c.Pointer(client))
return
}
if server.Accept((*libuv.Stream)(client)) == 0 {
(*libuv.Stream)(client).StartRead(AllocBuffer, EchoRead)
} else {
(*libuv.Handle)(client).Close(nil)
}
Req libuv.Write
Buf libuv.Buf
}
func main() {
@@ -95,6 +29,7 @@ func main() {
// Set up the address to bind the server to
var addr net.SockaddrIn
libuv.Ip4Addr(c.Str("0.0.0.0"), DEFAULT_PORT, &addr)
c.Printf(c.Str("Listening on %s:%d\n"), c.Str("0.0.0.0"), DEFAULT_PORT)
// Bind the server to the specified address and port
(&server).Bind((*net.SockAddr)(c.Pointer(&addr)), 0)
@@ -105,5 +40,81 @@ func main() {
}
// Start listening for incoming connections
loop.Run(libuv.RUN_DEFAULT)
libuv.Run(loop, libuv.RUN_DEFAULT)
}
func FreeWriteReq(req *libuv.Write) {
wr := (*WriteReq)(c.Pointer(req))
// Free the buffer base and the WriteReq itself.
c.Free(c.Pointer(wr.Buf.Base))
c.Free(c.Pointer(wr))
}
func AllocBuffer(handle *libuv.Handle, suggestedSize uintptr, buf *libuv.Buf) {
// Allocate memory for the buffer based on the suggested size.
buf.Base = (*c.Char)(c.Malloc(suggestedSize))
buf.Len = suggestedSize
}
func EchoWrite(req *libuv.Write, status c.Int) {
if status != 0 {
c.Fprintf(c.Stderr, c.Str("Write error: %s\n"), libuv.Strerror(status))
}
FreeWriteReq(req)
}
func EchoRead(client *libuv.Stream, nread c.Long, buf *libuv.Buf) {
if nread > 0 {
req := (*WriteReq)(c.Malloc(unsafe.Sizeof(WriteReq{})))
if req == nil {
c.Fprintf(c.Stderr, c.Str("Failed to allocate memory for write request\n"))
c.Free(c.Pointer(buf.Base))
return
}
// Initialize the buffer with the data read.
req.Buf = libuv.InitBuf(buf.Base, c.Uint(nread))
// Write the data back to the client.
(&req.Req).Write(client, &req.Buf, 1, EchoWrite)
return
}
if nread < 0 {
// Handle read errors and EOF.
if (libuv.Errno)(nread) != libuv.EOF {
c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror(c.Int(nread)))
}
(*libuv.Handle)(c.Pointer(client)).Close(nil)
}
// Free the buffer if it's no longer needed.
if buf.Base != nil {
c.Free(c.Pointer(buf.Base))
}
}
func OnNewConnection(server *libuv.Stream, status c.Int) {
if status < 0 {
c.Fprintf(c.Stderr, c.Str("New connection error: %s\n"), libuv.Strerror(status))
return
}
// Allocate memory for a new client.
client := (*libuv.Tcp)(c.Malloc(unsafe.Sizeof(libuv.Tcp{})))
if client == nil {
c.Fprintf(c.Stderr, c.Str("Failed to allocate memory for client\n"))
return
}
// Initialize the client TCP handle.
if libuv.InitTcp(loop, client) < 0 {
c.Fprintf(c.Stderr, c.Str("Failed to initialize client\n"))
c.Free(c.Pointer(client))
return
}
// Accept the new connection and start reading data.
if server.Accept((*libuv.Stream)(client)) == 0 {
(*libuv.Stream)(client).StartRead(AllocBuffer, EchoRead)
} else {
(*libuv.Handle)(c.Pointer(client)).Close(nil)
}
}

View File

@@ -1,70 +0,0 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/libuv"
"github.com/goplus/llgo/c/os"
"golang.org/x/tools/container/intsets"
"unsafe"
)
const bufferSize = 1024
var buffer []c.Char
var iov libuv.Buf
var loop *libuv.Loop
var readReq *libuv.Fs
var closeReq *libuv.Fs
var openReq *libuv.Fs
func initBuffer() {
buffer = make([]c.Char, bufferSize)
}
func main() {
loop = libuv.DefaultLoop()
initBuffer()
file := libuv.NewFile(loop, openReq)
path := c.Str("example.txt")
file.Open(path, os.O_RDONLY, 0, onOpen)
loop.Run(libuv.RUN_DEFAULT)
libuv.FsReqCleanup(openReq)
loop.Close()
c.Free(unsafe.Pointer(loop))
}
func onOpen(req *libuv.Fs) {
if req.GetResult() < 0 {
c.Fprintf(c.Stderr, c.Str("Error opening file: %s\n"), libuv.Strerror(req.GetResult()))
} else {
iov = libuv.InitBuf(unsafe.SliceData(buffer), c.Uint(unsafe.Sizeof(buffer)))
libuv.FsRead(loop, readReq, req.GetResult(), []libuv.Buf{iov}, 1, -1, onRead)
}
libuv.FsReqCleanup(req)
}
func onRead(req *libuv.Fs) {
if req.GetResult() < 0 {
c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror(req.GetResult()))
} else if req.GetResult() == 0 {
libuv.FsClose(loop, closeReq, req.GetResult(), onClose)
} else {
if req.GetResult() > intsets.MaxInt {
c.Fprintf(c.Stderr, c.Str("Too big file.\n"))
}
c.Printf(c.Str("%.*s"), c.Int(req.GetResult()), buffer)
libuv.FsRead(loop, req, req.GetResult(), []libuv.Buf{iov}, 1, -1, onRead)
}
libuv.FsReqCleanup(req)
}
func onClose(req *libuv.Fs) {
c.Printf(c.Str("\nFile closed.\n"))
libuv.FsReqCleanup(req)
}