luvit / luv Goto Github PK
View Code? Open in Web Editor NEWBare libuv bindings for lua
License: Apache License 2.0
Bare libuv bindings for lua
License: Apache License 2.0
I would like the fiber like the example in luvit to be added in luv.
I modified this example to work with luv.
https://github.com/hnakamur/luv_fiber_example
Actually wait.lua is the same as one in luvit. I modified file.lua to match function signatures in luv.
What do you think? Is it fine to add wait.lua as is to luv core, or should it go in a separate project?
We have some manual tests in the examples folder, but we need better test coverage and more automated pass/fail tests to detect regressions.
A.
I don't think multi-threading is important for Lua. We have to implement a set of APIs to exchange values between different lua_States of multi-threading threads, because the Lua APIs are not thread-safe. Creating new processes is a better choice for Lua.
And one multi-threading thread can only hold one uv_loop because uv_run blocks the thread. So exposing uv_loop to Lua is useless, and it reduces a little performance (passing the loop requires Lua stack operations) and makes the code written in Lua more complex (we should hold more objects).
Luv tries to expose the libuv APIs as-is, but i think some of the libuv APIs should be changed to supply the features of Lua and some designed for C should be redesigned(such as the dns's numbericserv).
B.
The event callback style should be redesigned in the following style too.
function stream:onread(data)
end
uv.read_start(stream)
into
uv.read_start(stream, function(data)
end)
The reason is that table indexing is slower than upvalues, and adding fields to userdata requires special implementing. The second style is also more like the libuv APIs.
C.
And in the read_cb implemention, luv used lua_pushlstring, which always does a copy operation that costs CPU resource. Please have a look at lua_Buffer APIs that allocs memory by Lua. I will test the performance of that later.
UPDATE: I tested and found lua_pushlstring is still faster. Lua 5.1 don't have luaL_Buffer inited char* too.
The spawn bindings are currently very limited in capability. This task is to expose all the functionality that libuv provides for spawning sub process including passing FDs between processes (on posix platforms)
I'm just wondering if you'd consider adding support thread support, such
as on the implementation here: https://github.com/richardhundt/luv/blob/master/examples/thread.lua
I'm currently trying to patch luv's C code myself with some of the code from there, but I'd appreciate
an expert opinion!
In some function before some of the local var definitions, there is other calls. MSVC 2008 doesn't support C99. And in C89 code like this is illegal.
For example,
static int luv_walk(lua_State* L) {
#ifdef LUV_STACK_CHECK
int top = lua_gettop(L);
#endif
luaL_checktype(L, 1, LUA_TFUNCTION); // We called an Lua API
luv_callback_t callback; // Then defined a local var
DNS servers doesn't return the address's socktype so registering this field can be removed from on_addrinfo.
Does anyone think so?
I don't think anyone uses this and it just gets in the way wasting an argument.
For example, the following luv code:
local timer = uv.new_timer()
uv.timer_start(timer, 100, 0, function (self) end)
Would be just function () end
without the self. This matters more for other callbacks that have err
and data
after self
.
uv.fs_stat returns uppercase types like "DIRECTORY" for .type, but uv.fs_scandir_next entries use "DIR". Lua's native type()
returns lowercase types.
I propose we make these types lowercase to match lua? Also should it be "directory" or "dir", the C apis don't seem consistent about when the shorten names.
All libuv callbacks need to report any possible libuv errors to the event handler.
This is all callbacks that have a int status
parameter. Some are:
typedef void (*uv_write_cb)(uv_write_t* req, int status);
typedef void (*uv_connect_cb)(uv_connect_t* req, int status);
typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status);
typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
typedef void (*uv_poll_cb)(uv_poll_t* handle, int status, int events);
typedef void (*uv_timer_cb)(uv_timer_t* handle, int status);
/* TODO: do these really need a status argument? */
typedef void (*uv_async_cb)(uv_async_t* handle, int status);
typedef void (*uv_prepare_cb)(uv_prepare_t* handle, int status);
typedef void (*uv_check_cb)(uv_check_t* handle, int status);
typedef void (*uv_idle_cb)(uv_idle_t* handle, int status);
typedef void (*uv_exit_cb)(uv_process_t*, int exit_status, int term_signal);
typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req,
int status,
struct addrinfo* res);
Has anyone tried getting luv working with awesome window manager?
leakage described in creationix/moonslice-luv#1 resides in pure luv, since the following code (barebone pseudo-HTTP server) shows constant growth of memory usage:
local utils = require('utils')
local p = utils.prettyPrint
local print = utils.print
utils.stdout = io.stdout
local luv = require('luv')
local function createServer(host, port, onConnection)
local server = luv.newTcp()
server:bind(host, port)
function server:onconnection()
local client = luv.newTcp()
server:accept(client)
onConnection(client)
end
server:listen()
return server
end
local server = createServer("127.0.0.1", 8080, function (client)
local function onend()
chunk = "HTTP/1.0 200 OK\r\nConnection: Close\r\nContent-Type: text/html\r\nContent-Length: 14\r\n\r\nHello World\n\r\n"
client:write(chunk, function ()
end)
client:shutdown(function ()
client:close()
end)
end
function client:ondata(chunk)
onend()
end
function client:onclose()
end
client:readStart()
end)
repeat
until luv.runOnce() == 0
please, consider fixing. tia
tty not work on windows,(on version https://github.com/luvit/luv/tree/uv-update-1.0.0)
output is
�[0;34m1�[0m �[0;35muv_tcp_t: 0x000e8fe8�[0m
�[1;32m"�[0;32mserver�[1;32m"�[0m �[0;35muv_tcp_t: 0x000e8fe8�[0m { ip = �
[1;32m"�[0;32m0.0.0.0�[1;32m"�[0m, family = �[1;32m"�[0;32mINET�[1;32m"�[0m, por
t = �[0;34m2024�[0m }
The following code demonstrates a bug/segfault, when trying to shedule a timer from a coroutine. Not sure how deep this issue is.
local uv = require('luv')
coroutine.wrap(function()
local timer = uv.new_timer()
function timer:ontimeout()
print('test')
end
uv.timer_start(timer, 1000, 0)
end)()
uv.run('default')
luv calls callbacks with lua_call, which does not catch Lua errors. When Lua errors occur in callbacks, Lua will do a long jump to the last pcall on the stack and return at that level.
Then the problem came. The long jump will skip the rest code of libuv's uv_run, which is unsafe. I didn't find any statement in the libuv document which ensures it safe to do long jumps in libuv callbacks.
The best solution to get over this problem is use lua_pcall, but it does not report the stack traceback when errors occur. That means debugging will be difficult.
All the libuv handles have a data
member that can be used to access arbitrary user data and this doesn't seem to be exposed.
All callbacks don't have any args. I suggest to check the status arg of luv_after_* callbacks and return the error message to the callback.
Even if the connect operation failed, the callback is also called, that'll cause some problems.
static void luv_after_connect(uv_connect_t* req, int status) {
lua_State* L = luv_prepare_callback(req->data);
#ifdef LUV_STACK_CHECK
int top = lua_gettop(L) - 1;
#endif
if (lua_isfunction(L, -1)) {
luv_call(L, 0, 0); // Here
} else {
lua_pop(L, 1);
}
I run it on win7, 32bits luajit + luv(https://github.com/luvit/luv/tree/uv-update-1.0.0)
I see luv ignored UV_ECONNRESET at the stream.c:luv_on_read callback. Why should we do that?
hi, less fs api bindings at current status?
Think about this
uv.fs_write(dev,chunk,0)
uv.fs_write(dev,chunk,0,cb)
3rd param meas offset in string, If it is optional val, will make code clear.
after have this feature, just change to
uv.fs_write(dev,chunk)
uv.fs_write(dev,chunk,cb)
The basic idea is to have share-nothing workers that can run lua code, each with it's own CPU thread, lua state and uv loop. This will be how luv exposes uv_thread_t to lua.
Please give me adivces
local uv = require 'luv'
function memleaks()
local socket = uv.new_tcp()
uv.close(socket)
socket = nil
collectgarbage()
end
for i=1,10000000 do
memleaks()
end
As a syntactic sugar and to make the API somewhat more like the Lua standard APIs, it would be nice if the different handle types could have their functions callable as members.
For example instead of:
local server = uv.new_tcp()
uv.tcp_bind(server, host, port)
One could do:
local server = uv.new_tcp()
server:bind(host, port)
This would require each handle type to get its own userdata type and to associate a metatable with __index
pointing to a table with the relevant subset of the API.
Most functions in common.c are general bindings of libuv just to create handles. And only luv_functions.c depends on common.h. So why not merge them to make it easier to compile luv by calling C compiler directly on toolchains without make?
Hey Tim,
It seems that there's a leak caused by uv.read_start.
Maybe I'm missing something: should shutdown be called on the onclose
event?
It can be reproduced like this:
-- server:
local uv = require 'luv'
local server = uv.new_tcp()
uv.tcp_bind(server, "0.0.0.0", 8483)
function server:onconnection()
local client = uv.new_tcp()
uv.accept(server, client)
client.ondata = function(self, data)
print('received: ', data)
end
client.onend = function(self)
print('closing client...')
uv.read_stop(client)
uv.close(client)
end
uv.read_start(client)
print("A client connected")
print(' - mem usage: ', collectgarbage('count')) -- ever increasing
collectgarbage()
end
uv.listen(server)
uv.run('default')
-- client:
local tcp = require 'socket'
while true do
print(os.date())
local conn = tcp.connect('localhost',8483)
conn:send('some string')
conn:close()
end
Thanks for your help.
C.
Branch: uv-update-1.0.0. MSVC doesn't support some C99 and GNU C features, so attribute((unused)) caused lots of warnings and some errors.
process.c:
int fd; // should the type of this be replaced with uv_os_fd_t? MSVC reports this.
uv_stream_t* stream = luv_check_stream(L, -1);
int err = uv_fileno((uv_handle_t*)stream, &fd);
And util.c:
static void luv_resume_with_status(lua_State* L, int status, int nargs) {
...
return luv_resume(L, 1 + nargs); // this is a void function but it has a return statement
}
And I wonder there is no co-routine design in libuv. Why it called Lua co-routine APIs? If we implement the co-routine support in C code, it won't be a BARE binding. I think co-routine wrapping should be done in Lua.
Hi, thanks for a nice project. It looks promising!
Could you add a LICENSE file, or add the LICENSE section in README?
Thanks!
When interfacing with libuv (a C library) I translate between strings and C constants. I can make most the checks case insensitive, but I wonder which would be the preferred method and the output format when results come from C constants For example when sending kill signals to a child process, should I send "SIGINT"
or 'sigint'
. When starting uv.run
should I pass in "ONCE"
or "once"
. Should the address family be "INET"
or "inet"
?
After allocate buffer e.g. for options.args
you can call lua_error and this buffer wont be free.
It causes application stoped when web browser drop previous connection and start an new one.
When attached to gdb, it says:
Program received signal SIGPIPE, Broken pipe
The breaks on write on socket handle.
By searching on web, it says need to handle the SIGPIPE signal. And I found following file has an example:
luv/libuv/test/runner-unix.c:53:
I tried to use uv.spawn and succeeded to connect stdout of the child process to the parent's stdout or a file.
https://gist.github.com/hnakamur/d503915badd15e7dd0cc
I would also like to connect it to a memory based stream so that I can store the output in a string.
Could you give me suggestion how to do it?
Thanks!
Same as #100, but for uv_fs_write
In libuv, the callback position in the function arguments is inconsistent. Should I match libuv exactly or move the callback to the last position or move it sometimes?
For example look at uv_timer_start
.
-- lua bindings for
-- int uv_timer_start(uv_timer_t* handle, uv_timer_cb cb, uint64_t timeout, uint64_t repeat)
-- With callback at end
uv.timer_start(timer, 100, 0, function (self)
end)
-- with callback in place
uv.timer_start(timer, function (self)
end, 100, 0)
Or in uv.spawn
the callback is actually a property in the config object and not an argument.
-- int uv_spawn(uv_loop_t* loop, uv_process_t* handle, const uv_process_options_t* options)
-- I could put the callback after the options
local child, pid = uv.spawn(program, {} function(self, exit_code, signal)
end)
-- Or put it in them
local child, pid = uv.spawn(program, {
on_exit = function(self, exit_code, signal)
end
})
When run your moonslice-luv with the send.lua, the file handles increases and I found you did not call the fs.close. But when I add the call, it blocks the routine. And I find the FS_CALL with 4, I guess it should be 2, right?
>>>>>>>>>>>>
static int luv_fs_close(lua_State* L) {
uv_file file = luaL_checkint(L, 1);
FS_CALL(close, 4, file);
}
<<<<<<<<<<<<<<
static int luv_fs_close(lua_State* L) {
uv_file file = luaL_checkint(L, 1);
FS_CALL(close, 2, file);
}
From the Lua 5.2 manual:
Function lua_objlen was renamed lua_rawlen.
And in the common.h file:
#if LUA_VERSION_NUM < 502
/* lua_rawlen: Not entirely correct, but should work anyway */
# define lua_rawlen lua_objlen
/* lua_...uservalue: Something very different, but it should get the job done */
# define lua_getuservalue lua_getfenv
# define lua_setuservalue lua_setfenv
# define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l))
# define luaL_setfuncs(L,l,n) (assert(n==0), luaL_register(L,NULL,l))
#endif
So please replace lua_objlen with lua_rawlen and do not use it any more to make the code's compliance better.
By the way, lua_objlen is just lua_rawlen so that comment can be removed.
Another frustrating bug in your reference counting implementation.
the way libuv works is that once you call uv_read_start, you can either call uv_read_stop, or uv_shutdown/uv_close.
However, in luv, luv_read_start increases the refcount (to not be garbage collected), but if you go the traditional libuv route and call luv_close/luv_shutdown, there is still 1 refcount left because of what luv_read_start incremented.
The only luv-specific hacky way around this is to call luv_read_stop explicitly, and also call luv_close/luv_shutdown.
uname_S=$(shell uname -s)
ifeq (Darwin, $(uname_S))
CFLAGS=-Ilibuv/include -g -I/usr/local/include/luajit-2.0 -DLUV_STACK_CHECK -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Werror -fPIC
LIBS=-lm -lluajit-5.1 -framework CoreServices -framework Cocoa
SHARED_LIB_FLAGS=-bundle -o luv.so luv.o libuv/libuv.a common.o
else
CFLAGS=-Ilibuv/include -g -I/usr/local/include/luajit-2.0 -DLUV_STACK_CHECK -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -Werror -fPIC
LIBS=-lm -lrt
SHARED_LIB_FLAGS=-shared -o luv.so luv.o libuv/libuv.a common.o
endif
all: luv.so
libuv/libuv.a:
CPPFLAGS=-fPIC $(MAKE) -C libuv
common.o: common.c common.h
$(CC) -c $< -o $@ ${CFLAGS}
luv.o: luv.c luv.h luv_functions.c
$(CC) -c $< -o $@ ${CFLAGS}
luv.so: luv.o libuv/libuv.a common.o
$(CC) ${SHARED_LIB_FLAGS} ${LIBS}
clean:
rm -f *.so *.o
I want to use luv for cocos2d-x game, but don't sure lua is supported arm64 or not.
I have reviewed the getaddrinfo document and looked through nodejs and luasocket's DNS API design. Nodejs and luasocket didn't expose the numeric service arg to js or lua. This is an arg specially designed for C convenience. If we specify this arg, the sockaddr ai_addr in the result is just ready to pass to connect or bind, because the OS has already set the port of it (result sockaddr) according to the numericserv and this is NOT depended on the name server response. For example, if we want the result sockaddr's port field set to 80, numericserv can be 'http', '80'(port no).
In Lua programming there is no chance we need it, because we can even not directly pass the results of uv.getaddrinfo to uv.connect. If we want to know the port of a service like http, we can look up documents and write them in Lua code.
The reason I want to talk about it again is that this will influence the args of uv.getaddrinfo and I thought I didnot express my mean clearly last time.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.