Giter Club home page Giter Club logo

luv's Introduction

luv

Linux Build Status Windows Build status

libuv bindings for luajit and lua 5.1/ 5.2/ 5.3/ 5.4.

This library makes libuv available to lua scripts. It was made for the luvit project but should usable from nearly any lua project.

The library can be used by multiple threads at once. Each thread is assumed to load the library from a different lua_State. Luv will create a unique uv_loop_t for each state. You can't share uv handles between states/loops.

local uv = require('luv')

-- Create a handle to a uv_timer_t
local timer = uv.new_timer()

-- This will wait 1000ms and then continue inside the callback
timer:start(1000, 0, function ()
  -- timer here is the value we passed in before from new_timer.

  print("Awake!")

  -- You must always close your uv handles or you'll leak memory
  -- We can't depend on the GC since it doesn't know enough about libuv.
  timer:close()
end)

print("Sleeping")

-- uv.run will block and wait for all events to run.
-- When there are no longer any active handles, it will return
uv.run()

Here is an example of an TCP echo server

local uv = require('luv')

local function create_server(host, port, on_connection)

  local server = uv.new_tcp()
  server:bind(host, port)

  server:listen(128, function(err)
    -- Make sure there was no problem setting up listen
    assert(not err, err)

    -- Accept the client
    local client = uv.new_tcp()
    server:accept(client)

    on_connection(client)
  end)

  return server
end

local server = create_server("0.0.0.0", 0, function (client)

  client:read_start(function (err, chunk)

    -- Crash on errors
    assert(not err, err)

    if chunk then
      -- Echo anything heard
      client:write(chunk)
    else
      -- When the stream ends, close the socket
      client:close()
    end
  end)
end)

print("TCP Echo server listening on port " .. server:getsockname().port)

uv.run()

More examples can be found in the examples and tests folders.

Luarocks

Luv is available on Luarocks here. It can be installed via:

luarocks install luv

Note: To require luv using require 'uv' (to maintain compatibility with how luv is required in luvi) create a uv.lua with the contents:

return require 'luv'

Building From Source

To build, first install your compiler tools.

Get a Compiler

On linux this probably means gcc and make. On Ubuntu, the build-essential package is good for this.

On OSX, you probably want XCode which comes with clang and make and friends.

For windows the free Visual Studio Express works. If you get the 2013 edition, make sure to get the Windows Deskop edition. The Windows version doesn't include a working C compiler. Make sure to run all of setup including getting a free license.

Install CMake

Now install Cmake. The version in brew on OSX or most Linux package managers is good. The version on Travis CI is too old and so I use a PPA there. On windows use the installer and make sure to add cmake to your command prompt path.

Install Git

If you haven't already, install git and make sure it's in your path. This comes with XCode on OSX. On Linux it's in your package manager. For windows, use the installer at http://git-scm.com. Make sure it's available to your windows command prompt.

Clone the Code

Now open a terminal and clone the code. For windows I recommend the special developer command prompt that came with Visual Studio.

git clone https://github.com/luvit/luv.git --recursive
cd luv

Build the Code and Test

On windows I wrote a small batch file that runs the correct cmake commands and copies the output files for easy access.

C:\Code\luv> msvcbuild.bat
C:\Code\luv> luajit tests\run.lua

On unix systems, use the Makefile.

~/Code/luv> make test

This will build luv as a module library. Module libraries are plugins that are not linked into other targets.

Build with PUC Lua 5.4

By default luv is linked with LuaJIT 2.1.0-beta3. If you rather like to link luv with PUC Lua 5.4 you can run make with:

~/Code/luv> WITH_LUA_ENGINE=Lua make

Build as static library

If you want to build luv as a static library run make with:

~/Code/luv> BUILD_MODULE=OFF BUILD_STATIC_LIBS=ON make

This will create a static library libluv_a.a.

Build as shared library

If you want to build luv as a shared library run make with:

~/Code/luv> BUILD_MODULE=OFF BUILD_SHARED_LIBS=ON make

This will create a shared library libluv.so.

Build with shared libraries

By default the build system will build luv with the supplied dependencies. These are:

  • libuv
  • LuaJIT or Lua

However, if your target system has already one or more of these dependencies installed you can link luv against them.

Linking with shared libuv

The default shared library name for libuv is libuv. To link against it use:

~/Code/luv> WITH_SHARED_LIBUV=ON make
Linking with shared LuaJIT

The default shared library name for LuaJIT is libluajit-5.1. To link against it use:

~/Code/luv> LUA_BUILD_TYPE=System make
Linking with shared Lua 5.x

The default shared library name for Lua 5.x is liblua5.x. To link against it use:

~/Code/luv> LUA_BUILD_TYPE=System WITH_LUA_ENGINE=Lua make

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

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

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?

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.

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.

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.

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

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.

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

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.

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

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.

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.

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.

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

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

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

__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.

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)

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

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!

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

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.

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

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:

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 }

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.

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)

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.