Giter Site home page Giter Site logo

luv's Introduction

Luvit 2.0 - Node.JS for the Lua Inventor

Linux Build Status Windows Build status Coverage Status

Welcome to the source code for Luvit 2.0. This repo contains the luvit/luvit metapackage and all luvit/* packages as published to lit.

This collection of packages and modules implements a node.js style API for the luvi/lit runtime. It can be used as both a library or a standalone executable.

See the main project webpage for more details. https://luvit.io/

Need Help?

Ask questions here through issues, on Discord or the mailing list.

Binary Modules

Luvit supports FFI and Lua based binary modules. There is a wiki entry explaining how to manage and include a binary module within a bundled application. Publishing Compiled Code

Hacking on Luvit Core

First you need to clone and build luvit, this is easy and works cross-platform thanks to Makefile and make.bat.

git clone https://github.com/luvit/luvit.git
cd luvit
make

If you want to test luvit without constantly building, use luvi.

luvi . 

Always make sure to run make test before submitting a PR.

Notes to Maintainers

  • Use luvi /path/to/luvit to test changes without rebuilding the binary.
  • To run the test suite, run make test to build a luvit and use that.
  • If you want to test a custom built luvi, run luvi . -- tests/run.lua
  • If you want to run a specific test file with a custom built luvi, run luvi . -- tests/test-<name-of-test>.lua (e.g. luvi . -- tests/test-http.lua)
  • There is a wiki page on making new luvit releases at https://github.com/luvit/luvit/wiki/Making-a-luvit-release.

The packages in deps live primarily in this repo, but some are duplicated in luvit/lit to ease lit bootstrapping. Updates can be pushed from either repo to lit, just make sure to keep them in sync. One way to do this is to rm -rf deps && lit install. This will install the latest version of all the packages from lit. Check the diff carefully to make sure you're not undoing any work. There might have been unpublished changes locally in luvit that aren't in the lit central database yet.

luv's People

Contributors

bilal2453 avatar bjorn avatar blueyed avatar brimworks avatar clementfarabet avatar creationix avatar daurnimator avatar devurandom avatar duckwhale avatar equalsraf avatar erw7 avatar ffontaine avatar jamessan avatar joerg-krause avatar mei-rune avatar ravener avatar rjemanuele avatar rphillips avatar samunders-core avatar sidyhe avatar sinisterrectus avatar slact avatar songgao avatar squeek502 avatar starwing avatar tarruda avatar tbastos avatar utkarsh009 avatar yihuang avatar zhaozg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

luv's Issues

luv_fs_close does not close the file handle

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);
}

Callback positions

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
})

still a DNS API design issue

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.

threading suggestions

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.

Could you add a LICENSE file?

Hi, thanks for a nice project. It looks promising!
Could you add a LICENSE file, or add the LICENSE section in README?
Thanks!

Remove self arg in callbacks.

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.

Leak triggered by read_start

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.

Enable member-function calling style for the different handle types

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.

Modified Makefile for Mac OS X

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

Program received signal SIGPIPE, Broken pipe

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:

maybe memleaks, or show me howto

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

luv_read_start leak

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.

Implement workers using uv_thread_t

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.

Add support for FD passing to uv_spawn bindings

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)

Lua 5.2 doesn't have the lua_objlen function

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.

Is there a way to know if the connect operation is successfully

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);
  }

Add proper error reporting to event handlers

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);

Add automated tests

We have some manual tests in the examples folder, but we need better test coverage and more automated pass/fail tests to detect regressions.

leak

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

Uppercase constants or lowercase

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"?

callbacks may longjmp out of the scope of uv.run

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.

Coroutine compat issue.

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')

why not merge common.c to luv_functions.c

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?

tty not work on windows

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 code is not OK with MSVC 2008 or older versions

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

Unify file types

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.

about 3rd param for uv.fs_write

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)

__attribute__((unused)) causes MSVC 2008 C4113 and C4047

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.