From db6930d9e4ccc4276c5d789982c7dad478333d4a Mon Sep 17 00:00:00 2001 From: hackerchai Date: Fri, 19 Jul 2024 17:27:18 +0800 Subject: [PATCH 1/6] feat(c/libuv): Add io, fs, signal, core, poll features Signed-off-by: hackerchai feat(c/libuv): Add io, fs, signal features Signed-off-by: hackerchai refactor(c/libuv): rename io into libuv Signed-off-by: hackerchai fix(c/libuv): fix some compile errors Signed-off-by: hackerchai --- c/libuv/fs.go | 451 ++++++++++++++++++++++++++++++++++++++++++++++ c/libuv/libuv.go | 141 +++++++++++++++ c/libuv/signal.go | 30 +++ 3 files changed, 622 insertions(+) create mode 100644 c/libuv/fs.go create mode 100644 c/libuv/libuv.go create mode 100644 c/libuv/signal.go diff --git a/c/libuv/fs.go b/c/libuv/fs.go new file mode 100644 index 00000000..3381e5bb --- /dev/null +++ b/c/libuv/fs.go @@ -0,0 +1,451 @@ +package libuv + +import ( + "github.com/goplus/llgo/c" + _ "unsafe" +) + +const ( + DirentUnknown DirentType = iota + DirentFile + DirentDir + DirentLink + DirentFifo + DirentSocket + DirentChar + DirentBlock +) + +type DirentType int + +/* Handle types. */ + +type Fs struct { + Unused [0]byte +} + +type FsEvent struct { + Unused [0]byte +} + +type FsPoll struct { + Unused [0]byte +} + +type Dirent struct { + Name *c.Char + Type DirentType +} + +type File struct { + Loop *Loop + Req *Fs +} + +// llgo:type C +type FsCb func(req *Fs) + +// llgo:type C +type FsEventCb func(handle *FsEvent, filename *c.Char, events c.Int, status c.Int) + +// llgo:type C +type FsPollCb func(handle *FsPoll, status c.Int, events c.Int) + +/* Request types. */ + +/* None of the above. */ + +// ---------------------------------------------- + +/* Fs related function and method */ + +//go:linkname FsReqCleanup C.uv_fs_req_cleanup +func FsReqCleanup(req *Fs) + +//go:linkname DefaultLoop C.uv_default_loop +func DefaultLoop() *Loop + +//go:linkname FsOpen C.uv_fs_open +func FsOpen(loop *Loop, req *Fs, path *c.Char, flags c.Int, mode c.Int, cb FsCb) c.Int + +//go:linkname FsClose C.uv_fs_close +func FsClose(loop *Loop, req *Fs, file c.Int, cb FsCb) c.Int + +//go:linkname FsRead C.uv_fs_read +func FsRead(loop *Loop, req *Fs, file c.Int, bufs []Buf, nbufs c.Uint, offset c.Int, cb FsCb) c.Int + +//go:linkname FsWrite C.uv_fs_write +func FsWrite(loop *Loop, req *Fs, file c.Int, bufs []Buf, nbufs c.Uint, offset c.Int, cb FsCb) c.Int + +//go:linkname FsUnlink C.uv_fs_unlink +func FsUnlink(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int + +//go:linkname FsMkdir C.uv_fs_mkdir +func FsMkdir(loop *Loop, req *Fs, path *c.Char, mode c.Int, cb FsCb) c.Int + +//go:linkname FsMkdtemp C.uv_fs_mkdtemp +func FsMkdtemp(loop *Loop, req *Fs, tpl *c.Char, cb FsCb) c.Int + +//go:linkname FsMkStemp C.uv_fs_mkstemp +func FsMkStemp(loop *Loop, req *Fs, tpl *c.Char, cb FsCb) c.Int + +//go:linkname FsRmdir C.uv_fs_rmdir +func FsRmdir(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int + +//go:linkname FsStat C.uv_fs_stat +func FsStat(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int + +//go:linkname FsFstat C.uv_fs_fstat +func FsFstat(loop *Loop, req *Fs, file c.Int, cb FsCb) c.Int + +//go:linkname FsRename C.uv_fs_rename +func FsRename(loop *Loop, req *Fs, path *c.Char, newPath *c.Char, cb FsCb) c.Int + +//go:linkname FsFsync C.uv_fs_fsync +func FsFsync(loop *Loop, req *Fs, file c.Int, cb FsCb) c.Int + +//go:linkname FsFdatasync C.uv_fs_fdatasync +func FsFdatasync(loop *Loop, req *Fs, file c.Int, cb FsCb) c.Int + +//go:linkname FsFtruncate C.uv_fs_ftruncate +func FsFtruncate(loop *Loop, req *Fs, file c.Int, offset c.Int, cb FsCb) c.Int + +//go:linkname FsSendfile C.uv_fs_sendfile +func FsSendfile(loop *Loop, req *Fs, outFd c.Int, inFd c.Int, inOffset c.Int, length c.Int, cb FsCb) c.Int + +//go:linkname FsAccess C.uv_fs_access +func FsAccess(loop *Loop, req *Fs, path *c.Char, flags c.Int, cb FsCb) c.Int + +//go:linkname FsChmod C.uv_fs_chmod +func FsChmod(loop *Loop, req *Fs, path *c.Char, mode c.Int, cb FsCb) c.Int + +//go:linkname FsFchmod C.uv_fs_fchmod +func FsFchmod(loop *Loop, req *Fs, file c.Int, mode c.Int, cb FsCb) c.Int + +//go:linkname FsUtime C.uv_fs_utime +func FsUtime(loop *Loop, req *Fs, path *c.Char, atime c.Int, mtime c.Int, cb FsCb) c.Int + +//go:linkname FsFutime C.uv_fs_futime +func FsFutime(loop *Loop, req *Fs, file c.Int, atime c.Int, mtime c.Int, cb FsCb) c.Int + +//go:linkname FsLutime C.uv_fs_lutime +func FsLutime(loop *Loop, req *Fs, path *c.Char, atime c.Int, mtime c.Int, cb FsCb) c.Int + +//go:linkname FsLink C.uv_fs_link +func FsLink(loop *Loop, req *Fs, path *c.Char, newPath *c.Char, cb FsCb) c.Int + +//go:linkname FsSymlink C.uv_fs_symlink +func FsSymlink(loop *Loop, req *Fs, path *c.Char, newPath *c.Char, flags c.Int, cb FsCb) c.Int + +//go:linkname FsReadlink C.uv_fs_read +func FsReadlink(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int + +//go:linkname FsRealpath C.uv_fs_realpath +func FsRealpath(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int + +//go:linkname FsCopyfile C.uv_fs_copyfile +func FsCopyfile(loop *Loop, req *Fs, path *c.Char, newPath *c.Char, flags c.Int, cb FsCb) c.Int + +//go:linkname FsScandir C.uv_fs_scandir +func FsScandir(loop *Loop, req *Fs, path *c.Char, flags c.Int, cb FsCb) c.Int + +//go:linkname FsScandirNext C.uv_fs_scandir_next +func FsScandirNext(req *Fs, ent *Dirent) c.Int + +//go:linkname FsOpenDir C.uv_fs_opendir +func FsOpenDir(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int + +//go:linkname FsReaddir C.uv_fs_readdir +func FsReaddir(loop *Loop, req *Fs, dir c.Int, cb FsCb) c.Int + +//go:linkname FsCloseDir C.uv_fs_closedir +func FsCloseDir(loop *Loop, req *Fs) c.Int + +//go:linkname FsStatfs C.uv_fs_statfs +func FsStatfs(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int + +//go:linkname FsChown C.uv_fs_chown +func FsChown(loop *Loop, req *Fs, path *c.Char, uid c.Int, gid c.Int, cb FsCb) c.Int + +//go:linkname FsFchown C.uv_fs_fchown +func FsFchown(loop *Loop, req *Fs, file c.Int, uid c.Int, gid c.Int, cb FsCb) c.Int + +//go:linkname FsLchown C.uv_fs_lchown +func FsLchown(loop *Loop, req *Fs, path *c.Char, uid c.Int, gid c.Int, cb FsCb) c.Int + +//go:linkname FsLstat C.uv_fs_lstat +func FsLstat(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int + +//go:linkname FsEventInit C.uv_fs_event_init +func FsEventInit(loop *Loop, handle *FsEvent) c.Int + +//go:linkname FsEventStart C.uv_fs_event_start +func FsEventStart(handle *FsEvent, cb FsEventCb, path *c.Char, flags c.Int) c.Int + +//go:linkname FsEventStop C.uv_fs_event_stop +func FsEventStop(handle *FsEvent) c.Int + +//go:linkname FsEventClose C.uv_fs_event_close +func FsEventClose(handle *FsEvent) c.Int + +//go:linkname FsEventGetpath C.uv_fs_event_getpath +func FsEventGetpath(handle *FsEvent) *c.Char + +//go:linkname FsPollInit C.uv_fs_poll_init +func FsPollInit(loop *Loop, handle *FsPoll) c.Int + +//go:linkname FsPollStart C.uv_fs_poll_start +func FsPollStart(handle *FsPoll, cb FsPollCb, path *c.Char, interval uint) c.Int + +//go:linkname FsPollStop C.uv_fs_poll_stop +func FsPollStop(handle *FsPoll) c.Int + +//go:linkname FsPollClose C.uv_fs_poll_close +func FsPollClose(handle *FsPoll) c.Int + +//go:linkname FsPollGetPath C.uv_fs_poll_getpath +func FsPollGetPath(handle *FsPoll) *c.Char + +//TODO: Implemnt uv_poll_init_socket + +// Cleanup cleans up the file system request. +func (f *File) Cleanup() { + FsReqCleanup(f.Req) +} + +func NewFile(loop *Loop, req *Fs) *File { + return &File{ + Loop: loop, + Req: req, + } +} + +// Open opens a file specified by the path with given flags and mode, and returns a file descriptor. +func (f *File) Open(path *c.Char, flags int, mode int, cb FsCb) int { + return FsOpen(f.Loop, f.Req, path, flags, mode, cb) +} + +// Close closes a file descriptor. +func (f *File) Close(file int, cb FsCb) int { + return FsClose(f.Loop, f.Req, file, cb) +} + +// Read reads data from a file descriptor into a buffer at a specified offset. +func (f *File) Read(file c.Int, bufs []Buf, nbufs c.Uint, offset c.Int, cb FsCb) int { + return FsRead(f.Loop, f.Req, file, bufs, nbufs, offset, cb) +} + +// Write writes data to a file descriptor from a buffer at a specified offset. +func (f *File) Write(file c.Int, bufs []Buf, nbufs c.Uint, offset c.Int, cb FsCb) int { + return FsWrite(f.Loop, f.Req, file, bufs, nbufs, offset, cb) +} + +// Unlink deletes a file specified by the path. +func (f *File) Unlink(path *c.Char, cb FsCb) int { + return FsUnlink(f.Loop, f.Req, path, cb) +} + +// Mkdir creates a new directory at the specified path with a specified mode. +func (f *File) Mkdir(path *c.Char, mode int, cb FsCb) int { + return FsMkdir(f.Loop, f.Req, path, mode, cb) +} + +// Mkdtemp creates a temporary directory with a template path. +func (f *File) Mkdtemp(tpl *c.Char, cb FsCb) int { + return FsMkdtemp(f.Loop, f.Req, tpl, cb) +} + +// MkStemp creates a temporary file from a template path. +func (f *File) MkStemp(tpl *c.Char, cb FsCb) int { + return FsMkStemp(f.Loop, f.Req, tpl, cb) +} + +// Rmdir removes a directory specified by the path. +func (f *File) Rmdir(path *c.Char, cb FsCb) int { + return FsRmdir(f.Loop, f.Req, path, cb) +} + +// Stat retrieves status information about the file specified by the path. +func (f *File) Stat(path *c.Char, cb FsCb) int { + return FsStat(f.Loop, f.Req, path, cb) +} + +// Fstat retrieves status information about a file descriptor. +func (f *File) Fstat(file int, cb FsCb) int { + return FsFstat(f.Loop, f.Req, file, cb) +} + +// Rename renames a file from the old path to the new path. +func (f *File) Rename(path *c.Char, newPath *c.Char, cb FsCb) int { + return FsRename(f.Loop, f.Req, path, newPath, cb) +} + +// Fsync synchronizes a file descriptor's state with storage device. +func (f *File) Fsync(file int, cb FsCb) int { + return FsFsync(f.Loop, f.Req, file, cb) +} + +// Fdatasync synchronizes a file descriptor's data with storage device. +func (f *File) Fdatasync(file int, cb FsCb) int { + return FsFdatasync(f.Loop, f.Req, file, cb) +} + +// Ftruncate truncates a file to a specified length. +func (f *File) Ftruncate(file int, offset int, cb FsCb) int { + return FsFtruncate(f.Loop, f.Req, file, offset, cb) +} + +// Sendfile sends data from one file descriptor to another. +func (f *File) Sendfile(outFd int, inFd int, inOffset int, length int, cb FsCb) int { + return FsSendfile(f.Loop, f.Req, outFd, inFd, inOffset, length, cb) +} + +// Access checks the access permissions of a file specified by the path. +func (f *File) Access(path *c.Char, flags int, cb FsCb) int { + return FsAccess(f.Loop, f.Req, path, flags, cb) +} + +// Chmod changes the permissions of a file specified by the path. +func (f *File) Chmod(path *c.Char, mode int, cb FsCb) int { + return FsChmod(f.Loop, f.Req, path, mode, cb) +} + +// Fchmod changes the permissions of a file descriptor. +func (f *File) Fchmod(file int, mode int, cb FsCb) int { + return FsFchmod(f.Loop, f.Req, file, mode, cb) +} + +// Utime updates the access and modification times of a file specified by the path. +func (f *File) Utime(path *c.Char, atime int, mtime int, cb FsCb) int { + return FsUtime(f.Loop, f.Req, path, atime, mtime, cb) +} + +// Futime updates the access and modification times of a file descriptor. +func (f *File) Futime(file int, atime int, mtime int, cb FsCb) int { + return FsFutime(f.Loop, f.Req, file, atime, mtime, cb) +} + +// Lutime updates the access and modification times of a file specified by the path, even if the path is a symbolic link. +func (f *File) Lutime(path *c.Char, atime int, mtime int, cb FsCb) int { + return FsLutime(f.Loop, f.Req, path, atime, mtime, cb) +} + +// Link creates a new link to an existing file. +func (f *File) Link(path *c.Char, newPath *c.Char, cb FsCb) int { + return FsLink(f.Loop, f.Req, path, newPath, cb) +} + +// Symlink creates a symbolic link from the path to the new path. +func (f *File) Symlink(path *c.Char, newPath *c.Char, flags int, cb FsCb) int { + return FsSymlink(f.Loop, f.Req, path, newPath, flags, cb) +} + +// Readlink reads the target of a symbolic link. +func (f *File) Readlink(path *c.Char, cb FsCb) int { + return FsReadlink(f.Loop, f.Req, path, cb) +} + +// Realpath resolves the absolute path of a file. +func (f *File) Realpath(path *c.Char, cb FsCb) int { + return FsRealpath(f.Loop, f.Req, path, cb) +} + +// Copyfile copies a file from the source path to the destination path. +func (f *File) Copyfile(path *c.Char, newPath *c.Char, flags int, cb FsCb) int { + return FsCopyfile(f.Loop, f.Req, path, newPath, flags, cb) +} + +// Scandir scans a directory for entries. +func (f *File) Scandir(path *c.Char, flags int, cb FsCb) int { + return FsScandir(f.Loop, f.Req, path, flags, cb) +} + +// OpenDir opens a directory specified by the path. +func (f *File) OpenDir(path *c.Char, cb FsCb) int { + return FsOpenDir(f.Loop, f.Req, path, cb) +} + +// Readdir reads entries from an open directory. +func (f *File) Readdir(dir int, cb FsCb) int { + return FsReaddir(f.Loop, f.Req, dir, cb) +} + +// CloseDir closes an open directory. +func (f *File) CloseDir() int { + return FsCloseDir(f.Loop, f.Req) +} + +// Statfs retrieves file system status information. +func (f *File) Statfs(path *c.Char, cb FsCb) int { + return FsStatfs(f.Loop, f.Req, path, cb) +} + +// Chown Change file ownership +func (f *File) Chown(path *c.Char, uid int, gid int, cb FsCb) int { + return FsChown(f.Loop, f.Req, path, uid, gid, cb) +} + +// Fchown Change file ownership by file descriptor +func (f *File) Fchown(file int, uid int, gid int, cb FsCb) int { + return FsFchown(f.Loop, f.Req, file, uid, gid, cb) +} + +// Lchown Change file ownership (symlink) +func (f *File) Lchown(path *c.Char, uid int, gid int, cb FsCb) int { + return FsLchown(f.Loop, f.Req, path, uid, gid, cb) +} + +// Lstat Get file status (symlink) +func (f *File) Lstat(path *c.Char, cb FsCb) int { + return FsLstat(f.Loop, f.Req, path, cb) +} + +// Init Initialize a file event handle +func (e *FsEvent) Init(loop *Loop) int { + return FsEventInit(loop, e) +} + +// Start listening for file events +func (e *FsEvent) Start(cb FsEventCb, path *c.Char, flags int) int { + return FsEventStart(e, cb, path, flags) +} + +// Stop listening for file events +func (e *FsEvent) Stop() int { + return FsEventStop(e) +} + +// Close the file event handle +func (e *FsEvent) Close() int { + return FsEventClose(e) +} + +// GetPath Get the path of the file event +func (e *FsEvent) GetPath() *c.Char { + return FsEventGetpath(e) +} + +// Init Initialize a file poll handle +func (p *FsPoll) Init(loop *Loop) int { + return FsPollInit(loop, p) +} + +// Start polling for file changes +func (p *FsPoll) Start(cb FsPollCb, path *c.Char, interval uint) int { + return FsPollStart(p, cb, path, interval) +} + +// Stop polling for file changes +func (p *FsPoll) Stop() int { + return FsPollStop(p) +} + +// Close the file poll handle +func (p *FsPoll) Close() int { + return FsPollClose(p) +} + +// GetPath Get the path of the file poll +func (p *FsPoll) GetPath() *c.Char { + return FsPollGetPath(p) +} diff --git a/c/libuv/libuv.go b/c/libuv/libuv.go new file mode 100644 index 00000000..26a6b6c8 --- /dev/null +++ b/c/libuv/libuv.go @@ -0,0 +1,141 @@ +package libuv + +import ( + "github.com/goplus/llgo/c" + _ "unsafe" +) + +const ( + LLGoPackage = "link: $(pkg-config --libs libuv); -luv" +) + +// ---------------------------------------------- + +const ( + RUN_DEFAULT RunMode = iota + RUN_ONCE + RUN_NOWAIT +) + +type RunMode int + +// ---------------------------------------------- + +/* Handle types. */ + +type Loop struct { + Unused [0]byte +} + +type Handle struct { + Unused [0]byte +} + +type Buf struct { + Base *c.Char + Len uintptr +} + +// ---------------------------------------------- + +/* Function type */ + +// llgo:type C +type WalkCb func(handle *Handle, arg c.Pointer) + +// ---------------------------------------------- + +//go:linkname LoopSize C.uv_loop_size +func LoopSize() uintptr + +// llgo:link (*Loop).Init C.uv_loop_init +func (loop *Loop) Init() c.Int { + return 0 +} + +// llgo:link (*Loop).Run C.uv_loop_run +func (l *Loop) Run(mode c.Int) c.Int { + return 0 +} + +// llgo:link (*Loop).Stop C.uv_loop_stop +func (l *Loop) Stop() { + return +} + +// llgo:link (*Loop).Default C.uv_default_loop +func (l *Loop) Default() *Loop { + return nil +} + +// llgo:link (*Loop).New C.uv_loop_new +func (l *Loop) New() *Loop { + return nil +} + +// Deprecated: use LoopClose instead. +// llgo:link (*Loop).Delete C.uv_loop_delete +func (l *Loop) Delete() { + return +} + +// llgo:link (*Loop).Alive C.uv_loop_alive +func (l *Loop) Alive() c.Int { + return 0 +} + +// llgo:link (*Loop).Close C.uv_loop_close +func (l *Loop) Close() c.Int { + return 0 +} + +// llgo:link (*Loop).Configure C.uv_loop_configure +func (l *Loop) Configure(loop *Loop, option c.Int, arg c.Int) c.Int { + return 0 +} + +// llgo:link (*Loop).Walk C.uv_walk +func (loop *Loop) Walk(walkCb WalkCb, arg c.Pointer) {} + +// llgo:link (*Loop).Fork C.uv_loop_fork +func (l *Loop) Fork(loop *Loop) int { + return 0 +} + +// llgo:link (*Loop).UpdateTime C.uv_update_time +func (l *Loop) UpdateTime() { + return +} + +// llgo:link (*Loop).Now C.uv_now +func (l *Loop) Now() uint64 { + return 0 +} + +// llgo:link (*Loop).BackendFd C.uv_backend_fd +func (l *Loop) BackendFd() int { + return 0 +} + +// llgo:link (*Loop).BackendTimeout C.uv_backend_timeout +func (l *Loop) BackendTimeout() int { + return 0 +} + +// llgo:link (*Handle).Ref C.uv_ref +func (h *Handle) Ref() { + return +} + +// llgo:link (*Handle).Unref C.uv_unref +func (h *Handle) Unref() { + return +} + +// llgo:link (*Handle).HasRef C.uv_has_ref +func (h *Handle) HasRef() int { + return 0 +} + +//go:linkname InitBuf C.uv_buf_init +func InitBuf(base *c.Char, len c.Uint) Buf diff --git a/c/libuv/signal.go b/c/libuv/signal.go new file mode 100644 index 00000000..46b6eb9d --- /dev/null +++ b/c/libuv/signal.go @@ -0,0 +1,30 @@ +package libuv + +import ( + "github.com/goplus/llgo/c" + _ "unsafe" +) + +type Signal struct { + Unused [0]byte +} + +// llgo:type C +type SignalCb func(handle *Signal, sigNum c.Int) + +//go:linkname UvSignalInit C.uv_signal_init +func UvSignalInit(loop *Loop, handle *Signal) c.Int + +// llgo:link (*Signal).Start C.uv_signal_start +func (s *Signal) Start(cb SignalCb, signum c.Int) c.Int { + return 0 +} + +// llgo:link (*Signal).StartOneshot C.uv_signal_start_oneshot +func (s *Signal) StartOneshot(handle *Signal, cb SignalCb, signum c.Int) c.Int { + return 0 +} + +func (s *Signal) Init(loop *Loop) int { + return UvSignalInit(loop, s) +} From 545f9f2ccae5e98506b98999cacfb2f61490a84e Mon Sep 17 00:00:00 2001 From: hackerchai Date: Tue, 23 Jul 2024 11:01:28 +0800 Subject: [PATCH 2/6] feat(c/libuv/demo): Add libuv async_fs demo Signed-off-by: hackerchai fix(c/libuv): fix fs demo Signed-off-by: hackerchai refactor(c/libuv): neat comment and adapt merge Signed-off-by: hackerchai --- c/libuv/_demo/libuv/fs.go | 70 +++++++++++++++++++++++++++++++ c/libuv/fs.go | 87 +++++++++++++++++++++++++++++++++++++-- c/libuv/libuv.go | 21 ++-------- c/libuv/signal.go | 6 +++ 4 files changed, 163 insertions(+), 21 deletions(-) create mode 100644 c/libuv/_demo/libuv/fs.go diff --git a/c/libuv/_demo/libuv/fs.go b/c/libuv/_demo/libuv/fs.go new file mode 100644 index 00000000..7d50f2e9 --- /dev/null +++ b/c/libuv/_demo/libuv/fs.go @@ -0,0 +1,70 @@ +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) +} diff --git a/c/libuv/fs.go b/c/libuv/fs.go index 3381e5bb..555b5b0f 100644 --- a/c/libuv/fs.go +++ b/c/libuv/fs.go @@ -5,6 +5,47 @@ import ( _ "unsafe" ) +const ( + FS_UNKNOWN FsType = -1 + FS_CUSTOM FsType = 0 + FS_OPEN FsType = 1 + FS_CLOSE FsType = 2 + FS_READ FsType = 3 + FS_WRITE FsType = 4 + FS_SENDFILE FsType = 5 + FS_STAT FsType = 6 + FS_LSTAT FsType = 7 + FS_FSTAT FsType = 8 + FS_FTRUNCATE FsType = 9 + FS_UTIME FsType = 10 + FS_FUTIME FsType = 11 + FS_ACCESS FsType = 12 + FS_CHMOD FsType = 13 + FS_FCHMOD FsType = 14 + FS_FSYNC FsType = 15 + FS_FDATASYNC FsType = 16 + FS_UNLINK FsType = 17 + FS_RMDIR FsType = 18 + FS_MKDIR FsType = 19 + FS_MKDTEMP FsType = 20 + FS_RENAME FsType = 21 + FS_SCANDIR FsType = 22 + FS_LINK FsType = 23 + FS_SYMLINK FsType = 24 + FS_READLINK FsType = 25 + FS_CHOWN FsType = 26 + FS_FCHOWN FsType = 27 + FS_REALPATH FsType = 28 + FS_COPYFILE FsType = 29 + FS_LCHOWN FsType = 30 + FS_OPENDIR FsType = 31 + FS_READDIR FsType = 32 + FS_CLOSEDIR FsType = 33 + FS_STATFS FsType = 34 + FS_MKSTEMP FsType = 35 + FS_LUTIME FsType = 36 +) + const ( DirentUnknown DirentType = iota DirentFile @@ -16,8 +57,12 @@ const ( DirentBlock ) +type FsType int + type DirentType int +// ---------------------------------------------- + /* Handle types. */ type Fs struct { @@ -42,6 +87,14 @@ type File struct { Req *Fs } +type Stat struct { + Unused [0]byte +} + +// ---------------------------------------------- + +/* Function type */ + // llgo:type C type FsCb func(req *Fs) @@ -51,14 +104,40 @@ type FsEventCb func(handle *FsEvent, filename *c.Char, events c.Int, status c.In // llgo:type C type FsPollCb func(handle *FsPoll, status c.Int, events c.Int) -/* Request types. */ - -/* None of the above. */ - // ---------------------------------------------- /* Fs related function and method */ +// llgo:link (*Fs).GetType C.uv_fs_get_type +func (f *Fs) GetType() *FsType { + return nil +} + +// llgo:link (*Fs).GetPath C.uv_fs_get_path +func (f *Fs) GetPath() *c.Char { + return nil +} + +// llgo:link (*Fs).GetResult C.uv_fs_get_result +func (f *Fs) GetResult() c.Int { + return 0 +} + +// llgo:link (*Fs).GetPtr C.uv_fs_get_ptr +func (f *Fs) GetPtr() c.Pointer { + return nil +} + +// llgo:link (*Fs).GetSystemError C.uv_fs_get_system_error +func (f *Fs) GetSystemError() c.Int { + return 0 +} + +// llgo:link (*Fs).GetStatBuf C.uv_fs_get_statbuf +func (f *Fs) GetStatBuf() *Stat { + return nil +} + //go:linkname FsReqCleanup C.uv_fs_req_cleanup func FsReqCleanup(req *Fs) diff --git a/c/libuv/libuv.go b/c/libuv/libuv.go index 26a6b6c8..7ca9e964 100644 --- a/c/libuv/libuv.go +++ b/c/libuv/libuv.go @@ -27,10 +27,6 @@ type Loop struct { Unused [0]byte } -type Handle struct { - Unused [0]byte -} - type Buf struct { Base *c.Char Len uintptr @@ -45,6 +41,8 @@ type WalkCb func(handle *Handle, arg c.Pointer) // ---------------------------------------------- +/* Loop related functions and method. */ + //go:linkname LoopSize C.uv_loop_size func LoopSize() uintptr @@ -122,20 +120,9 @@ func (l *Loop) BackendTimeout() int { return 0 } -// llgo:link (*Handle).Ref C.uv_ref -func (h *Handle) Ref() { - return -} +// ---------------------------------------------- -// llgo:link (*Handle).Unref C.uv_unref -func (h *Handle) Unref() { - return -} - -// llgo:link (*Handle).HasRef C.uv_has_ref -func (h *Handle) HasRef() int { - return 0 -} +/* Buf related functions and method. */ //go:linkname InitBuf C.uv_buf_init func InitBuf(base *c.Char, len c.Uint) Buf diff --git a/c/libuv/signal.go b/c/libuv/signal.go index 46b6eb9d..97847d1c 100644 --- a/c/libuv/signal.go +++ b/c/libuv/signal.go @@ -5,10 +5,16 @@ import ( _ "unsafe" ) +/* Handle types. */ + type Signal struct { Unused [0]byte } +// ---------------------------------------------- + +/* Signal related functions and method. */ + // llgo:type C type SignalCb func(handle *Signal, sigNum c.Int) From e9d4328fadaebc7192c4c98a5f692d95b5682f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E8=8B=B1=E6=9D=B0?= Date: Fri, 19 Jul 2024 15:17:20 +0800 Subject: [PATCH 3/6] feat(c/libuv): Add tcp, udp, poll, core, stream, err features feat(c/io): add libuv async io with io, tcp, udp, timer, dns, loop feat(c/io): add libuv async io with stream, req, handle feat(c/libuv): rename c/io to c/libuv, and improve errro, net, handle, stream feat(c/libuv): Add a libuv demo: echo_server refactor(c/libuv): Adjust comments and file names to accommodate merge --- c/libuv/error.go | 198 ++++++++++++++++++++ c/libuv/libuv.go | 460 +++++++++++++++++++++++++++++++++++++++-------- c/libuv/net.go | 256 ++++++++++++++++++++++++++ c/libuv/timer.go | 42 +++++ c/net/net.go | 13 ++ 5 files changed, 895 insertions(+), 74 deletions(-) create mode 100644 c/libuv/error.go create mode 100644 c/libuv/net.go create mode 100644 c/libuv/timer.go diff --git a/c/libuv/error.go b/c/libuv/error.go new file mode 100644 index 00000000..95ee68dd --- /dev/null +++ b/c/libuv/error.go @@ -0,0 +1,198 @@ +package libuv + +import ( + "github.com/goplus/llgo/c" + _ "unsafe" +) + +const ( + E2BIG Errno = iota + EACCES + EADDRINUSE + EADDRNOTAVAIL + EAFNOSUPPORT + EAGAIN + EAI_ADDRFAMILY + EAI_AGAIN + EAI_BADFLAGS + EAI_BADHINTS + EAI_CANCELED + EAI_FAIL + EAI_FAMILY + EAI_MEMORY + EAI_NODATA + EAI_NONAME + EAI_OVERFLOW + EAI_PROTOCOL + EAI_SERVICE + EAI_SOCKTYPE + EALREADY + EBADF + EBUSY + ECANCELED + ECHARSET + ECONNABORTED + ECONNREFUSED + ECONNRESET + EDESTADDRREQ + EEXIST + EFAULT + EFBIG + EHOSTUNREACH + EINTR + EINVAL + EIO + EISCONN + EISDIR + ELOOP + EMFILE + EMSGSIZE + ENAMETOOLONG + ENETDOWN + ENETUNREACH + ENFILE + ENOBUFS + ENODEV + ENOENT + ENOMEM + ENONET + ENOPROTOOPT + ENOSPC + ENOSYS + ENOTCONN + ENOTDIR + ENOTEMPTY + ENOTSOCK + ENOTSUP + EOVERFLOW + EPERM + EPIPE + EPROTO + EPROTONOSUPPORT + EPROTOTYPE + ERANGE + EROFS + ESHUTDOWN + ESPIPE + ESRCH + ETIMEDOUT + ETXTBSY + EXDEV + UNKNOWN + EOF + ENXIO + EMLINK + EHOSTDOWN + EREMOTEIO + ENOTTY + EFTYPE + EILSEQ + ESOCKTNOSUPPORT + ENODATA + EUNATCH + ERRNO_MAX +) + +//var errnoDescriptions = map[Errno]string{ +// E2BIG: "argument list too long", +// EACCES: "permission denied", +// EADDRINUSE: "address already in use", +// EADDRNOTAVAIL: "address not available", +// EAFNOSUPPORT: "address family not supported", +// EAGAIN: "resource temporarily unavailable", +// EAI_ADDRFAMILY: "address family not supported", +// EAI_AGAIN: "temporary failure", +// EAI_BADFLAGS: "bad ai_flags value", +// EAI_BADHINTS: "invalid value for hints", +// EAI_CANCELED: "request canceled", +// EAI_FAIL: "permanent failure", +// EAI_FAMILY: "ai_family not supported", +// EAI_MEMORY: "out of memory", +// EAI_NODATA: "no address", +// EAI_NONAME: "unknown node or service", +// EAI_OVERFLOW: "argument buffer overflow", +// EAI_PROTOCOL: "resolved protocol is unknown", +// EAI_SERVICE: "service not available for socket type", +// EAI_SOCKTYPE: "socket type not supported", +// EALREADY: "connection already in progress", +// EBADF: "bad file descriptor", +// EBUSY: "resource busy or locked", +// ECANCELED: "operation canceled", +// ECHARSET: "invalid Unicode character", +// ECONNABORTED: "software caused connection abort", +// ECONNREFUSED: "connection refused", +// ECONNRESET: "connection reset by peer", +// EDESTADDRREQ: "destination address required", +// EEXIST: "file already exists", +// EFAULT: "bad address in system call argument", +// EFBIG: "file too large", +// EHOSTUNREACH: "host is unreachable", +// EINTR: "interrupted system call", +// EINVAL: "invalid argument", +// EIO: "i/o error", +// EISCONN: "socket is already connected", +// EISDIR: "illegal operation on a directory", +// ELOOP: "too many symbolic links encountered", +// EMFILE: "too many open files", +// EMSGSIZE: "message too long", +// ENAMETOOLONG: "name too long", +// ENETDOWN: "network is down", +// ENETUNREACH: "network is unreachable", +// ENFILE: "file table overflow", +// ENOBUFS: "no buffer space available", +// ENODEV: "no such device", +// ENOENT: "no such file or directory", +// ENOMEM: "not enough memory", +// ENONET: "machine is not on the network", +// ENOPROTOOPT: "protocol not available", +// ENOSPC: "no space left on device", +// ENOSYS: "function not implemented", +// ENOTCONN: "socket is not connected", +// ENOTDIR: "not a directory", +// ENOTEMPTY: "directory not empty", +// ENOTSOCK: "socket operation on non-socket", +// ENOTSUP: "operation not supported on socket", +// EOVERFLOW: "value too large for defined data type", +// EPERM: "operation not permitted", +// EPIPE: "broken pipe", +// EPROTO: "protocol error", +// EPROTONOSUPPORT: "protocol not supported", +// EPROTOTYPE: "protocol wrong type for socket", +// ERANGE: "result too large", +// EROFS: "read-only file system", +// ESHUTDOWN: "cannot send after transport endpoint shutdown", +// ESPIPE: "invalid seek", +// ESRCH: "no such process", +// ETIMEDOUT: "connection timed out", +// ETXTBSY: "text file is busy", +// EXDEV: "cross-device link not permitted", +// UNKNOWN: "unknown error", +// EOF: "end of file", +// ENXIO: "no such device or address", +// EMLINK: "too many links", +// EHOSTDOWN: "host is down", +// EREMOTEIO: "remote I/O error", +// ENOTTY: "inappropriate ioctl for device", +// EFTYPE: "inappropriate file type or format", +// EILSEQ: "illegal byte sequence", +// ESOCKTNOSUPPORT: "socket type not supported", +// ENODATA: "no data available", +// EUNATCH: "protocol driver not attached", +//} + +type Errno c.Int + +//go:linkname TranslateSysError C.uv_translate_sys_error +func TranslateSysError(sysErrno c.Int) c.Int + +//go:linkname Strerror C.uv_strerror +func Strerror(err c.Int) *c.Char + +//go:linkname StrerrorR C.uv_strerror_r +func StrerrorR(err c.Int, buf *c.Char, bufLen uintptr) *c.Char + +//go:linkname ErrName C.uv_err_name +func ErrName(err c.Int) *c.Char + +//go:linkname ErrNameR C.uv_err_name_r +func ErrNameR(err c.Int, buf *c.Char, bufLen uintptr) *c.Char diff --git a/c/libuv/libuv.go b/c/libuv/libuv.go index 7ca9e964..004b223d 100644 --- a/c/libuv/libuv.go +++ b/c/libuv/libuv.go @@ -2,6 +2,7 @@ package libuv import ( "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/net" _ "unsafe" ) @@ -11,22 +12,183 @@ const ( // ---------------------------------------------- +const ( + LOOP_BLOCK_SIGNAL LoopOption = iota + METRICS_IDLE_TIME +) + const ( RUN_DEFAULT RunMode = iota RUN_ONCE RUN_NOWAIT ) -type RunMode int +const ( + UV_LEAVE_GROUP Membership = iota + UV_JOIN_GROUP +) + +const ( + UNKNOWN_HANDLE HandleType = iota + ASYNC + CHECK + FS_EVENT + FS_POLL + HANDLE + IDLE + NAMED_PIPE + POLL + PREPARE + PROCESS + STREAM + TCP + TIMER + TTY + UDP + SIGNAL + FILE + HANDLE_TYPE_MAX +) + +const ( + UNKNOWN_REQ ReqType = iota + REQ + CONNECT + WRITE + SHUTDOWN + UDP_SEND + FS + WORK + GETADDRINFO + GETNAMEINFO + RANDOM + REQ_TYPE_PRIVATE + REQ_TYPE_MAX +) + +type LoopOption c.Int + +type RunMode c.Int + +type Membership c.Int + +type HandleType c.Int + +type ReqType c.Int + +type Uv_File c.Int + +type OsSock c.Int + +type OsFd c.Int // ---------------------------------------------- /* Handle types. */ - type Loop struct { Unused [0]byte } +type Handle struct { + Unused [0]byte +} + +type Dir struct { + Unused [0]byte +} + +type Stream struct { + Unused [0]byte +} + +type Tcp struct { + Unused [0]byte +} + +type Udp struct { + Unused [0]byte +} + +type Pipe struct { + Unused [0]byte +} + +type Tty struct { + Unused [0]byte +} + +type Poll struct { + Unused [0]byte +} + +type Timer struct { + Unused [0]byte +} + +type Prepare struct { + Unused [0]byte +} + +type Check struct { + Unused [0]byte +} + +type Idle struct { + Unused [0]byte +} + +type Async struct { + Unused [0]byte +} + +type Process struct { + Unused [0]byte +} + +type FsEvent struct { + Unused [0]byte +} + +type FsPoll struct { + Unused [0]byte +} + +type Signal struct { + Unused [0]byte +} + +/* Request types. */ + +type Req struct { + Unused [0]byte +} + +type GetAddrInfo struct { + Unused [0]byte +} + +type GetNameInfo struct { + Unused [0]byte +} + +type Shutdown struct { + Unused [0]byte +} + +type Write struct { + Unused [0]byte +} + +type Connect struct { + Unused [0]byte +} + +type UdpSend struct { + Unused [0]byte +} + +// ---------------------------------------------- + type Buf struct { Base *c.Char Len uintptr @@ -36,93 +198,243 @@ type Buf struct { /* Function type */ +// llgo:type C +type MallocFunc func(size uintptr) c.Pointer + +// llgo:type C +type ReallocFunc func(ptr c.Pointer, size uintptr) c.Pointer + +// llgo:type C +type CallocFunc func(count uintptr, size uintptr) c.Pointer + +// llgo:type C +type FreeFunc func(ptr c.Pointer) + +// llgo:type C +type AllocCb func(handle *Handle, suggestedSize uintptr, buf *Buf) + +// llgo:type C +type ReadCb func(stream *Stream, nread c.Long, buf *Buf) + +// llgo:type C +type WriteCb func(req *Write, status c.Int) + +// llgo:type C +type GetaddrinfoCb func(req *GetAddrInfo, status c.Int, res *net.AddrInfo) + +// llgo:type C +type GetnameinfoCb func(req *GetNameInfo, status c.Int, hostname *c.Char, service *c.Char) + +// llgo:type C +type ConnectionCb func(server *Stream, status c.Int) + +// llgo:type C +type ShutdownCb func(req *Shutdown, status c.Int) + // llgo:type C type WalkCb func(handle *Handle, arg c.Pointer) // ---------------------------------------------- -/* Loop related functions and method. */ +//go:linkname Version C.uv_version +func Version() c.Uint -//go:linkname LoopSize C.uv_loop_size -func LoopSize() uintptr +//go:linkname VersionString C.uv_version_string +func VersionString() *c.Char -// llgo:link (*Loop).Init C.uv_loop_init -func (loop *Loop) Init() c.Int { - return 0 -} +//go:linkname LibraryShutdown C.uv_library_shutdown +func LibraryShutdown() -// llgo:link (*Loop).Run C.uv_loop_run -func (l *Loop) Run(mode c.Int) c.Int { - return 0 -} +//go:linkname ReplaceAllocator C.uv_replace_allocator +func ReplaceAllocator(mallocFunc MallocFunc, reallocFunc ReallocFunc, callocFunc CallocFunc, freeFunc FreeFunc) c.Int -// llgo:link (*Loop).Stop C.uv_loop_stop -func (l *Loop) Stop() { - return -} +// ---------------------------------------------- -// llgo:link (*Loop).Default C.uv_default_loop -func (l *Loop) Default() *Loop { - return nil -} - -// llgo:link (*Loop).New C.uv_loop_new -func (l *Loop) New() *Loop { - return nil -} - -// Deprecated: use LoopClose instead. -// llgo:link (*Loop).Delete C.uv_loop_delete -func (l *Loop) Delete() { - return -} - -// llgo:link (*Loop).Alive C.uv_loop_alive -func (l *Loop) Alive() c.Int { - return 0 -} - -// llgo:link (*Loop).Close C.uv_loop_close -func (l *Loop) Close() c.Int { - return 0 -} - -// llgo:link (*Loop).Configure C.uv_loop_configure -func (l *Loop) Configure(loop *Loop, option c.Int, arg c.Int) c.Int { - return 0 -} - -// llgo:link (*Loop).Walk C.uv_walk -func (loop *Loop) Walk(walkCb WalkCb, arg c.Pointer) {} - -// llgo:link (*Loop).Fork C.uv_loop_fork -func (l *Loop) Fork(loop *Loop) int { - return 0 -} - -// llgo:link (*Loop).UpdateTime C.uv_update_time -func (l *Loop) UpdateTime() { - return -} - -// llgo:link (*Loop).Now C.uv_now -func (l *Loop) Now() uint64 { - return 0 -} - -// llgo:link (*Loop).BackendFd C.uv_backend_fd -func (l *Loop) BackendFd() int { - return 0 -} - -// llgo:link (*Loop).BackendTimeout C.uv_backend_timeout -func (l *Loop) BackendTimeout() int { +// llgo:link (*Shutdown).Shutdown C.uv_shutdown +func (shutdown *Shutdown) Shutdown(stream *Stream, shutdownCb ShutdownCb) c.Int { return 0 } // ---------------------------------------------- -/* Buf related functions and method. */ +/* HandleT related function and method */ + +// llgo:link (*Handle).Ref C.uv_ref +func (handle *Handle) Ref() {} + +// llgo:link (*Handle).Unref C.uv_unref +func (handle *Handle) Unref() {} + +// llgo:link (*Handle).HasRef C.uv_has_ref +func (handle *Handle) HasRef() c.Int { + return 0 +} + +//go:linkname HandleSize C.uv_handle_size +func HandleSize(handleType HandleType) uintptr + +// llgo:link (*Handle).GetType C.uv_handle_get_type +func (handle *Handle) GetType() HandleType { + return 0 +} + +//go:linkname HandleTypeName C.uv_handle_type_name +func HandleTypeName(handleType HandleType) *c.Char + +// llgo:link (*Handle).GetData C.uv_handle_get_data +func (handle *Handle) GetData() c.Pointer { + return nil +} + +// llgo:link (*Handle).GetLoop C.uv_handle_get_loop +func (handle *Handle) GetLoop() *Loop { + return nil +} + +// llgo:link (*Handle).SetData C.uv_handle_set_data +func (handle *Handle) SetData(data c.Pointer) {} + +// llgo:link (*Handle).IsActive C.uv_is_active +func (handle *Handle) IsActive() c.Int { + return 0 +} + +// llgo:link (*Handle).Close C.uv_close +func (handle *Handle) Close(closeCb CloseCb) {} + +// llgo:link (*Handle).SendBufferSize C.uv_send_buffer_size +func (handle *Handle) SendBufferSize(value *c.Int) c.Int { + return 0 +} + +// llgo:link (*Handle).RecvBufferSize C.uv_recv_buffer_size +func (handle *Handle) RecvBufferSize(value *c.Int) c.Int { + return 0 +} + +// llgo:link (*Handle).Fileno C.uv_fileno +func (handle *Handle) Fileno(fd *OsFd) c.Int { + return 0 +} //go:linkname InitBuf C.uv_buf_init func InitBuf(base *c.Char, len c.Uint) Buf + +//go:linkname UvPipe C.uv_pipe +func UvPipe(fds [2]Uv_File, readFlags c.Int, writeFlags c.Int) c.Int { + return 0 +} + +//go:linkname Socketpair C.uv_socketpair +func Socketpair(_type c.Int, protocol c.Int, socketVector [2]OsSock, flag0 c.Int, flag1 c.Int) c.Int { + return 0 +} + +// llgo:link (*Handle).IsClosing C.uv_is_closing +func (handle *Handle) IsClosing() c.Int { + return 0 +} + +// ---------------------------------------------- + +/* Req related function and method */ + +//go:linkname ReqSize C.uv_req_size +func ReqSize(reqType ReqType) uintptr + +// llgo:link (*Req).GetData C.uv_req_get_data +func (req *Req) GetData() c.Pointer { + return nil +} + +// llgo:link (*Req).SetData C.uv_handle_set_data +func (req *Req) SetData(data c.Pointer) {} + +// llgo:link (*Req).GetType C.uv_req_get_type +func (req *Req) GetType() ReqType { + return 0 +} + +//go:linkname TypeName C.uv_req_type_name +func TypeName(reqType ReqType) *c.Char + +// ---------------------------------------------- + +/* Stream related function and method */ + +// llgo:link (*Stream).GetWriteQueueSize C.uv_stream_get_write_queue_size +func (stream *Stream) GetWriteQueueSize() uintptr { + return 0 +} + +// llgo:link (*Stream).Listen C.uv_listen +func (stream *Stream) Listen(backlog c.Int, connectionCb ConnectionCb) c.Int { + return 0 +} + +// llgo:link (*Stream).Accept C.uv_accept +func (server *Stream) Accept(client *Stream) c.Int { + return 0 +} + +// llgo:link (*Stream).StartRead C.uv_read_start +func (stream *Stream) StartRead(allocCb AllocCb, readCb ReadCb) c.Int { + return 0 +} + +// llgo:link (*Stream).StopRead C.uv_read_stop +func (stream *Stream) StopRead() c.Int { + return 0 +} + +// llgo:link (*Write).Write C.uv_write +func (req *Write) Write(stream *Stream, bufs []Buf, nbufs c.Uint, writeCb WriteCb) c.Int { + return 0 +} + +// llgo:link (*Write).Write2 C.uv_write2 +func (req *Write) Write2(stream *Stream, bufs []Buf, nbufs c.Uint, sendStream *Stream, writeCb WriteCb) c.Int { + return 0 +} + +// llgo:link (*Stream).TryWrite C.uv_try_write +func (stream *Stream) TryWrite(bufs []Buf, nbufs c.Uint) c.Int { + return 0 +} + +// llgo:link (*Stream).TryWrite2 C.uv_try_write2 +func (stream *Stream) TryWrite2(bufs []Buf, nbufs c.Uint, sendStream *Stream) c.Int { + return 0 +} + +// llgo:link (*Stream).IsReadable C.uv_is_readable +func (stream *Stream) IsReadable() c.Int { + return 0 +} + +// llgo:link (*Stream).IsWritable C.uv_is_writable +func (stream *Stream) IsWritable() c.Int { + return 0 +} + +// llgo:link (*Stream).SetBlocking C.uv_stream_set_blocking +func (stream *Stream) SetBlocking(blocking c.Int) c.Int { + return 0 +} + +// ---------------------------------------------- + +/* Getaddrinfo related function and method */ + +//go:linkname Getaddrinfo C.uv_getaddrinfo +func Getaddrinfo(loop *Loop, req *GetAddrInfo, getaddrinfoCb GetaddrinfoCb, node *c.Char, service *c.Char, hints *net.AddrInfo) c.Int + +//go:linkname Freeaddrinfo C.uv_freeaddrinfo +func Freeaddrinfo(addrInfo *net.AddrInfo) + +// ---------------------------------------------- + +/* Getnameinfo related function and method */ + +//go:linkname Getnameinfo C.uv_getnameinfo +func Getnameinfo(loop *Loop, req *GetNameInfo, getnameinfoCb GetnameinfoCb, addr *net.SockAddr, flags c.Int) c.Int diff --git a/c/libuv/net.go b/c/libuv/net.go new file mode 100644 index 00000000..1e5f7590 --- /dev/null +++ b/c/libuv/net.go @@ -0,0 +1,256 @@ +package libuv + +import ( + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/net" + _ "unsafe" +) + +const ( + /* Used with uv_tcp_bind, when an IPv6 address is used. */ + TCP_IPV6ONLY TcpFlags = 1 +) + +/* + * UDP support. + */ +const ( + /* Disables dual stack mode. */ + UDP_IPV6ONLY UdpFlags = 1 + /* + * Indicates message was truncated because read buffer was too small. The + * remainder was discarded by the OS. Used in uv_udp_recv_cb. + */ + UDP_PARTIAL UdpFlags = 2 + /* + * Indicates if SO_REUSEADDR will be set when binding the handle. + * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other + * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that + * multiple threads or processes can bind to the same address without error + * (provided they all set the flag) but only the last one to bind will receive + * any traffic, in effect "stealing" the port from the previous listener. + */ + UDP_REUSEADDR UdpFlags = 4 + /* + * Indicates that the message was received by recvmmsg, so the buffer provided + * must not be freed by the recv_cb callback. + */ + UDP_MMSG_CHUNK UdpFlags = 8 + /* + * Indicates that the buffer provided has been fully utilized by recvmmsg and + * that it should now be freed by the recv_cb callback. When this flag is set + * in uv_udp_recv_cb, nread will always be 0 and addr will always be NULL. + */ + UDP_MMSG_FREE UdpFlags = 16 + /* + * Indicates if IP_RECVERR/IPV6_RECVERR will be set when binding the handle. + * This sets IP_RECVERR for IPv4 and IPV6_RECVERR for IPv6 UDP sockets on + * Linux. This stops the Linux kernel from suppressing some ICMP error + * messages and enables full ICMP error reporting for faster failover. + * This flag is no-op on platforms other than Linux. + */ + UDP_LINUX_RECVERR UdpFlags = 32 + /* + * Indicates that recvmmsg should be used, if available. + */ + UDP_RECVMMSG UdpFlags = 256 +) + +type TcpFlags c.Int + +type UdpFlags c.Int + +// ---------------------------------------------- + +/* Function type */ + +// llgo:type C +type CloseCb func(handle *Handle) + +// llgo:type C +type ConnectCb func(req *Connect, status c.Int) + +// llgo:type C +type UdpSendCb func(req *UdpSend, status c.Int) + +// llgo:type C +type UdpRecvCb func(handle *Udp, nread c.Long, buf *Buf, addr *net.SockAddr, flags c.Uint) + +// ---------------------------------------------- + +/* TcpT related function and method */ + +//go:linkname InitTcp C.uv_tcp_init +func InitTcp(loop *Loop, tcp *Tcp) c.Int + +//go:linkname InitTcpEx C.uv_tcp_init_ex +func InitTcpEx(loop *Loop, tcp *Tcp, flags c.Uint) c.Int + +// llgo:link (*Tcp).Open C.uv_tcp_open +func (tcp *Tcp) Open(sock OsSock) c.Int { + return 0 +} + +// llgo:link (*Tcp).Nodelay C.uv_tcp_nodelay +func (tcp *Tcp) Nodelay(enable c.Int) c.Int { + return 0 +} + +// llgo:link (*Tcp).KeepAlive C.uv_tcp_keepalive +func (tcp *Tcp) KeepAlive(enable c.Int, delay c.Uint) c.Int { + return 0 +} + +// llgo:link (*Tcp).SimultaneousAccepts C.uv_tcp_simultaneous_accepts +func (tcp *Tcp) SimultaneousAccepts(enable c.Int) c.Int { + return 0 +} + +// llgo:link (*Tcp).Bind C.uv_tcp_bind +func (tcp *Tcp) Bind(addr *net.SockAddr, flags c.Uint) c.Int { + return 0 +} + +// llgo:link (*Tcp).Getsockname C.uv_tcp_getsockname +func (tcp *Tcp) Getsockname(name *net.SockAddr, nameLen *c.Int) c.Int { + return 0 +} + +// llgo:link (*Tcp).Getpeername C.uv_tcp_getpeername +func (tcp *Tcp) Getpeername(name *net.SockAddr, nameLen *c.Int) c.Int { + return 0 +} + +// llgo:link (*Tcp).CloseReset C.uv_tcp_close_reset +func (tcp *Tcp) CloseReset(closeCb CloseCb) c.Int { + return 0 +} + +//go:linkname TcpConnect C.uv_tcp_connect +func TcpConnect(req *Connect, tcp *Tcp, addr *net.SockAddr, connectCb ConnectCb) c.Int + +// ---------------------------------------------- + +/* UdpT related function and method */ + +//go:linkname InitUdp C.uv_udp_init +func InitUdp(loop *Loop, udp *Udp) c.Int + +//go:linkname InitUdpEx C.uv_udp_init_ex +func InitUdpEx(loop *Loop, udp *Udp, flags c.Uint) c.Int + +// llgo:link (*Udp).Open C.uv_udp_open +func (udp *Udp) Open(sock OsSock) c.Int { + return 0 +} + +// llgo:link (*Udp).Bind C.uv_udp_bind +func (udp *Udp) Bind(addr *net.SockAddr, flags c.Uint) c.Int { + return 0 +} + +// llgo:link (*Udp).Connect C.uv_udp_connect +func (udp *Udp) Connect(addr *net.SockAddr) c.Int { + return 0 +} + +// llgo:link (*Udp).Getpeername C.uv_udp_getpeername +func (udp *Udp) Getpeername(name *net.SockAddr, nameLen *c.Int) c.Int { + return 0 +} + +// llgo:link (*Udp).Getsockname C.uv_udp_getsockname +func (udp *Udp) Getsockname(name *net.SockAddr, nameLen *c.Int) c.Int { + return 0 +} + +// llgo:link (*Udp).SetMembership C.uv_udp_set_membership +func (udp *Udp) SetMembership(multicastAddr *c.Char, interfaceAddr *c.Char, membership Membership) c.Int { + return 0 +} + +// llgo:link (*Udp).SourceMembership C.uv_udp_set_source_membership +func (udp *Udp) SourceMembership(multicastAddr *c.Char, interfaceAddr *c.Char, sourceAddr *c.Char, membership Membership) c.Int { + return 0 +} + +// llgo:link (*Udp).SetMulticastLoop C.uv_udp_set_multicast_loop +func (udp *Udp) SetMulticastLoop(on c.Int) c.Int { + return 0 +} + +// llgo:link (*Udp).SetMulticastTTL C.uv_udp_set_multicast_ttl +func (udp *Udp) SetMulticastTTL(ttl c.Int) c.Int { + return 0 +} + +// llgo:link (*Udp).SetMulticastInterface C.uv_udp_set_multicast_interface +func (udp *Udp) SetMulticastInterface(interfaceAddr *c.Char) c.Int { + return 0 +} + +// llgo:link (*Udp).SAetBroadcast C.uv_udp_set_broadcast +func (udp *Udp) SAetBroadcast(on c.Int) c.Int { + return 0 +} + +// llgo:link (*Udp).SetTTL C.uv_udp_set_ttl +func (udp *Udp) SetTTL(ttl c.Int) c.Int { + return 0 +} + +//go:linkname Send C.uv_udp_send +func Send(req *UdpSend, udp *Udp, bufs []Buf, nbufs c.Uint, addr *net.SockAddr, sendCb UdpSendCb) c.Int + +// llgo:link (*Udp).TrySend C.uv_udp_try_send +func (udp *Udp) TrySend(bufs []Buf, nbufs c.Uint, addr *net.SockAddr) c.Int { + return 0 +} + +// llgo:link (*Udp).RecvStart C.uv_udp_recv_start +func (udp *Udp) RecvStart(allocCb AllocCb, recvCb UdpRecvCb) c.Int { + return 0 +} + +// llgo:link (*Udp).UsingRecvmmsg C.uv_udp_using_recvmmsg +func (udp *Udp) UsingRecvmmsg() c.Int { + return 0 +} + +// llgo:link (*Udp).RecvStop C.uv_udp_recv_stop +func (udp *Udp) RecvStop() c.Int { + return 0 +} + +// llgo:link (*Udp).GetSendQueueSize C.uv_udp_get_send_queue_size +func (udp *Udp) GetSendQueueSize() uintptr { + return 0 +} + +// llgo:link (*Udp).GetSendQueueCount C.uv_udp_get_send_queue_count +func (udp *Udp) GetSendQueueCount() uintptr { + return 0 +} + +// ---------------------------------------------- + +//go:linkname Ip4Addr C.uv_ip4_addr +func Ip4Addr(ip *c.Char, port c.Int, addr *net.SockaddrIn) c.Int + +//go:linkname Ip6Addr C.uv_ip6_addr +func Ip6Addr(ip *c.Char, port c.Int, addr *net.SockaddrIn6) c.Int + +//go:linkname Ip4Name C.uv_ip4_name +func Ip4Name(src *net.SockaddrIn, dst *c.Char, size uintptr) c.Int + +//go:linkname Ip6Name C.uv_ip6_name +func Ip6Name(src *net.SockaddrIn6, dst *c.Char, size uintptr) c.Int + +//go:linkname IpName C.uv_ip_name +func IpName(src *net.SockAddr, dst *c.Char, size uintptr) c.Int + +//go:linkname InetNtop C.uv_inet_ntop +func InetNtop(af c.Int, src c.Pointer, dst *c.Char, size uintptr) c.Int + +//go:linkname InetPton C.uv_inet_pton +func InetPton(af c.Int, src *c.Char, dst c.Pointer) c.Int diff --git a/c/libuv/timer.go b/c/libuv/timer.go new file mode 100644 index 00000000..615da48b --- /dev/null +++ b/c/libuv/timer.go @@ -0,0 +1,42 @@ +package libuv + +import ( + "github.com/goplus/llgo/c" + _ "unsafe" +) + +// llgo:type C +type TimerCb func(timer *Timer) + +/* TimerT related function and method */ + +//go:linkname InitTimer C.uv_timer_init +func InitTimer(loop *Loop, timer *Timer) c.Int + +// llgo:link (*Timer).Start C.uv_timer_start +func (timer *Timer) Start(cb TimerCb, timeout uint64, repeat uint64) c.Int { + return 0 +} + +// llgo:link (*Timer).Stop C.uv_timer_stop +func (timer *Timer) Stop() c.Int { + return 0 +} + +// llgo:link (*Timer).Again C.uv_timer_again +func (timer *Timer) Again() c.Int { + return 0 +} + +// llgo:link (*Timer).SetRepeat C.uv_timer_set_repeat +func (timer *Timer) SetRepeat(repeat uint64) {} + +// llgo:link (*Timer).GetRepeat C.uv_timer_get_repeat +func (timer *Timer) GetRepeat() uint64 { + return 0 +} + +// llgo:link (*Timer).GetDueIn C.uv_timer_get_due_in +func (timer *Timer) GetDueIn() uint64 { + return 0 +} diff --git a/c/net/net.go b/c/net/net.go index 7b2608aa..0b794084 100644 --- a/c/net/net.go +++ b/c/net/net.go @@ -91,10 +91,23 @@ type SockaddrIn struct { Zero [8]c.Char } +type SockaddrIn6 struct { + Len uint8 + Family uint8 + Port uint16 + Flowinfo c.Uint + Addr In6Addr + ScopeId c.Uint +} + type InAddr struct { Addr c.Uint } +type In6Addr struct { + U6Addr [16]uint8 +} + type SockAddr struct { Len uint8 Family uint8 From c63580ee3813326c4179d349897aca99a9895b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E8=8B=B1=E6=9D=B0?= <2635879218@qq.com> Date: Mon, 22 Jul 2024 18:02:09 +0800 Subject: [PATCH 4/6] feat(c/libuv/demo): Add libuv demo echo_server refactor(c/libuv): Adjust comments and file names to accommodate merge --- _demo/libuv/echo_server.go | 109 +++++++++++++++++++++++ c/libuv/_demo/echo_server/echo_server.go | 109 +++++++++++++++++++++++ c/libuv/error.go | 87 ------------------ c/libuv/libuv.go | 39 +------- c/libuv/net.go | 22 ++++- c/libuv/timer.go | 14 ++- 6 files changed, 252 insertions(+), 128 deletions(-) create mode 100644 _demo/libuv/echo_server.go create mode 100644 c/libuv/_demo/echo_server/echo_server.go diff --git a/_demo/libuv/echo_server.go b/_demo/libuv/echo_server.go new file mode 100644 index 00000000..81d18148 --- /dev/null +++ b/_demo/libuv/echo_server.go @@ -0,0 +1,109 @@ +package main + +import ( + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/libuv" + "github.com/goplus/llgo/c/net" + "unsafe" +) + +var DEFAULT_PORT c.Int = 8080 +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) + } +} + +func main() { + // Initialize the default event loop + loop = libuv.DefaultLoop() + + // Initialize a TCP server + var server libuv.Tcp + libuv.InitTcp(loop, &server) + + // Set up the address to bind the server to + var addr net.SockaddrIn + libuv.Ip4Addr(c.Str("0.0.0.0"), DEFAULT_PORT, &addr) + + // Bind the server to the specified address and port + (&server).Bind((*net.SockAddr)(c.Pointer(&addr)), 0) + res := (*libuv.Stream)(&server).Listen(DEFAULT_BACKLOG, OnNewConnection) + if res != 0 { + c.Fprintf(c.Stderr, c.Str("Listen error: %s\n"), libuv.Strerror(res)) + return + } + + // Start listening for incoming connections + loop.Run(libuv.RUN_DEFAULT) +} diff --git a/c/libuv/_demo/echo_server/echo_server.go b/c/libuv/_demo/echo_server/echo_server.go new file mode 100644 index 00000000..81d18148 --- /dev/null +++ b/c/libuv/_demo/echo_server/echo_server.go @@ -0,0 +1,109 @@ +package main + +import ( + "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/libuv" + "github.com/goplus/llgo/c/net" + "unsafe" +) + +var DEFAULT_PORT c.Int = 8080 +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) + } +} + +func main() { + // Initialize the default event loop + loop = libuv.DefaultLoop() + + // Initialize a TCP server + var server libuv.Tcp + libuv.InitTcp(loop, &server) + + // Set up the address to bind the server to + var addr net.SockaddrIn + libuv.Ip4Addr(c.Str("0.0.0.0"), DEFAULT_PORT, &addr) + + // Bind the server to the specified address and port + (&server).Bind((*net.SockAddr)(c.Pointer(&addr)), 0) + res := (*libuv.Stream)(&server).Listen(DEFAULT_BACKLOG, OnNewConnection) + if res != 0 { + c.Fprintf(c.Stderr, c.Str("Listen error: %s\n"), libuv.Strerror(res)) + return + } + + // Start listening for incoming connections + loop.Run(libuv.RUN_DEFAULT) +} diff --git a/c/libuv/error.go b/c/libuv/error.go index 95ee68dd..b9397cf9 100644 --- a/c/libuv/error.go +++ b/c/libuv/error.go @@ -93,93 +93,6 @@ const ( ERRNO_MAX ) -//var errnoDescriptions = map[Errno]string{ -// E2BIG: "argument list too long", -// EACCES: "permission denied", -// EADDRINUSE: "address already in use", -// EADDRNOTAVAIL: "address not available", -// EAFNOSUPPORT: "address family not supported", -// EAGAIN: "resource temporarily unavailable", -// EAI_ADDRFAMILY: "address family not supported", -// EAI_AGAIN: "temporary failure", -// EAI_BADFLAGS: "bad ai_flags value", -// EAI_BADHINTS: "invalid value for hints", -// EAI_CANCELED: "request canceled", -// EAI_FAIL: "permanent failure", -// EAI_FAMILY: "ai_family not supported", -// EAI_MEMORY: "out of memory", -// EAI_NODATA: "no address", -// EAI_NONAME: "unknown node or service", -// EAI_OVERFLOW: "argument buffer overflow", -// EAI_PROTOCOL: "resolved protocol is unknown", -// EAI_SERVICE: "service not available for socket type", -// EAI_SOCKTYPE: "socket type not supported", -// EALREADY: "connection already in progress", -// EBADF: "bad file descriptor", -// EBUSY: "resource busy or locked", -// ECANCELED: "operation canceled", -// ECHARSET: "invalid Unicode character", -// ECONNABORTED: "software caused connection abort", -// ECONNREFUSED: "connection refused", -// ECONNRESET: "connection reset by peer", -// EDESTADDRREQ: "destination address required", -// EEXIST: "file already exists", -// EFAULT: "bad address in system call argument", -// EFBIG: "file too large", -// EHOSTUNREACH: "host is unreachable", -// EINTR: "interrupted system call", -// EINVAL: "invalid argument", -// EIO: "i/o error", -// EISCONN: "socket is already connected", -// EISDIR: "illegal operation on a directory", -// ELOOP: "too many symbolic links encountered", -// EMFILE: "too many open files", -// EMSGSIZE: "message too long", -// ENAMETOOLONG: "name too long", -// ENETDOWN: "network is down", -// ENETUNREACH: "network is unreachable", -// ENFILE: "file table overflow", -// ENOBUFS: "no buffer space available", -// ENODEV: "no such device", -// ENOENT: "no such file or directory", -// ENOMEM: "not enough memory", -// ENONET: "machine is not on the network", -// ENOPROTOOPT: "protocol not available", -// ENOSPC: "no space left on device", -// ENOSYS: "function not implemented", -// ENOTCONN: "socket is not connected", -// ENOTDIR: "not a directory", -// ENOTEMPTY: "directory not empty", -// ENOTSOCK: "socket operation on non-socket", -// ENOTSUP: "operation not supported on socket", -// EOVERFLOW: "value too large for defined data type", -// EPERM: "operation not permitted", -// EPIPE: "broken pipe", -// EPROTO: "protocol error", -// EPROTONOSUPPORT: "protocol not supported", -// EPROTOTYPE: "protocol wrong type for socket", -// ERANGE: "result too large", -// EROFS: "read-only file system", -// ESHUTDOWN: "cannot send after transport endpoint shutdown", -// ESPIPE: "invalid seek", -// ESRCH: "no such process", -// ETIMEDOUT: "connection timed out", -// ETXTBSY: "text file is busy", -// EXDEV: "cross-device link not permitted", -// UNKNOWN: "unknown error", -// EOF: "end of file", -// ENXIO: "no such device or address", -// EMLINK: "too many links", -// EHOSTDOWN: "host is down", -// EREMOTEIO: "remote I/O error", -// ENOTTY: "inappropriate ioctl for device", -// EFTYPE: "inappropriate file type or format", -// EILSEQ: "illegal byte sequence", -// ESOCKTNOSUPPORT: "socket type not supported", -// ENODATA: "no data available", -// EUNATCH: "protocol driver not attached", -//} - type Errno c.Int //go:linkname TranslateSysError C.uv_translate_sys_error diff --git a/c/libuv/libuv.go b/c/libuv/libuv.go index 004b223d..fb0c7664 100644 --- a/c/libuv/libuv.go +++ b/c/libuv/libuv.go @@ -17,12 +17,6 @@ const ( METRICS_IDLE_TIME ) -const ( - RUN_DEFAULT RunMode = iota - RUN_ONCE - RUN_NOWAIT -) - const ( UV_LEAVE_GROUP Membership = iota UV_JOIN_GROUP @@ -68,8 +62,6 @@ const ( type LoopOption c.Int -type RunMode c.Int - type Membership c.Int type HandleType c.Int @@ -85,9 +77,6 @@ type OsFd c.Int // ---------------------------------------------- /* Handle types. */ -type Loop struct { - Unused [0]byte -} type Handle struct { Unused [0]byte @@ -101,14 +90,6 @@ type Stream struct { Unused [0]byte } -type Tcp struct { - Unused [0]byte -} - -type Udp struct { - Unused [0]byte -} - type Pipe struct { Unused [0]byte } @@ -121,10 +102,6 @@ type Poll struct { Unused [0]byte } -type Timer struct { - Unused [0]byte -} - type Prepare struct { Unused [0]byte } @@ -183,17 +160,6 @@ type Connect struct { Unused [0]byte } -type UdpSend struct { - Unused [0]byte -} - -// ---------------------------------------------- - -type Buf struct { - Base *c.Char - Len uintptr -} - // ---------------------------------------------- /* Function type */ @@ -257,7 +223,7 @@ func (shutdown *Shutdown) Shutdown(stream *Stream, shutdownCb ShutdownCb) c.Int // ---------------------------------------------- -/* HandleT related function and method */ +/* Handle related function and method */ // llgo:link (*Handle).Ref C.uv_ref func (handle *Handle) Ref() {} @@ -317,9 +283,6 @@ func (handle *Handle) Fileno(fd *OsFd) c.Int { return 0 } -//go:linkname InitBuf C.uv_buf_init -func InitBuf(base *c.Char, len c.Uint) Buf - //go:linkname UvPipe C.uv_pipe func UvPipe(fds [2]Uv_File, readFlags c.Int, writeFlags c.Int) c.Int { return 0 diff --git a/c/libuv/net.go b/c/libuv/net.go index 1e5f7590..e2f824f6 100644 --- a/c/libuv/net.go +++ b/c/libuv/net.go @@ -62,6 +62,24 @@ type UdpFlags c.Int // ---------------------------------------------- +/* Handle types. */ + +type Tcp struct { + Unused [0]byte +} + +type Udp struct { + Unused [0]byte +} + +/* Request types. */ + +type UdpSend struct { + Unused [0]byte +} + +// ---------------------------------------------- + /* Function type */ // llgo:type C @@ -78,7 +96,7 @@ type UdpRecvCb func(handle *Udp, nread c.Long, buf *Buf, addr *net.SockAddr, fla // ---------------------------------------------- -/* TcpT related function and method */ +/* Tcp related function and method */ //go:linkname InitTcp C.uv_tcp_init func InitTcp(loop *Loop, tcp *Tcp) c.Int @@ -131,7 +149,7 @@ func TcpConnect(req *Connect, tcp *Tcp, addr *net.SockAddr, connectCb ConnectCb) // ---------------------------------------------- -/* UdpT related function and method */ +/* Udp related function and method */ //go:linkname InitUdp C.uv_udp_init func InitUdp(loop *Loop, udp *Udp) c.Int diff --git a/c/libuv/timer.go b/c/libuv/timer.go index 615da48b..fff1af5d 100644 --- a/c/libuv/timer.go +++ b/c/libuv/timer.go @@ -5,10 +5,22 @@ import ( _ "unsafe" ) +// ---------------------------------------------- + +/* Handle types. */ + +type Timer struct { + Unused [0]byte +} + +// ---------------------------------------------- + // llgo:type C type TimerCb func(timer *Timer) -/* TimerT related function and method */ +// ---------------------------------------------- + +/* Timer related function and method */ //go:linkname InitTimer C.uv_timer_init func InitTimer(loop *Loop, timer *Timer) c.Int From c27c654180eff36bbd5daaaacd086b48db8d488d Mon Sep 17 00:00:00 2001 From: hackerchai Date: Tue, 23 Jul 2024 11:43:02 +0800 Subject: [PATCH 5/6] refactor(c/libuv): general fixes & optimize code Signed-off-by: hackerchai refactor(c/libuv): optimize functions Signed-off-by: hackerchai refactor(c/libuv): mv name Signed-off-by: hackerchai refactor(c/libuv): modify libs Signed-off-by: hackerchai refactor(c/libuv): use new buffer arg Signed-off-by: hackerchai refactor(c/libuv/demo): optimize code style with go style Signed-off-by: hackerchai refactor(c/libuv): optimize code and add comment Signed-off-by: hackerchai fix(c/libuv): fix TranslateSysError Signed-off-by: hackerchai refactor(c/libuv): remove go wrapper Signed-off-by: hackerchai refactor(c/libuv/demo): refactor c style Signed-off-by: hackerchai refactor(c/liobuv/demo): Some adjustments after removing go wrapper refactor(c/libuv/demo): add print in echo_server Signed-off-by: hackerchai doc(c/libuv): add README.md for c/libuv Signed-off-by: hackerchai feat(c/libuv): implement poll_init_socket Signed-off-by: hackerchai refactor(c/libuv): mv poll_init_socket function Signed-off-by: hackerchai refactor(demo): remove libuv demo Signed-off-by: hackerchai --- _demo/libuv/echo_server.go | 109 -------- c/libuv/README.md | 44 ++++ c/libuv/_demo/async_fs/async_fs.go | 97 +++++++ c/libuv/_demo/async_fs/example.txt | 1 + c/libuv/_demo/echo_server/echo_server.go | 153 +++++------ c/libuv/_demo/libuv/fs.go | 70 ------ c/libuv/fs.go | 308 ++--------------------- c/libuv/libuv.go | 130 ++++++++-- c/libuv/net.go | 18 +- c/libuv/signal.go | 24 +- c/libuv/timer.go | 2 +- 11 files changed, 378 insertions(+), 578 deletions(-) delete mode 100644 _demo/libuv/echo_server.go create mode 100644 c/libuv/README.md create mode 100644 c/libuv/_demo/async_fs/async_fs.go create mode 100755 c/libuv/_demo/async_fs/example.txt delete mode 100644 c/libuv/_demo/libuv/fs.go diff --git a/_demo/libuv/echo_server.go b/_demo/libuv/echo_server.go deleted file mode 100644 index 81d18148..00000000 --- a/_demo/libuv/echo_server.go +++ /dev/null @@ -1,109 +0,0 @@ -package main - -import ( - "github.com/goplus/llgo/c" - "github.com/goplus/llgo/c/libuv" - "github.com/goplus/llgo/c/net" - "unsafe" -) - -var DEFAULT_PORT c.Int = 8080 -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) - } -} - -func main() { - // Initialize the default event loop - loop = libuv.DefaultLoop() - - // Initialize a TCP server - var server libuv.Tcp - libuv.InitTcp(loop, &server) - - // Set up the address to bind the server to - var addr net.SockaddrIn - libuv.Ip4Addr(c.Str("0.0.0.0"), DEFAULT_PORT, &addr) - - // Bind the server to the specified address and port - (&server).Bind((*net.SockAddr)(c.Pointer(&addr)), 0) - res := (*libuv.Stream)(&server).Listen(DEFAULT_BACKLOG, OnNewConnection) - if res != 0 { - c.Fprintf(c.Stderr, c.Str("Listen error: %s\n"), libuv.Strerror(res)) - return - } - - // Start listening for incoming connections - loop.Run(libuv.RUN_DEFAULT) -} diff --git a/c/libuv/README.md b/c/libuv/README.md new file mode 100644 index 00000000..30f2ed5b --- /dev/null +++ b/c/libuv/README.md @@ -0,0 +1,44 @@ +LLGo wrapper of libuv +===== + +## How to install + +### on macOS (Homebrew) + +```sh +brew install libuv +``` + +### on Linux (Debian/Ubuntu) + +```sh +apt-get install -y libuv1-dev +``` + +### on Linux (CentOS/RHEL) + +```sh +yum install -y libuv-devel +``` + +### on Linux (Arch Linux) + +```sh +pacman -S libuv +``` + +## Demos + +The `_demo` directory contains our demos (it start with `_` to prevent the `go` command from compiling it): + +* [async_fs](_demo/async_fs/async_fs.go): a simple async file read demo +* [echo_server](_demo/echo_server/echo_server.go): a basic async tcp echo server + +### How to run demos + +To run the demos in directory `_demo`: + +```sh +cd # eg. cd _demo/sqlitedemo +llgo run . +``` diff --git a/c/libuv/_demo/async_fs/async_fs.go b/c/libuv/_demo/async_fs/async_fs.go new file mode 100644 index 00000000..6a549441 --- /dev/null +++ b/c/libuv/_demo/async_fs/async_fs.go @@ -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) +} diff --git a/c/libuv/_demo/async_fs/example.txt b/c/libuv/_demo/async_fs/example.txt new file mode 100755 index 00000000..190a1803 --- /dev/null +++ b/c/libuv/_demo/async_fs/example.txt @@ -0,0 +1 @@ +123 diff --git a/c/libuv/_demo/echo_server/echo_server.go b/c/libuv/_demo/echo_server/echo_server.go index 81d18148..fdb04b5b 100644 --- a/c/libuv/_demo/echo_server/echo_server.go +++ b/c/libuv/_demo/echo_server/echo_server.go @@ -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) + } } diff --git a/c/libuv/_demo/libuv/fs.go b/c/libuv/_demo/libuv/fs.go deleted file mode 100644 index 7d50f2e9..00000000 --- a/c/libuv/_demo/libuv/fs.go +++ /dev/null @@ -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) -} diff --git a/c/libuv/fs.go b/c/libuv/fs.go index 555b5b0f..0de0a458 100644 --- a/c/libuv/fs.go +++ b/c/libuv/fs.go @@ -57,9 +57,11 @@ const ( DirentBlock ) -type FsType int +type FsType c.Int -type DirentType int +type DirentType c.Int + +type UvFile c.Int // ---------------------------------------------- @@ -108,35 +110,23 @@ type FsPollCb func(handle *FsPoll, status c.Int, events c.Int) /* Fs related function and method */ -// llgo:link (*Fs).GetType C.uv_fs_get_type -func (f *Fs) GetType() *FsType { - return nil -} +//go:linkname FsGetType C.uv_fs_get_type +func FsGetType(req *Fs) *FsType -// llgo:link (*Fs).GetPath C.uv_fs_get_path -func (f *Fs) GetPath() *c.Char { - return nil -} +//go:linkname FsGetPath C.uv_fs_get_path +func FsGetPath(req *Fs) *c.Char -// llgo:link (*Fs).GetResult C.uv_fs_get_result -func (f *Fs) GetResult() c.Int { - return 0 -} +//go:linkname FsGetResult C.uv_fs_get_result +func FsGetResult(req *Fs) c.Int -// llgo:link (*Fs).GetPtr C.uv_fs_get_ptr -func (f *Fs) GetPtr() c.Pointer { - return nil -} +//go:linkname FsGetPtr C.uv_fs_get_ptr +func FsGetPtr(req *Fs) c.Pointer -// llgo:link (*Fs).GetSystemError C.uv_fs_get_system_error -func (f *Fs) GetSystemError() c.Int { - return 0 -} +//go:linkname FsGetSystemError C.uv_fs_get_system_error +func FsGetSystemError(req *Fs) c.Int -// llgo:link (*Fs).GetStatBuf C.uv_fs_get_statbuf -func (f *Fs) GetStatBuf() *Stat { - return nil -} +//go:linkname FsGetStatBuf C.uv_fs_get_statbuf +func FsGetStatBuf(req *Fs) *Stat //go:linkname FsReqCleanup C.uv_fs_req_cleanup func FsReqCleanup(req *Fs) @@ -148,13 +138,13 @@ func DefaultLoop() *Loop func FsOpen(loop *Loop, req *Fs, path *c.Char, flags c.Int, mode c.Int, cb FsCb) c.Int //go:linkname FsClose C.uv_fs_close -func FsClose(loop *Loop, req *Fs, file c.Int, cb FsCb) c.Int +func FsClose(loop *Loop, req *Fs, file UvFile, cb FsCb) c.Int //go:linkname FsRead C.uv_fs_read -func FsRead(loop *Loop, req *Fs, file c.Int, bufs []Buf, nbufs c.Uint, offset c.Int, cb FsCb) c.Int +func FsRead(loop *Loop, req *Fs, file UvFile, bufs *Buf, nbufs c.Uint, offset c.LongLong, cb FsCb) c.Int //go:linkname FsWrite C.uv_fs_write -func FsWrite(loop *Loop, req *Fs, file c.Int, bufs []Buf, nbufs c.Uint, offset c.Int, cb FsCb) c.Int +func FsWrite(loop *Loop, req *Fs, file UvFile, bufs *Buf, nbufs c.Uint, offset c.LongLong, cb FsCb) c.Int //go:linkname FsUnlink C.uv_fs_unlink func FsUnlink(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int @@ -175,22 +165,22 @@ func FsRmdir(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int func FsStat(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int //go:linkname FsFstat C.uv_fs_fstat -func FsFstat(loop *Loop, req *Fs, file c.Int, cb FsCb) c.Int +func FsFstat(loop *Loop, req *Fs, file UvFile, cb FsCb) c.Int //go:linkname FsRename C.uv_fs_rename func FsRename(loop *Loop, req *Fs, path *c.Char, newPath *c.Char, cb FsCb) c.Int //go:linkname FsFsync C.uv_fs_fsync -func FsFsync(loop *Loop, req *Fs, file c.Int, cb FsCb) c.Int +func FsFsync(loop *Loop, req *Fs, file UvFile, cb FsCb) c.Int //go:linkname FsFdatasync C.uv_fs_fdatasync -func FsFdatasync(loop *Loop, req *Fs, file c.Int, cb FsCb) c.Int +func FsFdatasync(loop *Loop, req *Fs, file UvFile, cb FsCb) c.Int //go:linkname FsFtruncate C.uv_fs_ftruncate -func FsFtruncate(loop *Loop, req *Fs, file c.Int, offset c.Int, cb FsCb) c.Int +func FsFtruncate(loop *Loop, req *Fs, file UvFile, offset c.LongLong, cb FsCb) c.Int //go:linkname FsSendfile C.uv_fs_sendfile -func FsSendfile(loop *Loop, req *Fs, outFd c.Int, inFd c.Int, inOffset c.Int, length c.Int, cb FsCb) c.Int +func FsSendfile(loop *Loop, req *Fs, outFd c.Int, inFd c.Int, inOffset c.LongLong, length c.Int, cb FsCb) c.Int //go:linkname FsAccess C.uv_fs_access func FsAccess(loop *Loop, req *Fs, path *c.Char, flags c.Int, cb FsCb) c.Int @@ -199,13 +189,13 @@ func FsAccess(loop *Loop, req *Fs, path *c.Char, flags c.Int, cb FsCb) c.Int func FsChmod(loop *Loop, req *Fs, path *c.Char, mode c.Int, cb FsCb) c.Int //go:linkname FsFchmod C.uv_fs_fchmod -func FsFchmod(loop *Loop, req *Fs, file c.Int, mode c.Int, cb FsCb) c.Int +func FsFchmod(loop *Loop, req *Fs, file UvFile, mode c.Int, cb FsCb) c.Int //go:linkname FsUtime C.uv_fs_utime func FsUtime(loop *Loop, req *Fs, path *c.Char, atime c.Int, mtime c.Int, cb FsCb) c.Int //go:linkname FsFutime C.uv_fs_futime -func FsFutime(loop *Loop, req *Fs, file c.Int, atime c.Int, mtime c.Int, cb FsCb) c.Int +func FsFutime(loop *Loop, req *Fs, file UvFile, atime c.Int, mtime c.Int, cb FsCb) c.Int //go:linkname FsLutime C.uv_fs_lutime func FsLutime(loop *Loop, req *Fs, path *c.Char, atime c.Int, mtime c.Int, cb FsCb) c.Int @@ -247,7 +237,7 @@ func FsStatfs(loop *Loop, req *Fs, path *c.Char, cb FsCb) c.Int func FsChown(loop *Loop, req *Fs, path *c.Char, uid c.Int, gid c.Int, cb FsCb) c.Int //go:linkname FsFchown C.uv_fs_fchown -func FsFchown(loop *Loop, req *Fs, file c.Int, uid c.Int, gid c.Int, cb FsCb) c.Int +func FsFchown(loop *Loop, req *Fs, file UvFile, uid c.Int, gid c.Int, cb FsCb) c.Int //go:linkname FsLchown C.uv_fs_lchown func FsLchown(loop *Loop, req *Fs, path *c.Char, uid c.Int, gid c.Int, cb FsCb) c.Int @@ -284,247 +274,3 @@ func FsPollClose(handle *FsPoll) c.Int //go:linkname FsPollGetPath C.uv_fs_poll_getpath func FsPollGetPath(handle *FsPoll) *c.Char - -//TODO: Implemnt uv_poll_init_socket - -// Cleanup cleans up the file system request. -func (f *File) Cleanup() { - FsReqCleanup(f.Req) -} - -func NewFile(loop *Loop, req *Fs) *File { - return &File{ - Loop: loop, - Req: req, - } -} - -// Open opens a file specified by the path with given flags and mode, and returns a file descriptor. -func (f *File) Open(path *c.Char, flags int, mode int, cb FsCb) int { - return FsOpen(f.Loop, f.Req, path, flags, mode, cb) -} - -// Close closes a file descriptor. -func (f *File) Close(file int, cb FsCb) int { - return FsClose(f.Loop, f.Req, file, cb) -} - -// Read reads data from a file descriptor into a buffer at a specified offset. -func (f *File) Read(file c.Int, bufs []Buf, nbufs c.Uint, offset c.Int, cb FsCb) int { - return FsRead(f.Loop, f.Req, file, bufs, nbufs, offset, cb) -} - -// Write writes data to a file descriptor from a buffer at a specified offset. -func (f *File) Write(file c.Int, bufs []Buf, nbufs c.Uint, offset c.Int, cb FsCb) int { - return FsWrite(f.Loop, f.Req, file, bufs, nbufs, offset, cb) -} - -// Unlink deletes a file specified by the path. -func (f *File) Unlink(path *c.Char, cb FsCb) int { - return FsUnlink(f.Loop, f.Req, path, cb) -} - -// Mkdir creates a new directory at the specified path with a specified mode. -func (f *File) Mkdir(path *c.Char, mode int, cb FsCb) int { - return FsMkdir(f.Loop, f.Req, path, mode, cb) -} - -// Mkdtemp creates a temporary directory with a template path. -func (f *File) Mkdtemp(tpl *c.Char, cb FsCb) int { - return FsMkdtemp(f.Loop, f.Req, tpl, cb) -} - -// MkStemp creates a temporary file from a template path. -func (f *File) MkStemp(tpl *c.Char, cb FsCb) int { - return FsMkStemp(f.Loop, f.Req, tpl, cb) -} - -// Rmdir removes a directory specified by the path. -func (f *File) Rmdir(path *c.Char, cb FsCb) int { - return FsRmdir(f.Loop, f.Req, path, cb) -} - -// Stat retrieves status information about the file specified by the path. -func (f *File) Stat(path *c.Char, cb FsCb) int { - return FsStat(f.Loop, f.Req, path, cb) -} - -// Fstat retrieves status information about a file descriptor. -func (f *File) Fstat(file int, cb FsCb) int { - return FsFstat(f.Loop, f.Req, file, cb) -} - -// Rename renames a file from the old path to the new path. -func (f *File) Rename(path *c.Char, newPath *c.Char, cb FsCb) int { - return FsRename(f.Loop, f.Req, path, newPath, cb) -} - -// Fsync synchronizes a file descriptor's state with storage device. -func (f *File) Fsync(file int, cb FsCb) int { - return FsFsync(f.Loop, f.Req, file, cb) -} - -// Fdatasync synchronizes a file descriptor's data with storage device. -func (f *File) Fdatasync(file int, cb FsCb) int { - return FsFdatasync(f.Loop, f.Req, file, cb) -} - -// Ftruncate truncates a file to a specified length. -func (f *File) Ftruncate(file int, offset int, cb FsCb) int { - return FsFtruncate(f.Loop, f.Req, file, offset, cb) -} - -// Sendfile sends data from one file descriptor to another. -func (f *File) Sendfile(outFd int, inFd int, inOffset int, length int, cb FsCb) int { - return FsSendfile(f.Loop, f.Req, outFd, inFd, inOffset, length, cb) -} - -// Access checks the access permissions of a file specified by the path. -func (f *File) Access(path *c.Char, flags int, cb FsCb) int { - return FsAccess(f.Loop, f.Req, path, flags, cb) -} - -// Chmod changes the permissions of a file specified by the path. -func (f *File) Chmod(path *c.Char, mode int, cb FsCb) int { - return FsChmod(f.Loop, f.Req, path, mode, cb) -} - -// Fchmod changes the permissions of a file descriptor. -func (f *File) Fchmod(file int, mode int, cb FsCb) int { - return FsFchmod(f.Loop, f.Req, file, mode, cb) -} - -// Utime updates the access and modification times of a file specified by the path. -func (f *File) Utime(path *c.Char, atime int, mtime int, cb FsCb) int { - return FsUtime(f.Loop, f.Req, path, atime, mtime, cb) -} - -// Futime updates the access and modification times of a file descriptor. -func (f *File) Futime(file int, atime int, mtime int, cb FsCb) int { - return FsFutime(f.Loop, f.Req, file, atime, mtime, cb) -} - -// Lutime updates the access and modification times of a file specified by the path, even if the path is a symbolic link. -func (f *File) Lutime(path *c.Char, atime int, mtime int, cb FsCb) int { - return FsLutime(f.Loop, f.Req, path, atime, mtime, cb) -} - -// Link creates a new link to an existing file. -func (f *File) Link(path *c.Char, newPath *c.Char, cb FsCb) int { - return FsLink(f.Loop, f.Req, path, newPath, cb) -} - -// Symlink creates a symbolic link from the path to the new path. -func (f *File) Symlink(path *c.Char, newPath *c.Char, flags int, cb FsCb) int { - return FsSymlink(f.Loop, f.Req, path, newPath, flags, cb) -} - -// Readlink reads the target of a symbolic link. -func (f *File) Readlink(path *c.Char, cb FsCb) int { - return FsReadlink(f.Loop, f.Req, path, cb) -} - -// Realpath resolves the absolute path of a file. -func (f *File) Realpath(path *c.Char, cb FsCb) int { - return FsRealpath(f.Loop, f.Req, path, cb) -} - -// Copyfile copies a file from the source path to the destination path. -func (f *File) Copyfile(path *c.Char, newPath *c.Char, flags int, cb FsCb) int { - return FsCopyfile(f.Loop, f.Req, path, newPath, flags, cb) -} - -// Scandir scans a directory for entries. -func (f *File) Scandir(path *c.Char, flags int, cb FsCb) int { - return FsScandir(f.Loop, f.Req, path, flags, cb) -} - -// OpenDir opens a directory specified by the path. -func (f *File) OpenDir(path *c.Char, cb FsCb) int { - return FsOpenDir(f.Loop, f.Req, path, cb) -} - -// Readdir reads entries from an open directory. -func (f *File) Readdir(dir int, cb FsCb) int { - return FsReaddir(f.Loop, f.Req, dir, cb) -} - -// CloseDir closes an open directory. -func (f *File) CloseDir() int { - return FsCloseDir(f.Loop, f.Req) -} - -// Statfs retrieves file system status information. -func (f *File) Statfs(path *c.Char, cb FsCb) int { - return FsStatfs(f.Loop, f.Req, path, cb) -} - -// Chown Change file ownership -func (f *File) Chown(path *c.Char, uid int, gid int, cb FsCb) int { - return FsChown(f.Loop, f.Req, path, uid, gid, cb) -} - -// Fchown Change file ownership by file descriptor -func (f *File) Fchown(file int, uid int, gid int, cb FsCb) int { - return FsFchown(f.Loop, f.Req, file, uid, gid, cb) -} - -// Lchown Change file ownership (symlink) -func (f *File) Lchown(path *c.Char, uid int, gid int, cb FsCb) int { - return FsLchown(f.Loop, f.Req, path, uid, gid, cb) -} - -// Lstat Get file status (symlink) -func (f *File) Lstat(path *c.Char, cb FsCb) int { - return FsLstat(f.Loop, f.Req, path, cb) -} - -// Init Initialize a file event handle -func (e *FsEvent) Init(loop *Loop) int { - return FsEventInit(loop, e) -} - -// Start listening for file events -func (e *FsEvent) Start(cb FsEventCb, path *c.Char, flags int) int { - return FsEventStart(e, cb, path, flags) -} - -// Stop listening for file events -func (e *FsEvent) Stop() int { - return FsEventStop(e) -} - -// Close the file event handle -func (e *FsEvent) Close() int { - return FsEventClose(e) -} - -// GetPath Get the path of the file event -func (e *FsEvent) GetPath() *c.Char { - return FsEventGetpath(e) -} - -// Init Initialize a file poll handle -func (p *FsPoll) Init(loop *Loop) int { - return FsPollInit(loop, p) -} - -// Start polling for file changes -func (p *FsPoll) Start(cb FsPollCb, path *c.Char, interval uint) int { - return FsPollStart(p, cb, path, interval) -} - -// Stop polling for file changes -func (p *FsPoll) Stop() int { - return FsPollStop(p) -} - -// Close the file poll handle -func (p *FsPoll) Close() int { - return FsPollClose(p) -} - -// GetPath Get the path of the file poll -func (p *FsPoll) GetPath() *c.Char { - return FsPollGetPath(p) -} diff --git a/c/libuv/libuv.go b/c/libuv/libuv.go index fb0c7664..11a36700 100644 --- a/c/libuv/libuv.go +++ b/c/libuv/libuv.go @@ -11,6 +11,11 @@ const ( ) // ---------------------------------------------- +const ( + RUN_DEFAULT RunMode = iota + RUN_ONCE + RUN_NOWAIT +) const ( LOOP_BLOCK_SIGNAL LoopOption = iota @@ -60,6 +65,15 @@ const ( REQ_TYPE_MAX ) +const ( + READABLE PollEvent = 1 << iota + WRITABLE + DISCONNECT + PRIPRIORITIZED +) + +type RunMode c.Int + type LoopOption c.Int type Membership c.Int @@ -68,26 +82,30 @@ type HandleType c.Int type ReqType c.Int -type Uv_File c.Int - type OsSock c.Int type OsFd c.Int +type PollEvent c.Int + // ---------------------------------------------- /* Handle types. */ -type Handle struct { +type Loop struct { Unused [0]byte } +type Handle struct { + Unused [96]byte +} + type Dir struct { Unused [0]byte } type Stream struct { - Unused [0]byte + Unused [264]byte } type Pipe struct { @@ -122,18 +140,6 @@ type Process struct { Unused [0]byte } -type FsEvent struct { - Unused [0]byte -} - -type FsPoll struct { - Unused [0]byte -} - -type Signal struct { - Unused [0]byte -} - /* Request types. */ type Req struct { @@ -153,14 +159,17 @@ type Shutdown struct { } type Write struct { - Unused [0]byte + Unused [192]byte } type Connect struct { Unused [0]byte } -// ---------------------------------------------- +type Buf struct { + Base *c.Char + Len uintptr +} // ---------------------------------------------- /* Function type */ @@ -200,6 +209,9 @@ type ShutdownCb func(req *Shutdown, status c.Int) // llgo:type C type WalkCb func(handle *Handle, arg c.Pointer) +// llgo:type C +type PollCb func(handle *Poll, status c.Int, events c.Int) + // ---------------------------------------------- //go:linkname Version C.uv_version @@ -284,7 +296,7 @@ func (handle *Handle) Fileno(fd *OsFd) c.Int { } //go:linkname UvPipe C.uv_pipe -func UvPipe(fds [2]Uv_File, readFlags c.Int, writeFlags c.Int) c.Int { +func UvPipe(fds [2]UvFile, readFlags c.Int, writeFlags c.Int) c.Int { return 0 } @@ -351,22 +363,22 @@ func (stream *Stream) StopRead() c.Int { } // llgo:link (*Write).Write C.uv_write -func (req *Write) Write(stream *Stream, bufs []Buf, nbufs c.Uint, writeCb WriteCb) c.Int { +func (req *Write) Write(stream *Stream, bufs *Buf, nbufs c.Uint, writeCb WriteCb) c.Int { return 0 } // llgo:link (*Write).Write2 C.uv_write2 -func (req *Write) Write2(stream *Stream, bufs []Buf, nbufs c.Uint, sendStream *Stream, writeCb WriteCb) c.Int { +func (req *Write) Write2(stream *Stream, bufs *Buf, nbufs c.Uint, sendStream *Stream, writeCb WriteCb) c.Int { return 0 } // llgo:link (*Stream).TryWrite C.uv_try_write -func (stream *Stream) TryWrite(bufs []Buf, nbufs c.Uint) c.Int { +func (stream *Stream) TryWrite(bufs *Buf, nbufs c.Uint) c.Int { return 0 } // llgo:link (*Stream).TryWrite2 C.uv_try_write2 -func (stream *Stream) TryWrite2(bufs []Buf, nbufs c.Uint, sendStream *Stream) c.Int { +func (stream *Stream) TryWrite2(bufs *Buf, nbufs c.Uint, sendStream *Stream) c.Int { return 0 } @@ -387,6 +399,78 @@ func (stream *Stream) SetBlocking(blocking c.Int) c.Int { // ---------------------------------------------- +/* Loop related functions and method. */ + +//go:linkname LoopSize C.uv_loop_size +func LoopSize() uintptr + +//go:linkname Run C.uv_run +func Run(loop *Loop, mode RunMode) c.Int + +//go:linkname LoopAlive C.uv_loop_alive +func LoopAlive(loop *Loop) c.Int + +//go:linkname LoopClose C.uv_loop_close +func LoopClose(loop *Loop) c.Int + +//go:linkname LoopConfigure C.uv_loop_configure +func LoopConfigure(loop *Loop, option LoopOption, arg c.Int) c.Int + +//go:linkname LoopDefault C.uv_default_loop +func LoopDefault() *Loop + +//go:linkname LoopDelete C.uv_loop_delete +func LoopDelete(loop *Loop) c.Int + +//go:linkname LoopFork C.uv_loop_fork +func LoopFork(loop *Loop) c.Int + +//go:linkname LoopInit C.uv_loop_init +func LoopInit(loop *Loop) c.Int + +//go:linkname LoopNew C.uv_loop_new +func LoopNew() *Loop + +//go:linkname LoopNow C.uv_now +func LoopNow(loop *Loop) c.UlongLong + +//go:linkname LoopUpdateTime C.uv_update_time +func LoopUpdateTime(loop *Loop) + +//go:linkname LoopBackendFd C.uv_backend_fd +func LoopBackendFd(loop *Loop) c.Int + +//go:linkname LoopBackendTimeout C.uv_backend_timeout +func LoopBackendTimeout(loop *Loop) c.Int + +//go:linkname LoopWalk C.uv_walk +func LoopWalk(loop *Loop, walkCb WalkCb, arg c.Pointer) + +// ---------------------------------------------- + +/* Buf related functions and method. */ + +//go:linkname InitBuf C.uv_buf_init +func InitBuf(base *c.Char, len c.Uint) Buf + +// ---------------------------------------------- + +/* Poll related function and method */ + +//go:linkname PollInit C.uv_poll_init +func PollInit(loop *Loop, handle *Poll, fd OsFd) c.Int + +//go:linkname PollStart C.uv_poll_start +func PollStart(handle *Poll, events c.Int, cb PollCb) c.Int + +//go:linkname PollStop C.uv_poll_stop +func PollStop(handle *Poll) c.Int + +//go:linkname PollInitSocket C.uv_poll_init_socket +func PollInitSocket(loop *Loop, handle *Poll, socket c.Int) c.Int + +// ---------------------------------------------- + /* Getaddrinfo related function and method */ //go:linkname Getaddrinfo C.uv_getaddrinfo diff --git a/c/libuv/net.go b/c/libuv/net.go index e2f824f6..3fbb8f96 100644 --- a/c/libuv/net.go +++ b/c/libuv/net.go @@ -65,7 +65,7 @@ type UdpFlags c.Int /* Handle types. */ type Tcp struct { - Unused [0]byte + Unused [264]byte } type Udp struct { @@ -207,8 +207,8 @@ func (udp *Udp) SetMulticastInterface(interfaceAddr *c.Char) c.Int { return 0 } -// llgo:link (*Udp).SAetBroadcast C.uv_udp_set_broadcast -func (udp *Udp) SAetBroadcast(on c.Int) c.Int { +// llgo:link (*Udp).SetBroadcast C.uv_udp_set_broadcast +func (udp *Udp) SetBroadcast(on c.Int) c.Int { return 0 } @@ -218,15 +218,15 @@ func (udp *Udp) SetTTL(ttl c.Int) c.Int { } //go:linkname Send C.uv_udp_send -func Send(req *UdpSend, udp *Udp, bufs []Buf, nbufs c.Uint, addr *net.SockAddr, sendCb UdpSendCb) c.Int +func Send(req *UdpSend, udp *Udp, bufs *Buf, nbufs c.Uint, addr *net.SockAddr, sendCb UdpSendCb) c.Int // llgo:link (*Udp).TrySend C.uv_udp_try_send -func (udp *Udp) TrySend(bufs []Buf, nbufs c.Uint, addr *net.SockAddr) c.Int { +func (udp *Udp) TrySend(bufs *Buf, nbufs c.Uint, addr *net.SockAddr) c.Int { return 0 } -// llgo:link (*Udp).RecvStart C.uv_udp_recv_start -func (udp *Udp) RecvStart(allocCb AllocCb, recvCb UdpRecvCb) c.Int { +// llgo:link (*Udp).StartRecv C.uv_udp_recv_start +func (udp *Udp) StartRecv(allocCb AllocCb, recvCb UdpRecvCb) c.Int { return 0 } @@ -235,8 +235,8 @@ func (udp *Udp) UsingRecvmmsg() c.Int { return 0 } -// llgo:link (*Udp).RecvStop C.uv_udp_recv_stop -func (udp *Udp) RecvStop() c.Int { +// llgo:link (*Udp).StopRecv C.uv_udp_recv_stop +func (udp *Udp) StopRecv() c.Int { return 0 } diff --git a/c/libuv/signal.go b/c/libuv/signal.go index 97847d1c..8aad3b0e 100644 --- a/c/libuv/signal.go +++ b/c/libuv/signal.go @@ -13,24 +13,20 @@ type Signal struct { // ---------------------------------------------- -/* Signal related functions and method. */ +/* Function type */ // llgo:type C type SignalCb func(handle *Signal, sigNum c.Int) -//go:linkname UvSignalInit C.uv_signal_init -func UvSignalInit(loop *Loop, handle *Signal) c.Int +// ---------------------------------------------- -// llgo:link (*Signal).Start C.uv_signal_start -func (s *Signal) Start(cb SignalCb, signum c.Int) c.Int { - return 0 -} +/* Signal related functions and method. */ -// llgo:link (*Signal).StartOneshot C.uv_signal_start_oneshot -func (s *Signal) StartOneshot(handle *Signal, cb SignalCb, signum c.Int) c.Int { - return 0 -} +//go:linkname SignalInit C.uv_signal_init +func SignalInit(loop *Loop, handle *Signal) c.Int -func (s *Signal) Init(loop *Loop) int { - return UvSignalInit(loop, s) -} +//go:linkname SignalStart C.uv_signal_start +func SignalStart(handle *Signal, cb SignalCb, signum c.Int) c.Int + +//go:linkname SignalStartOneshot C.uv_signal_start_oneshot +func SignalStartOneshot(handle *Signal, cb SignalCb, signum c.Int) c.Int diff --git a/c/libuv/timer.go b/c/libuv/timer.go index fff1af5d..feeabe5a 100644 --- a/c/libuv/timer.go +++ b/c/libuv/timer.go @@ -15,7 +15,7 @@ type Timer struct { // ---------------------------------------------- -// llgo:type C +// llgo:type Cgit type TimerCb func(timer *Timer) // ---------------------------------------------- From 65e1f261c0fb47373cb419c60df373d60d351b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E8=8B=B1=E6=9D=B0?= <2635879218@qq.com> Date: Thu, 25 Jul 2024 15:40:02 +0800 Subject: [PATCH 6/6] refactor(c-libuv): Ajust Errno --- c/libuv/_demo/async_fs/async_fs.go | 10 +- c/libuv/_demo/echo_server/echo_server.go | 8 +- c/libuv/error.go | 181 ++++++++++++----------- c/net/net.go | 17 +++ 4 files changed, 117 insertions(+), 99 deletions(-) diff --git a/c/libuv/_demo/async_fs/async_fs.go b/c/libuv/_demo/async_fs/async_fs.go index 6a549441..6f715974 100644 --- a/c/libuv/_demo/async_fs/async_fs.go +++ b/c/libuv/_demo/async_fs/async_fs.go @@ -40,7 +40,7 @@ func main() { 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))) + c.Fprintf(c.Stderr, c.Str("Error opening file: %s\n"), libuv.Strerror(libuv.Errno(libuv.LoopClose(loop)))) libuv.LoopClose(loop) return } @@ -49,7 +49,7 @@ func onOpen(req *libuv.Fs) { // 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) + c.Printf(c.Str("Error in FsRead: %s (code: %d)\n"), libuv.Strerror(libuv.Errno(readRes)), readRes) libuv.LoopClose(loop) return } @@ -58,7 +58,7 @@ func onOpen(req *libuv.Fs) { 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))) + c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror(libuv.Errno(libuv.FsGetResult(req)))) libuv.LoopClose(loop) } else if libuv.FsGetResult(req) == 0 { c.Printf(c.Str("EOF\n")) @@ -66,7 +66,7 @@ func onRead(req *libuv.Fs) { 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) + c.Printf(c.Str("Error in FsClose: %s (code: %d)\n"), libuv.Strerror(libuv.Errno(closeRes)), closeRes) libuv.LoopClose(loop) return } @@ -80,7 +80,7 @@ func onRead(req *libuv.Fs) { 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))) + c.Fprintf(c.Stderr, c.Str("Error closing file: %s\n"), libuv.Strerror(libuv.Errno(libuv.FsGetResult(req)))) } else { c.Printf(c.Str("\nFile closed successfully.\n")) } diff --git a/c/libuv/_demo/echo_server/echo_server.go b/c/libuv/_demo/echo_server/echo_server.go index fdb04b5b..ee7faafc 100644 --- a/c/libuv/_demo/echo_server/echo_server.go +++ b/c/libuv/_demo/echo_server/echo_server.go @@ -35,7 +35,7 @@ func main() { (&server).Bind((*net.SockAddr)(c.Pointer(&addr)), 0) res := (*libuv.Stream)(&server).Listen(DEFAULT_BACKLOG, OnNewConnection) if res != 0 { - c.Fprintf(c.Stderr, c.Str("Listen error: %s\n"), libuv.Strerror(res)) + c.Fprintf(c.Stderr, c.Str("Listen error: %s\n"), libuv.Strerror((libuv.Errno(res)))) return } @@ -58,7 +58,7 @@ func AllocBuffer(handle *libuv.Handle, suggestedSize uintptr, buf *libuv.Buf) { func EchoWrite(req *libuv.Write, status c.Int) { if status != 0 { - c.Fprintf(c.Stderr, c.Str("Write error: %s\n"), libuv.Strerror(status)) + c.Fprintf(c.Stderr, c.Str("Write error: %s\n"), libuv.Strerror((libuv.Errno(status)))) } FreeWriteReq(req) } @@ -80,7 +80,7 @@ func EchoRead(client *libuv.Stream, nread c.Long, buf *libuv.Buf) { 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))) + c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror((libuv.Errno)(nread))) } (*libuv.Handle)(c.Pointer(client)).Close(nil) } @@ -92,7 +92,7 @@ func EchoRead(client *libuv.Stream, nread c.Long, buf *libuv.Buf) { 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)) + c.Fprintf(c.Stderr, c.Str("New connection error: %s\n"), libuv.Strerror(libuv.Errno(status))) return } diff --git a/c/libuv/error.go b/c/libuv/error.go index b9397cf9..beb286a2 100644 --- a/c/libuv/error.go +++ b/c/libuv/error.go @@ -2,110 +2,111 @@ package libuv import ( "github.com/goplus/llgo/c" + "github.com/goplus/llgo/c/net" + "github.com/goplus/llgo/c/syscall" _ "unsafe" ) const ( - E2BIG Errno = iota - EACCES - EADDRINUSE - EADDRNOTAVAIL - EAFNOSUPPORT - EAGAIN - EAI_ADDRFAMILY - EAI_AGAIN - EAI_BADFLAGS - EAI_BADHINTS - EAI_CANCELED - EAI_FAIL - EAI_FAMILY - EAI_MEMORY - EAI_NODATA - EAI_NONAME - EAI_OVERFLOW - EAI_PROTOCOL - EAI_SERVICE - EAI_SOCKTYPE - EALREADY - EBADF - EBUSY - ECANCELED - ECHARSET - ECONNABORTED - ECONNREFUSED - ECONNRESET - EDESTADDRREQ - EEXIST - EFAULT - EFBIG - EHOSTUNREACH - EINTR - EINVAL - EIO - EISCONN - EISDIR - ELOOP - EMFILE - EMSGSIZE - ENAMETOOLONG - ENETDOWN - ENETUNREACH - ENFILE - ENOBUFS - ENODEV - ENOENT - ENOMEM - ENONET - ENOPROTOOPT - ENOSPC - ENOSYS - ENOTCONN - ENOTDIR - ENOTEMPTY - ENOTSOCK - ENOTSUP - EOVERFLOW - EPERM - EPIPE - EPROTO - EPROTONOSUPPORT - EPROTOTYPE - ERANGE - EROFS - ESHUTDOWN - ESPIPE - ESRCH - ETIMEDOUT - ETXTBSY - EXDEV - UNKNOWN - EOF - ENXIO - EMLINK - EHOSTDOWN - EREMOTEIO - ENOTTY - EFTYPE - EILSEQ - ESOCKTNOSUPPORT - ENODATA - EUNATCH - ERRNO_MAX + E2BIG Errno = (Errno)(syscall.E2BIG) + EACCES Errno = (Errno)(syscall.EACCES) + EADDRINUSE Errno = (Errno)(syscall.EADDRINUSE) + EADDRNOTAVAIL Errno = (Errno)(syscall.EADDRNOTAVAIL) + EAFNOSUPPORT Errno = (Errno)(syscall.EAFNOSUPPORT) + EAGAIN Errno = (Errno)(syscall.EAGAIN) + EAI_ADDRFAMILY Errno = net.EAI_ADDRFAMILY + EAI_AGAIN Errno = net.EAI_AGAIN + EAI_BADFLAGS Errno = net.EAI_BADFLAGS + EAI_BADHINTS Errno = net.EAI_BADHINTS + EAI_CANCELED Errno = -3003 + EAI_FAIL Errno = net.EAI_FAIL + EAI_FAMILY Errno = net.EAI_FAMILY + EAI_MEMORY Errno = net.EAI_MEMORY + EAI_NODATA Errno = net.EAI_NODATA + EAI_NONAME Errno = net.EAI_NONAME + EAI_OVERFLOW Errno = net.EAI_OVERFLOW + EAI_PROTOCOL Errno = net.EAI_PROTOCOL + EAI_SERVICE Errno = net.EAI_SERVICE + EAI_SOCKTYPE Errno = net.EAI_SOCKTYPE + EALREADY Errno = (Errno)(syscall.EALREADY) + EBADF Errno = (Errno)(syscall.EBADF) + EBUSY Errno = (Errno)(syscall.EBUSY) + ECANCELED Errno = (Errno)(syscall.ECANCELED) + ECHARSET Errno = -4080 + ECONNABORTED Errno = (Errno)(syscall.ECONNABORTED) + ECONNREFUSED Errno = (Errno)(syscall.ECONNREFUSED) + ECONNRESET Errno = (Errno)(syscall.ECONNRESET) + EDESTADDRREQ Errno = (Errno)(syscall.EDESTADDRREQ) + EEXIST Errno = (Errno)(syscall.EEXIST) + EFAULT Errno = (Errno)(syscall.EFAULT) + EFBIG Errno = (Errno)(syscall.EFBIG) + EHOSTUNREACH Errno = (Errno)(syscall.EHOSTUNREACH) + EINTR Errno = (Errno)(syscall.EINTR) + EINVAL Errno = (Errno)(syscall.EINVAL) + EIO Errno = (Errno)(syscall.EIO) + EISCONN Errno = (Errno)(syscall.EISCONN) + EISDIR Errno = (Errno)(syscall.EISDIR) + ELOOP Errno = (Errno)(syscall.ELOOP) + EMFILE Errno = (Errno)(syscall.EMFILE) + EMSGSIZE Errno = (Errno)(syscall.EMSGSIZE) + ENAMETOOLONG Errno = (Errno)(syscall.ENAMETOOLONG) + ENETDOWN Errno = (Errno)(syscall.ENETDOWN) + ENETUNREACH Errno = (Errno)(syscall.ENETUNREACH) + ENFILE Errno = (Errno)(syscall.ENFILE) + ENOBUFS Errno = (Errno)(syscall.ENOBUFS) + ENODEV Errno = (Errno)(syscall.ENODEV) + ENOENT Errno = (Errno)(syscall.ENOENT) + ENOMEM Errno = (Errno)(syscall.ENOMEM) + ENONET Errno = -4056 + ENOPROTOOPT Errno = (Errno)(syscall.ENOPROTOOPT) + ENOSPC Errno = (Errno)(syscall.ENOSPC) + ENOSYS Errno = (Errno)(syscall.ENOSYS) + ENOTCONN Errno = (Errno)(syscall.ENOTCONN) + ENOTDIR Errno = (Errno)(syscall.ENOTDIR) + ENOTEMPTY Errno = (Errno)(syscall.ENOTEMPTY) + ENOTSOCK Errno = (Errno)(syscall.ENOTSOCK) + ENOTSUP Errno = (Errno)(syscall.ENOTSUP) + EOVERFLOW Errno = (Errno)(syscall.EOVERFLOW) + EPERM Errno = (Errno)(syscall.EPERM) + EPIPE Errno = (Errno)(syscall.EPIPE) + EPROTO Errno = (Errno)(syscall.EPROTO) + EPROTONOSUPPORT Errno = (Errno)(syscall.EPROTONOSUPPORT) + EPROTOTYPE Errno = (Errno)(syscall.EPROTOTYPE) + ERANGE Errno = (Errno)(syscall.ERANGE) + EROFS Errno = (Errno)(syscall.EROFS) + ESHUTDOWN Errno = (Errno)(syscall.ESHUTDOWN) + ESPIPE Errno = (Errno)(syscall.ESPIPE) + ESRCH Errno = (Errno)(syscall.ESRCH) + ETIMEDOUT Errno = (Errno)(syscall.ETIMEDOUT) + ETXTBSY Errno = (Errno)(syscall.ETXTBSY) + EXDEV Errno = (Errno)(syscall.EXDEV) + UNKNOWN Errno = -4094 + EOF Errno = -1 + ENXIO Errno = (Errno)(syscall.ENXIO) + EMLINK Errno = (Errno)(syscall.EMLINK) + EHOSTDOWN Errno = (Errno)(syscall.EHOSTDOWN) + EREMOTEIO Errno = -4030 + ENOTTY Errno = (Errno)(syscall.ENOTTY) + EFTYPE Errno = (Errno)(syscall.EFTYPE) + EILSEQ Errno = (Errno)(syscall.EILSEQ) + ESOCKTNOSUPPORT Errno = (Errno)(syscall.ESOCKTNOSUPPORT) + + ERRNO_MAX = EOF - 1 ) type Errno c.Int //go:linkname TranslateSysError C.uv_translate_sys_error -func TranslateSysError(sysErrno c.Int) c.Int +func TranslateSysError(sysErrno c.Int) Errno //go:linkname Strerror C.uv_strerror -func Strerror(err c.Int) *c.Char +func Strerror(err Errno) *c.Char //go:linkname StrerrorR C.uv_strerror_r -func StrerrorR(err c.Int, buf *c.Char, bufLen uintptr) *c.Char +func StrerrorR(err Errno, buf *c.Char, bufLen uintptr) *c.Char //go:linkname ErrName C.uv_err_name -func ErrName(err c.Int) *c.Char +func ErrName(err Errno) *c.Char //go:linkname ErrNameR C.uv_err_name_r -func ErrNameR(err c.Int, buf *c.Char, bufLen uintptr) *c.Char +func ErrNameR(err Errno, buf *c.Char, bufLen uintptr) *c.Char diff --git a/c/net/net.go b/c/net/net.go index 0b794084..e811d316 100644 --- a/c/net/net.go +++ b/c/net/net.go @@ -80,6 +80,23 @@ const ( SOCK_SEQPACKET = 5 // sequenced packet stream ) +const ( + EAI_ADDRFAMILY = iota + 1 /* address family for hostname not supported */ + EAI_AGAIN /* temporary failure in name resolution */ + EAI_BADFLAGS /* invalid value for ai_flags */ + EAI_FAIL /* non-recoverable failure in name resolution */ + EAI_FAMILY /* ai_family not supported */ + EAI_MEMORY /* memory allocation failure */ + EAI_NODATA /* no address associated with hostname */ + EAI_NONAME /* hostname nor servname provided, or not known */ + EAI_SERVICE /* servname not supported for ai_socktype */ + EAI_SOCKTYPE /* ai_socktype not supported */ + EAI_SYSTEM /* system error returned in errno */ + EAI_BADHINTS /* invalid value for hints */ + EAI_PROTOCOL /* resolved protocol is unknown */ + EAI_OVERFLOW /* argument buffer overflow */ +) + // (TODO) merge to inet const INET_ADDRSTRLEN = 16