remove feature: remote object. Issue #58

This commit is contained in:
云风
2013-12-16 11:05:49 +08:00
parent e950ddd177
commit 48f6d42264
8 changed files with 7 additions and 323 deletions

View File

@@ -80,7 +80,7 @@ service/gate.so : service-src/service_gate.c
service/localcast.so : service-src/service_localcast.c
gcc $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src
luaclib/skynet.so : lualib-src/lua-skynet.c lualib-src/lua-seri.c lualib-src/lua-remoteobj.c lualib-src/trace_service.c | luaclib
luaclib/skynet.so : lualib-src/lua-skynet.c lualib-src/lua-seri.c lualib-src/trace_service.c | luaclib
gcc $(CFLAGS) $(SHARED) -Iluacompat $^ -o $@ -Iskynet-src -Iservice-src -Ilualib-src
service/client.so : service-src/service_client.c

View File

@@ -1,156 +0,0 @@
#include <lua.h>
#include <lauxlib.h>
#include "luacompat52.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define MAX_REMOTE_OBJECT 0x40000
struct remote_address {
int handle;
uint32_t address;
};
struct remote_objects {
int handle_index;
struct remote_address addr[MAX_REMOTE_OBJECT];
};
static struct remote_objects * _R = NULL;
static struct remote_objects *
_create() {
struct remote_objects * r = malloc(sizeof(*r));
r->handle_index = 0;
memset(r, 0, sizeof(*r));
r->addr[0].address = 0xffffffff;
return r;
}
static void
_remove(struct remote_objects *r, uint32_t address) {
int i;
for (i=0;i<MAX_REMOTE_OBJECT;i++) {
if (r->addr[i].address == address) {
r->addr[i].address = 0;
}
}
}
static int
_alloc(struct remote_objects *r, uint32_t address) {
int i = 0;
for (i=0;i<MAX_REMOTE_OBJECT;i++) {
int handle = __sync_add_and_fetch(&r->handle_index, 1);
struct remote_address * slot = r->addr + handle % MAX_REMOTE_OBJECT;
if (slot->address == 0) {
if (__sync_bool_compare_and_swap(&slot->address, 0, address)) {
slot->handle = handle;
return handle;
}
}
}
return -1;
}
static int
_bind(struct remote_objects *r, int handle, uint32_t address) {
struct remote_address * slot = r->addr + handle % MAX_REMOTE_OBJECT;
if (slot->handle != handle) {
return 0;
}
for (;;) {
uint32_t old = slot->address;
if (__sync_bool_compare_and_swap(&slot->address, old, address)) {
return old;
}
}
}
static uint32_t
_query(struct remote_objects *r, int handle) {
struct remote_address * slot = r->addr + handle % MAX_REMOTE_OBJECT;
if (slot->handle == handle) {
return slot->address;
}
return 0;
}
static int
lbind(lua_State *L) {
uint32_t addr = lua_tounsigned(L,lua_upvalueindex(1));
int handle = luaL_checkinteger(L,1);
uint32_t old = _bind(_R, handle, addr);
if (old == 0) {
luaL_error(L, "handle %d is not exist", handle);
}
lua_pushnumber(L, old);
return 1;
}
static int
lremove(lua_State *L) {
uint32_t * addr = lua_touserdata(L,1);
_remove(_R, *addr);
return 0;
}
static int
lalloc(lua_State *L) {
uint32_t addr = lua_tounsigned(L,lua_upvalueindex(1));
int handle = _alloc(_R, addr);
if (handle < 0) {
return luaL_error(L, "Too many remote object");
}
lua_pushinteger(L,handle);
return 1;
}
static int
lquery(lua_State *L) {
int handle = luaL_checkinteger(L,1);
uint32_t addr = _query(_R, handle);
if (addr == 0) {
return 0;
}
lua_pushnumber(L, addr);
return 1;
}
int
remoteobj_init(lua_State *L) {
if (_R == NULL) {
struct remote_objects * r = _create();
if (!__sync_bool_compare_and_swap(&_R, NULL, r)) {
free(r);
}
}
uint32_t address = luaL_checkunsigned(L, -1);
lua_pushcfunction(L, lquery);
lua_pushnumber(L, address);
uint32_t * addr = lua_newuserdata(L, sizeof(*addr));
*addr = address;
lua_createtable(L, 0, 1);
lua_pushcfunction(L, lremove);
lua_setfield(L, -2, "__gc");
lua_setmetatable(L,-2);
lua_pushcclosure(L, lalloc, 2);
lua_pushnumber(L, address);
lua_pushcclosure(L, lbind, 1);
return 3;
}

View File

@@ -20,7 +20,6 @@
// hibits 0~31 : len
#define TYPE_LONG_STRING 5
#define TYPE_TABLE 6
#define TYPE_REMOTE 7
#define MAX_COOKIE 32
#define COMBINE_TYPE(t,v) ((t) | (v) << 3)
@@ -360,16 +359,7 @@ _pack_one(lua_State *L, struct write_block *b, int index, int depth) {
if (index < 0) {
index = lua_gettop(L) + index + 1;
}
lua_pushvalue(L, lua_upvalueindex(2)); // __remote
lua_rawget(L, index);
if (lua_isnumber(L,-1)) {
int handle = lua_tointeger(L,-1);
lua_pop(L,1);
wb_integer(b, handle, TYPE_REMOTE);
} else {
lua_pop(L,1);
wb_table(L, b, index, depth+1);
}
wb_table(L, b, index, depth+1);
break;
}
default:
@@ -531,21 +521,8 @@ _push_value(lua_State *L, struct read_block *rb, int type, int cookie) {
_unpack_table(L,rb,cookie);
break;
}
case TYPE_REMOTE: {
lua_pushvalue(L,lua_upvalueindex(1)); // metatable
int handle = _get_integer(L,rb,cookie);
lua_rawgeti(L,-1,handle);
if (lua_isnil(L,-1)) {
lua_pop(L,2);
lua_createtable(L,0,1);
lua_pushvalue(L,lua_upvalueindex(2)); // __remote
lua_pushinteger(L,handle);
lua_rawset(L,-3);
lua_pushvalue(L,lua_upvalueindex(1)); // metatable
lua_setmetatable(L,-2);
} else {
lua_replace(L, -2);
}
default: {
_invalid_stream(L,rb);
break;
}
}

View File

@@ -454,19 +454,10 @@ _reload(lua_State *L) {
return 0;
}
// define in lua-remoteobj.c
int remoteobj_init(lua_State *L);
int
luaopen_skynet_c(lua_State *L) {
luaL_checkversion(L);
luaL_Reg pack[] = {
{ "pack", _luaseri_pack },
{ "unpack", _luaseri_unpack },
{ NULL, NULL },
};
luaL_Reg l[] = {
{ "send" , _send },
{ "genid", _genid },
@@ -477,12 +468,13 @@ luaopen_skynet_c(lua_State *L) {
{ "tostring", _tostring },
{ "harbor", _harbor },
{ "context", _context },
{ "pack", _luaseri_pack },
{ "unpack", _luaseri_unpack },
{ NULL, NULL },
};
luaL_Reg l2[] = {
{ "stat", _stat },
{ "remote_init", remoteobj_init },
{ "trace_new", _trace_new },
{ "trace_delete", _trace_delete },
{ "trace_switch", _trace_switch },
@@ -491,10 +483,7 @@ luaopen_skynet_c(lua_State *L) {
{ NULL, NULL },
};
lua_createtable(L, 0, (sizeof(pack) + sizeof(l) + sizeof(l2))/sizeof(luaL_Reg)-1);
lua_newtable(L);
lua_pushstring(L,"__remote");
luaL_setfuncs(L,pack,2);
lua_createtable(L, 0, (sizeof(l) + sizeof(l2))/sizeof(luaL_Reg)-1);
lua_getfield(L, LUA_REGISTRYINDEX, "skynet_lua");
struct snlua *lua = lua_touserdata(L,-1);

View File

@@ -481,87 +481,6 @@ function skynet.harbor(addr)
return c.harbor(addr)
end
------ remote object --------
do
-- proto is 11
local remote_query, remote_alloc, remote_bind = c.remote_init(skynet.self())
local weak_meta = { __mode = "kv" }
local meta = getmetatable(c.unpack(c.pack({ __remote = 0 })))
local remote_call_func = setmetatable({}, weak_meta)
local _send = assert(c.send)
local _pack = assert(c.pack)
local _unpack = assert(c.unpack)
local _local = skynet.self()
function meta__index(t, method)
local f = remote_call_func[method]
if f == nil then
f = function(...)
local addr = remote_query(t.__remote)
-- the proto is 11 (lua is 10)
local session = assert(_send(addr, 11 , nil, _pack(t,method,...)), "call to invalid address")
local succ, msg, sz = coroutine_yield("CALL", session)
if succ then
return select(2,assert(_unpack(msg,sz)))
else
error "call to dead remote object"
end
end
remote_call_func[method] = f
end
rawset(t,method,f)
return f
end
-- prevent gc
meta.__index = meta__index
meta.__newindex = error
function skynet.remote_create(t, handle)
t = t or {}
if handle then
remote_bind(handle)
else
handle = remote_alloc()
end
rawset(t, "__remote" , handle)
rawset(meta, handle, t)
return t
end
function skynet.remote_bind(handle)
return setmetatable( { __remote = handle } , meta)
end
local function remote_call(obj, method, ...)
if type(obj) ~= "table" or type(method) ~= "string" then
return coroutine_yield("RETURN", _pack(false, "Invalid call"))
end
local f = obj[method]
if type(f) ~= "function" then
return coroutine_yield("RETURN", _pack(false, "Object has not method " .. method))
end
return coroutine_yield("RETURN", _pack(pcall(f,...)))
end
function skynet.remote_root()
return skynet.remote_bind(0)
end
skynet.register_protocol {
name = "remoteobj",
id = 11,
unpack = c.unpack,
dispatch = function (session, source, ...)
remote_call(...)
end
}
end
----- debug
local internal_info_func

View File

@@ -6,7 +6,6 @@ skynet.start(function()
skynet.monitor "simplemonitor"
local lualog = skynet.newservice("lualog")
local console = skynet.newservice("console")
local remoteroot = skynet.newservice("remote_root")
local watchdog = skynet.newservice("watchdog","8888 4 0")
local db = skynet.newservice("simpledb")
-- skynet.launch("snlua","testgroup")

View File

@@ -1,21 +0,0 @@
local skynet = require "skynet"
local service = {}
local root = {}
function root.register(name, obj)
service[name] = obj
end
function root.query(name)
return service[name]
end
function root.echo(hello)
return hello
end
skynet.remote_create(root,0)
skynet.start(function() end)

View File

@@ -1,23 +0,0 @@
local skynet = require "skynet"
local obj = { id = 0 }
function obj.hello()
return "Hello"
end
function obj:inc()
self.id = self.id + 1
return self.id
end
skynet.start(function()
skynet.remote_create(obj)
local root = skynet.remote_root()
print(root.echo("hello"))
root.register("test",obj)
local qobj = root.query "test"
print(qobj.hello())
print(qobj:inc())
skynet.exit()
end)