Compare commits

...

46 Commits

Author SHA1 Message Date
Cloud Wu
2128a82571 update history, and release v0.3.2 2014-06-23 11:01:20 +08:00
Cloud Wu
d910686cb8 cluster bugfix : add socket.header to decode bigendian header 2014-06-21 18:03:08 +08:00
Cloud Wu
078ac2bcd2 bugfix: double free 2014-06-18 15:09:15 +08:00
云风
c7887cceb7 Merge pull request #119 from cloudwu/dev
release v0.3.1
2014-06-16 10:11:18 +08:00
Cloud Wu
4fbd433199 release v0.3.1 2014-06-16 10:10:18 +08:00
Cloud Wu
87d276caf6 typo fix 2014-06-12 17:28:54 +08:00
Cloud Wu
0f64e909fa big-endian encoding bson objectid 2014-06-11 15:11:18 +08:00
Cloud Wu
4bc2e800fd bugfix: lua mongo result 2014-06-09 18:08:23 +08:00
Cloud Wu
bf6501f2ee check mongo reply data stream 2014-06-09 17:43:40 +08:00
Cloud Wu
f92fc153e4 bugfix: in freebsd, libthr may call calloc before globalinit 2014-06-04 02:51:29 +00:00
Cloud Wu
c10e5412c0 invalid length may nagtive 2014-06-04 10:23:49 +08:00
Cloud Wu
9477cc8171 turn off memory hook in freeBSD 2014-06-03 12:35:00 +00:00
Cloud Wu
7f3ba76a41 update history 2014-06-02 21:10:58 +08:00
云风
4545ef149b Merge pull request #116 from cloudwu/dev
merge dev version
2014-06-02 21:05:15 +08:00
Cloud Wu
c130a93a91 bson : check string length 2014-06-02 11:53:55 +08:00
Cloud Wu
cd0a1a495e optimize timer 2014-05-28 11:30:39 +08:00
Cloud Wu
3597bb6d75 use jemalloc release 3.6.0 2014-05-27 21:04:22 +08:00
Cloud Wu
39c5e13d1a Merge branch 'dev' of github.com:cloudwu/skynet into dev 2014-05-26 13:42:07 +08:00
Cloud Wu
e1a72bd820 optimize message dispatch 2014-05-26 13:40:49 +08:00
Cloud Wu
f77482024e Merge branch 'master' into dev 2014-05-26 13:23:59 +08:00
Cloud Wu
866e59811e remove unused mq api 2014-05-26 13:23:57 +08:00
Cloud Wu
f3b1f5be51 bugfix: check globalmq push is complete 2014-05-26 13:18:09 +08:00
Cloud
0fcab96431 daemon is deprecarted in macosx 2014-05-23 16:52:24 +08:00
Cloud Wu
e765d3c305 don't unlock pidfile after write pid 2014-05-23 14:06:41 +08:00
Cloud Wu
8005b55ef5 add pidfile for daemon 2014-05-23 13:24:02 +08:00
Cloud Wu
1ce90b7d17 daemon mode 2014-05-23 10:54:54 +08:00
Cloud Wu
37ea7a025c single node mode 2014-05-22 22:44:20 +08:00
Cloud Wu
88700c2c90 cluster support 2014-05-22 21:04:32 +08:00
Cloud Wu
90cd967333 concurrence bugfix 2014-05-22 11:24:36 +08:00
Cloud Wu
1fbee1ac0b update lua-bson to fix the 32bit signed int bug 2014-05-21 11:21:01 +08:00
云风
d6a4c5cc59 Merge pull request #114 from tangyi/minor-fix
fix the missing of 'Welcome to skynet' in example
2014-05-20 10:39:33 +08:00
tangyi
66a0a6e1db fix the missing of 'Welcome to skynet' in example 2014-05-19 18:13:34 +08:00
云风
57f37a55ba Merge pull request #113 from cloudwu/dev
bugfix
2014-05-19 10:53:08 +08:00
Cloud Wu
84e8abc09c update history 2014-05-19 10:51:20 +08:00
云风
dbfa17be09 Merge pull request #112 from zhoukk/master
remove services when launch error.
2014-05-19 10:50:12 +08:00
zhoukk
19729576f6 lua service launch错误时,移除services中记录
lua service launch错误后,没有移除 launcher.lua里services中的服务记录,导致debug_console中的list mem等命令返回数据不正确
2014-05-18 12:36:38 +08:00
Cloud Wu
a5df196e92 use skynet_error for memory dump 2014-05-16 17:36:49 +08:00
Cloud Wu
a2ad158dbc update PTYPE_* macro 2014-05-16 15:01:25 +08:00
Cloud Wu
ff155c623e bugfix: stdin is 0 2014-05-16 14:31:27 +08:00
Cloud Wu
9fe6a0a954 Merge branch 'master' into dev 2014-05-15 19:33:30 +08:00
Cloud Wu
c2ed2f8603 bugfix. the harbor and master service need to rewrite in future 2014-05-15 19:32:54 +08:00
Cloud Wu
a67e561a64 Merge branch 'master' into dev 2014-05-14 11:55:53 +08:00
Cloud Wu
ef2da264f1 bugfix: watchdog socket data 2014-05-14 11:55:40 +08:00
Cloud Wu
b397c70c34 remove unused pingqueue 2014-05-13 17:00:43 +08:00
Cloud Wu
02f2f88b6d Fix issue #109 2014-05-13 13:35:37 +08:00
Cloud Wu
29917efad7 add MAX_SLOT_SIZE limit 2014-05-13 11:09:15 +08:00
42 changed files with 1000 additions and 167 deletions

1
.gitignore vendored
View File

@@ -1,6 +1,7 @@
*.o
*.a
skynet
skynet.pid
3rd/lua/lua
3rd/lua/luac
cservice

View File

@@ -1,3 +1,32 @@
v0.3.2 (2014-6-23)
----------
* Bugifx : mongo driver and lua-bson . (objectid encoding, and gc problem when mongdo driver reply bson object).
* Bugfix : cluster (double free).
* Add socket.header() to decode big-endian package header (and fix the bug in cluster).
v0.3.1 (2014-6-16)
-----------
* Bugfix: lua mongo driver . Hold reply string before decode bson data.
* More check in bson decoding.
* Use big-endian for encoding bson objectid.
v0.3.0 (2014-6-2)
-----------
* Add cluster support
* Add single node mode
* Add daemon mode
* Bugfix: update lua-bson (signed 32bit int bug / check string length)
* Optimize timer
* Simplify message queue and optimize message dispatch
* Use jemalloc release 3.6.0
v0.2.1 (2014-5-19)
-----------
* Bugfix: check all the events already read after socket close
* Bugfix: socket data in gate service
* Bugfix: boundary problem in harbor service
* Bugfix: stdin handle is 0
v0.2.0 (2014-5-12)
-----------

View File

@@ -40,13 +40,15 @@ jemalloc : $(MALLOC_STATICLIB)
# skynet
CSERVICE = snlua logger gate master harbor
LUA_CLIB = skynet socketdriver int64 bson mongo md5 netpack cjson clientsocket memory profile multicast
CSERVICE = snlua logger gate master harbor dummy
LUA_CLIB = skynet socketdriver int64 bson mongo md5 netpack \
cjson clientsocket memory profile multicast \
cluster
SKYNET_SRC = skynet_main.c skynet_handle.c skynet_module.c skynet_mq.c \
skynet_server.c skynet_start.c skynet_timer.c skynet_error.c \
skynet_harbor.c skynet_env.c skynet_monitor.c skynet_socket.c socket_server.c \
malloc_hook.c
malloc_hook.c skynet_daemon.c
all : \
$(SKYNET_BUILD_PATH)/skynet \
@@ -64,7 +66,7 @@ $(CSERVICE_PATH) :
define CSERVICE_TEMP
$$(CSERVICE_PATH)/$(1).so : service-src/service_$(1).c | $$(CSERVICE_PATH)
$(CC) $$(CFLAGS) $$(SHARED) $$< -o $$@ -Iskynet-src
$$(CC) $$(CFLAGS) $$(SHARED) $$< -o $$@ -Iskynet-src
endef
$(foreach v, $(CSERVICE), $(eval $(call CSERVICE_TEMP,$(v))))
@@ -105,6 +107,9 @@ $(LUA_CLIB_PATH)/profile.so : lualib-src/lua-profile.c | $(LUA_CLIB_PATH)
$(LUA_CLIB_PATH)/multicast.so : lualib-src/lua-multicast.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
$(LUA_CLIB_PATH)/cluster.so : lualib-src/lua-cluster.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
clean :
rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so

View File

@@ -1,6 +1,6 @@
## Build
Install autoconf first for jemalloc
For linux, install autoconf first for jemalloc
```
git clone git@github.com:cloudwu/skynet.git
@@ -15,6 +15,8 @@ export PLAT=linux
make
```
For freeBSD , use gmake instead of make .
## Test
Run these in different console

View File

@@ -8,7 +8,7 @@ local CMD = {}
local client_fd
local function send_client(v)
socket.write(client_fd, netpack.pack(jsonpack.pack(0,v)))
socket.write(client_fd, netpack.pack(jsonpack.pack(0, {true, v})))
end
local function response_client(session,v)

9
examples/cluster1.lua Normal file
View File

@@ -0,0 +1,9 @@
local skynet = require "skynet"
local cluster = require "cluster"
skynet.start(function()
skynet.newservice("simpledb")
print(skynet.call("SIMPLEDB", "lua", "SET", "a", "foobar"))
print(skynet.call("SIMPLEDB", "lua", "GET", "a"))
cluster.open(2528)
end)

6
examples/cluster2.lua Normal file
View File

@@ -0,0 +1,6 @@
local skynet = require "skynet"
local cluster = require "cluster"
skynet.start(function()
print(cluster.call("db", "SIMPLEDB", "GET", "a"))
end)

1
examples/clustername.lua Normal file
View File

@@ -0,0 +1 @@
db = "127.0.0.1:2528"

View File

@@ -12,3 +12,4 @@ lualoader = "lualib/loader.lua"
-- preload = "./examples/preload.lua" -- run preload.lua before every lua service run
snax = root.."examples/?.lua;"..root.."test/?.lua"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"

9
examples/config.c1 Normal file
View File

@@ -0,0 +1,9 @@
thread = 8
logger = nil
harbor = 0
start = "cluster1"
bootstrap = "snlua bootstrap" -- The service for bootstrap
luaservice = "./service/?.lua;./test/?.lua;./examples/?.lua"
lualoader = "lualib/loader.lua"
cpath = "./cservice/?.so"
cluster = "./examples/clustername.lua"

9
examples/config.c2 Normal file
View File

@@ -0,0 +1,9 @@
thread = 8
logger = nil
harbor = 0
start = "cluster2"
bootstrap = "snlua bootstrap" -- The service for bootstrap
luaservice = "./service/?.lua;./test/?.lua;./examples/?.lua"
lualoader = "lualib/loader.lua"
cpath = "./cservice/?.so"
cluster = "./examples/clustername.lua"

View File

@@ -1,5 +1,3 @@
#include "skynet_malloc.h"
#include <lua.h>
#include <lauxlib.h>
@@ -70,10 +68,17 @@ struct bson_reader {
int size;
};
static inline int32_t
get_length(const uint8_t * data) {
const uint8_t * b = (const uint8_t *)data;
int32_t len = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
return len;
}
static inline void
bson_destroy(struct bson *b) {
if (b->ptr != b->buffer) {
skynet_free(b->ptr);
free(b->ptr);
}
}
@@ -93,10 +98,10 @@ bson_reserve(struct bson *b, int sz) {
} while (b->cap <= b->size + sz);
if (b->ptr == b->buffer) {
b->ptr = skynet_malloc(b->cap);
b->ptr = malloc(b->cap);
memcpy(b->ptr, b->buffer, b->size);
} else {
b->ptr = skynet_realloc(b->ptr, b->cap);
b->ptr = realloc(b->ptr, b->cap);
}
}
@@ -258,13 +263,13 @@ append_key(struct bson *bs, int type, const char *key, size_t sz) {
static void
append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) {
lua_Integer i = lua_tointeger(L, -1);
int64_t i = lua_tointeger(L, -1);
lua_Number d = lua_tonumber(L,-1);
if (i != d) {
append_key(bs, BSON_REAL, key, sz);
write_double(bs, d);
} else {
int si = (int64_t)i >> 32;
int si = i >> 31;
if (si == 0 || si == -1) {
append_key(bs, BSON_INT32, key, sz);
write_int32(bs, i);
@@ -459,7 +464,7 @@ pack_dict(lua_State *L, struct bson *b, bool isarray) {
}
static void
pack_sorted_dict(lua_State *L, struct bson *b, int n) {
pack_ordered_dict(lua_State *L, struct bson *b, int n) {
int length = reserve_length(b);
int i;
for (i=0;i<n;i+=2) {
@@ -534,6 +539,9 @@ unpack_dict(lua_State *L, struct bson_reader *br, bool array) {
break;
case BSON_STRING: {
int sz = read_int32(L, &t);
if (sz <= 0) {
luaL_error(L, "Invalid bson string , length = %d", sz);
}
lua_pushlstring(L, read_bytes(L, &t, sz), sz-1);
break;
}
@@ -643,7 +651,7 @@ static int
lmakeindex(lua_State *L) {
int32_t *bson = luaL_checkudata(L,1,"bson");
const uint8_t * start = (const uint8_t *)bson;
struct bson_reader br = { start+4, *bson - 5 };
struct bson_reader br = { start+4, get_length(start) - 5 };
lua_newtable(L);
for (;;) {
@@ -806,6 +814,9 @@ lreplace(lua_State *L) {
write_int64(&b, i);
break;
}
default:
luaL_error(L, "Can't replace type %d", type);
break;
}
return 0;
}
@@ -816,7 +827,9 @@ ldecode(lua_State *L) {
if (data == NULL) {
return 0;
}
struct bson_reader br = { (const uint8_t *)data , *data };
const uint8_t * b = (const uint8_t *)data;
int32_t len = get_length(b);
struct bson_reader br = { b , len };
unpack_dict(L, &br, false);
@@ -865,7 +878,7 @@ lencode_order(lua_State *L) {
if (n%2 != 0) {
return luaL_error(L, "Invalid ordered dict");
}
pack_sorted_dict(L, &b, n);
pack_ordered_dict(L, &b, n);
lua_settop(L,1);
void * ud = lua_newuserdata(L, b.size);
memcpy(ud, b.ptr, b.size);
@@ -1136,14 +1149,14 @@ lobjectid(lua_State *L) {
}
} else {
time_t ti = time(NULL);
oid[2] = ti & 0xff;
oid[3] = (ti>>8) & 0xff;
oid[4] = (ti>>16) & 0xff;
oid[5] = (ti>>24) & 0xff;
oid[2] = (ti>>24) & 0xff;
oid[3] = (ti>>16) & 0xff;
oid[4] = (ti>>8) & 0xff;
oid[5] = ti & 0xff;
memcpy(oid+6 , oid_header, 5);
oid[11] = oid_counter & 0xff;
oid[11] = (oid_counter>>16) & 0xff;
oid[12] = (oid_counter>>8) & 0xff;
oid[13] = (oid_counter>>16) & 0xff;
oid[13] = oid_counter & 0xff;
++oid_counter;
}
lua_pushlstring( L, (const char *)oid, 14);
@@ -1190,3 +1203,4 @@ luaopen_bson(lua_State *L) {
return 1;
}

205
lualib-src/lua-cluster.c Normal file
View File

@@ -0,0 +1,205 @@
#include <lua.h>
#include <lauxlib.h>
#include <string.h>
#include "skynet.h"
/*
uint32_t/string addr
uint32_t/session session
lightuserdata msg
uint32_t sz
return
string request
uint32_t next_session
*/
#define TEMP_LENGTH 0x10002
static void
fill_uint32(uint8_t * buf, uint32_t n) {
buf[0] = n & 0xff;
buf[1] = (n >> 8) & 0xff;
buf[2] = (n >> 16) & 0xff;
buf[3] = (n >> 24) & 0xff;
}
static void
fill_header(lua_State *L, uint8_t *buf, int sz, void *msg) {
if (sz >= 0x10000) {
skynet_free(msg);
luaL_error(L, "request message is too long %d", sz);
}
buf[0] = (sz >> 8) & 0xff;
buf[1] = sz & 0xff;
}
static void
packreq_number(lua_State *L, int session, void * msg, size_t sz) {
uint32_t addr = lua_tounsigned(L,1);
uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+9, msg);
buf[2] = 0;
fill_uint32(buf+3, addr);
fill_uint32(buf+7, (uint32_t)session);
memcpy(buf+11,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+11);
}
static void
packreq_string(lua_State *L, int session, void * msg, size_t sz) {
size_t namelen = 0;
const char *name = lua_tolstring(L, 1, &namelen);
if (name == NULL || namelen < 1 || namelen > 255) {
skynet_free(msg);
luaL_error(L, "name is too long %s", name);
}
uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+5+namelen, msg);
buf[2] = (uint8_t)namelen;
memcpy(buf+3, name, namelen);
fill_uint32(buf+3+namelen, (uint32_t)session);
memcpy(buf+7+namelen,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+7+namelen);
}
static int
lpackrequest(lua_State *L) {
void *msg = lua_touserdata(L,3);
if (msg == NULL) {
return luaL_error(L, "Invalid request message");
}
size_t sz = luaL_checkunsigned(L,4);
int session = luaL_checkinteger(L,2);
if (session <= 0) {
return luaL_error(L, "Invalid request session %d", session);
}
int addr_type = lua_type(L,1);
if (addr_type == LUA_TNUMBER) {
packreq_number(L, session, msg, sz);
} else {
packreq_string(L, session, msg, sz);
}
if (++session < 0) {
session = 1;
}
skynet_free(msg);
lua_pushinteger(L, session);
return 2;
}
/*
string packed message
return
uint32_t or string addr
int session
string msg
*/
static inline uint32_t
unpack_uint32(const uint8_t * buf) {
return buf[0] | buf[1]<<8 | buf[2]<<16 | buf[3]<<24;
}
static int
unpackreq_number(lua_State *L, const uint8_t * buf, size_t sz) {
if (sz < 9) {
return luaL_error(L, "Invalid cluster message");
}
uint32_t address = unpack_uint32(buf+1);
uint32_t session = unpack_uint32(buf+5);
lua_pushunsigned(L, address);
lua_pushunsigned(L, session);
lua_pushlstring(L, (const char *)buf+9, sz-9);
return 3;
}
static int
unpackreq_string(lua_State *L, const uint8_t * buf, size_t sz) {
size_t namesz = buf[0];
if (sz < namesz + 5) {
return luaL_error(L, "Invalid cluster message");
}
lua_pushlstring(L, (const char *)buf+1, namesz);
uint32_t session = unpack_uint32(buf + namesz + 1);
lua_pushunsigned(L, session);
lua_pushlstring(L, (const char *)buf+1+namesz+4, sz - namesz - 5);
return 3;
}
static int
lunpackrequest(lua_State *L) {
size_t sz;
const char *msg = luaL_checklstring(L,1,&sz);
if (msg[0] == 0) {
return unpackreq_number(L, (const uint8_t *)msg, sz);
} else {
return unpackreq_string(L, (const uint8_t *)msg, sz);
}
}
/*
int session
lightuserdata msg
int sz
return string response
*/
static int
lpackresponse(lua_State *L) {
uint32_t session = luaL_checkunsigned(L,1);
// clusterd.lua:command.socket call lpackresponse,
// and the msg/sz is return by skynet.rawcall , so don't free(msg)
void * msg = lua_touserdata(L,2);
size_t sz = luaL_checkunsigned(L, 3);
uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+4, msg);
fill_uint32(buf+2, session);
memcpy(buf+6,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+6);
return 1;
}
/*
string packed response
return integer session
boolean ok
string msg
*/
static int
lunpackresponse(lua_State *L) {
size_t sz;
const char * buf = luaL_checklstring(L, 1, &sz);
if (sz < 4) {
return 0;
}
uint32_t session = unpack_uint32((const uint8_t *)buf);
lua_pushunsigned(L, session);
lua_pushboolean(L, 1);
lua_pushlstring(L, buf+4, sz-4);
return 3;
}
int
luaopen_cluster_c(lua_State *L) {
luaL_Reg l[] = {
{ "packrequest", lpackrequest },
{ "unpackrequest", lunpackrequest },
{ "packresponse", lpackresponse },
{ "unpackresponse", lunpackresponse },
{ NULL, NULL },
};
luaL_checkversion(L);
luaL_newlib(L,l);
return 1;
}

View File

@@ -260,6 +260,13 @@ op_reply(lua_State *L) {
lua_pushnil(L);
lua_rawseti(L, 2, i);
}
} else {
if (sz >= 4) {
sz -= get_length((document)doc);
}
}
if (sz != 0) {
return luaL_error(L, "Invalid result bson document");
}
lua_pushboolean(L,1);
lua_pushinteger(L, id);

View File

@@ -188,10 +188,29 @@ pop_lstring(lua_State *L, struct socket_buffer *sb, int sz, int skip) {
luaL_pushresult(&b);
}
static int
lheader(lua_State *L) {
size_t len;
const uint8_t * s = (const uint8_t *)luaL_checklstring(L, 1, &len);
if (len > 4 || len < 1) {
return luaL_error(L, "Invalid read %s", s);
}
int i;
size_t sz = 0;
for (i=0;i<(int)len;i++) {
sz <<= 8;
sz |= s[i];
}
lua_pushunsigned(L, sz);
return 1;
}
/*
userdata send_buffer
table pool
integer sz
integer sz
*/
static int
lpopbuffer(lua_State *L) {
@@ -469,6 +488,7 @@ luaopen_socketdriver(lua_State *L) {
{ "clear", lclearbuffer },
{ "readline", lreadline },
{ "str2p", lstr2p },
{ "header", lheader },
{ "unpack", lunpack },
{ NULL, NULL },

19
lualib/cluster.lua Normal file
View File

@@ -0,0 +1,19 @@
local skynet = require "skynet"
local clusterd
local cluster = {}
function cluster.call(node, address, ...)
-- skynet.pack(...) will free by cluster.c.packrequest
return skynet.call(clusterd, "lua", "req", node, address, skynet.pack(...))
end
function cluster.open(port)
skynet.call(clusterd, "lua", "listen", "0.0.0.0", port)
end
skynet.init(function()
clusterd = skynet.uniqueservice("clusterd")
end)
return cluster

View File

@@ -98,7 +98,7 @@ function mongo.client( conf )
host = obj.host,
port = obj.port,
response = dispatch_reply,
auth = mongo_auth(conf),
auth = mongo_auth(obj),
}
setmetatable(obj, client_meta)
obj.__sock:connect(true) -- try connect only once
@@ -167,7 +167,9 @@ function mongo_db:runCommand(cmd,cmd_v,...)
bson_cmd = bson_encode_order(cmd,cmd_v,...)
end
local pack = driver.query(request_id, 0, self.__cmd, 0, 1, bson_cmd)
local doc = sock:request(pack, request_id).document
-- we must hold req (req.data), because req.document is a lightuserdata, it's a pointer to the string (req.data)
local req = sock:request(pack, request_id)
local doc = req.document
return bson_decode(doc)
end
@@ -224,7 +226,9 @@ function mongo_collection:findOne(query, selector)
local request_id = conn:genId()
local sock = conn.__sock
local pack = driver.query(request_id, 0, self.full_name, 0, 1, query and bson_encode(query) or empty_bson, selector and bson_encode(selector))
local doc = sock:request(pack, request_id).document
-- we must hold req (req.data), because req.document is a lightuserdata, it's a pointer to the string (req.data)
local req = sock:request(pack, request_id)
local doc = req.document
return bson_decode(doc)
end

View File

@@ -151,7 +151,7 @@ function socket.bind(os_fd)
end
function socket.stdin()
return socket.bind(1)
return socket.bind(0)
end
function socket.start(id, func)
@@ -266,6 +266,7 @@ end
socket.write = assert(driver.send)
socket.lwrite = assert(driver.lsend)
socket.header = assert(driver.header)
function socket.invalid(id)
return socket_pool[id] == nil

View File

@@ -31,7 +31,7 @@ macosx : EXPORT :=
macosx linux : SKYNET_LIBS += -ldl
linux freebsd : SKYNET_LIBS += -lrt
# Turn off jemalloc and malloc hook on macosx
# Turn off jemalloc and malloc hook on macosx and freebsd
macosx : MALLOC_STATICLIB :=
macosx : SKYNET_DEFINES :=-DNOUSE_JEMALLOC

292
service-src/service_dummy.c Normal file
View File

@@ -0,0 +1,292 @@
#include "skynet.h"
#include "skynet_harbor.h"
#include <string.h>
#include <assert.h>
#define HASH_SIZE 4096
#define DEFAULT_QUEUE_SIZE 1024
struct msg {
uint8_t * buffer;
size_t size;
};
struct msg_queue {
int size;
int head;
int tail;
struct msg * data;
};
struct keyvalue {
struct keyvalue * next;
char key[GLOBALNAME_LENGTH];
uint32_t hash;
uint32_t value;
struct msg_queue * queue;
};
struct hashmap {
struct keyvalue *node[HASH_SIZE];
};
/*
message type (8bits) is in destination high 8bits
harbor id (8bits) is also in that place , but remote message doesn't need harbor id.
*/
struct remote_message_header {
uint32_t source;
uint32_t destination;
uint32_t session;
};
// 12 is sizeof(struct remote_message_header)
#define HEADER_COOKIE_LENGTH 12
struct dummy {
struct skynet_context *ctx;
struct hashmap * map;
};
// hash table
static void
_push_queue(struct msg_queue * queue, const void * buffer, size_t sz, struct remote_message_header * header) {
// If there is only 1 free slot which is reserved to distinguish full/empty
// of circular buffer, expand it.
if (((queue->tail + 1) % queue->size) == queue->head) {
struct msg * new_buffer = skynet_malloc(queue->size * 2 * sizeof(struct msg));
int i;
for (i=0;i<queue->size-1;i++) {
new_buffer[i] = queue->data[(i+queue->head) % queue->size];
}
skynet_free(queue->data);
queue->data = new_buffer;
queue->head = 0;
queue->tail = queue->size - 1;
queue->size *= 2;
}
struct msg * slot = &queue->data[queue->tail];
queue->tail = (queue->tail + 1) % queue->size;
slot->buffer = skynet_malloc(sz + sizeof(*header));
memcpy(slot->buffer, buffer, sz);
memcpy(slot->buffer + sz, header, sizeof(*header));
slot->size = sz + sizeof(*header);
}
static struct msg *
_pop_queue(struct msg_queue * queue) {
if (queue->head == queue->tail) {
return NULL;
}
struct msg * slot = &queue->data[queue->head];
queue->head = (queue->head + 1) % queue->size;
return slot;
}
static struct msg_queue *
_new_queue() {
struct msg_queue * queue = skynet_malloc(sizeof(*queue));
queue->size = DEFAULT_QUEUE_SIZE;
queue->head = 0;
queue->tail = 0;
queue->data = skynet_malloc(DEFAULT_QUEUE_SIZE * sizeof(struct msg));
return queue;
}
static void
_release_queue(struct msg_queue *queue) {
if (queue == NULL)
return;
struct msg * m = _pop_queue(queue);
while (m) {
skynet_free(m->buffer);
m = _pop_queue(queue);
}
skynet_free(queue->data);
skynet_free(queue);
}
static struct keyvalue *
_hash_search(struct hashmap * hash, const char name[GLOBALNAME_LENGTH]) {
uint32_t *ptr = (uint32_t*) name;
uint32_t h = ptr[0] ^ ptr[1] ^ ptr[2] ^ ptr[3];
struct keyvalue * node = hash->node[h % HASH_SIZE];
while (node) {
if (node->hash == h && strncmp(node->key, name, GLOBALNAME_LENGTH) == 0) {
return node;
}
node = node->next;
}
return NULL;
}
static struct keyvalue *
_hash_insert(struct hashmap * hash, const char name[GLOBALNAME_LENGTH]) {
uint32_t *ptr = (uint32_t *)name;
uint32_t h = ptr[0] ^ ptr[1] ^ ptr[2] ^ ptr[3];
struct keyvalue ** pkv = &hash->node[h % HASH_SIZE];
struct keyvalue * node = skynet_malloc(sizeof(*node));
memcpy(node->key, name, GLOBALNAME_LENGTH);
node->next = *pkv;
node->queue = NULL;
node->hash = h;
node->value = 0;
*pkv = node;
return node;
}
static struct hashmap *
_hash_new() {
struct hashmap * h = skynet_malloc(sizeof(struct hashmap));
memset(h,0,sizeof(*h));
return h;
}
static void
_hash_delete(struct hashmap *hash) {
int i;
for (i=0;i<HASH_SIZE;i++) {
struct keyvalue * node = hash->node[i];
while (node) {
struct keyvalue * next = node->next;
_release_queue(node->queue);
skynet_free(node);
node = next;
}
}
skynet_free(hash);
}
///////////////
struct dummy *
dummy_create(void) {
struct dummy * d = skynet_malloc(sizeof(*d));
d->map = _hash_new();
return d;
}
void
dummy_release(struct dummy *d) {
_hash_delete(d->map);
skynet_free(d);
}
static inline void
to_bigendian(uint8_t *buffer, uint32_t n) {
buffer[0] = (n >> 24) & 0xff;
buffer[1] = (n >> 16) & 0xff;
buffer[2] = (n >> 8) & 0xff;
buffer[3] = n & 0xff;
}
static inline void
_header_to_message(const struct remote_message_header * header, uint8_t * message) {
to_bigendian(message , header->source);
to_bigendian(message+4 , header->destination);
to_bigendian(message+8 , header->session);
}
static inline uint32_t
from_bigendian(uint32_t n) {
union {
uint32_t big;
uint8_t bytes[4];
} u;
u.big = n;
return u.bytes[0] << 24 | u.bytes[1] << 16 | u.bytes[2] << 8 | u.bytes[3];
}
static inline void
_message_to_header(const uint32_t *message, struct remote_message_header *header) {
header->source = from_bigendian(message[0]);
header->destination = from_bigendian(message[1]);
header->session = from_bigendian(message[2]);
}
static void
_dispatch_queue(struct dummy *h, struct msg_queue * queue, uint32_t handle, const char name[GLOBALNAME_LENGTH] ) {
struct msg * m = _pop_queue(queue);
while (m) {
struct remote_message_header cookie;
uint8_t *ptr = m->buffer + m->size - sizeof(cookie);
memcpy(&cookie, ptr, sizeof(cookie));
int type = cookie.destination >> HANDLE_REMOTE_SHIFT;
skynet_send(h->ctx, cookie.source, handle , type | PTYPE_TAG_DONTCOPY, cookie.session, m->buffer, m->size - sizeof(cookie));
m = _pop_queue(queue);
}
}
static void
_update_name(struct dummy *h, const char name[GLOBALNAME_LENGTH], uint32_t handle) {
struct keyvalue * node = _hash_search(h->map, name);
if (node == NULL) {
node = _hash_insert(h->map, name);
}
node->value = handle;
if (node->queue) {
_dispatch_queue(h, node->queue, handle, name);
_release_queue(node->queue);
node->queue = NULL;
}
}
static void
_send_name(struct dummy *h, uint32_t source, const char name[GLOBALNAME_LENGTH], int type, int session, const char * msg, size_t sz) {
struct keyvalue * node = _hash_search(h->map, name);
if (node == NULL) {
node = _hash_insert(h->map, name);
}
if (node->value == 0) {
if (node->queue == NULL) {
node->queue = _new_queue();
}
struct remote_message_header header;
header.source = source;
header.destination = type << HANDLE_REMOTE_SHIFT;
header.session = (uint32_t)session;
_push_queue(node->queue, msg, sz, &header);
} else {
// local message
skynet_send(h->ctx, source, node->value , type | PTYPE_TAG_DONTCOPY, session, (void *)msg, sz);
}
}
static int
_mainloop(struct skynet_context * context, void * ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
struct dummy * h = ud;
switch (type) {
case PTYPE_SYSTEM: {
// register name message
const struct remote_message *rmsg = msg;
assert (sz == sizeof(rmsg->destination));
_update_name(h, rmsg->destination.name, rmsg->destination.handle);
return 0;
}
default: {
// remote message out
const struct remote_message *rmsg = msg;
if (rmsg->destination.handle == 0) {
_send_name(h, source , rmsg->destination.name, type, session, rmsg->message, rmsg->sz);
} else {
// local message
skynet_send(context, source, rmsg->destination.handle , type | PTYPE_TAG_DONTCOPY, session, (void *)rmsg->message, rmsg->sz);
}
return 0;
}
}
}
int
dummy_init(struct dummy *d, struct skynet_context *ctx, const char * args) {
d->ctx = ctx;
skynet_harbor_start(ctx);
skynet_callback(ctx, d, _mainloop);
return 0;
}

View File

@@ -47,6 +47,9 @@ struct remote_message_header {
uint32_t session;
};
// 12 is sizeof(struct remote_message_header)
#define HEADER_COOKIE_LENGTH 12
struct harbor {
struct skynet_context *ctx;
char * local_addr;
@@ -502,23 +505,23 @@ _mainloop(struct skynet_context * context, void * ud, int type, int session, uin
case PTYPE_HARBOR: {
// remote message in
const char * cookie = msg;
cookie += sz - 12;
cookie += sz - HEADER_COOKIE_LENGTH;
struct remote_message_header header;
_message_to_header((const uint32_t *)cookie, &header);
if (header.source == 0) {
if (header.destination < REMOTE_MAX) {
// 1 byte harbor id (0~255)
// update remote harbor address
char ip [sz - 11];
memcpy(ip, msg, sz-12);
ip[sz-11] = '\0';
char ip [sz - HEADER_COOKIE_LENGTH + 1];
memcpy(ip, msg, sz-HEADER_COOKIE_LENGTH);
ip[sz-HEADER_COOKIE_LENGTH] = '\0';
_update_remote_address(h, header.destination, ip);
} else {
// update global name
if (sz - 12 > GLOBALNAME_LENGTH) {
char name[sz-11];
memcpy(name, msg, sz-12);
name[sz-11] = '\0';
if (sz - HEADER_COOKIE_LENGTH > GLOBALNAME_LENGTH) {
char name[sz-HEADER_COOKIE_LENGTH+1];
memcpy(name, msg, sz-HEADER_COOKIE_LENGTH);
name[sz-HEADER_COOKIE_LENGTH] = '\0';
skynet_error(context, "Global name is too long %s", name);
}
_update_remote_name(h, msg, header.destination);
@@ -527,7 +530,7 @@ _mainloop(struct skynet_context * context, void * ud, int type, int session, uin
uint32_t destination = header.destination;
int type = (destination >> HANDLE_REMOTE_SHIFT) | PTYPE_TAG_DONTCOPY;
destination = (destination & HANDLE_MASK) | ((uint32_t)h->id << HANDLE_REMOTE_SHIFT);
skynet_send(context, header.source, destination, type, (int)header.session, (void *)msg, sz-12);
skynet_send(context, header.source, destination, type, (int)header.session, (void *)msg, sz-HEADER_COOKIE_LENGTH);
return 1;
}
return 0;

View File

@@ -28,7 +28,7 @@ logger_release(struct logger * inst) {
static int
_logger(struct skynet_context * context, void *ud, int type, int session, uint32_t source, const void * msg, size_t sz) {
struct logger * inst = ud;
fprintf(inst->handle, "[:%x] ",source);
fprintf(inst->handle, "[:%08x] ",source);
fwrite(msg, sz , 1, inst->handle);
fprintf(inst->handle, "\n");
fflush(inst->handle);

View File

@@ -4,17 +4,24 @@ skynet.start(function()
assert(skynet.launch("logger", skynet.getenv "logger"))
local standalone = skynet.getenv "standalone"
local master_addr = skynet.getenv "master"
local harbor_id = tonumber(skynet.getenv "harbor")
if harbor_id == 0 then
assert(standalone == nil)
standalone = true
skynet.setenv("standalone", "true")
assert(skynet.launch("dummy"))
else
local master_addr = skynet.getenv "master"
if standalone then
assert(skynet.launch("master", master_addr))
if standalone then
assert(skynet.launch("master", master_addr))
end
local local_addr = skynet.getenv "address"
assert(skynet.launch("harbor",master_addr, local_addr, harbor_id))
end
local local_addr = skynet.getenv "address"
local harbor_id = skynet.getenv "harbor"
assert(skynet.launch("harbor",master_addr, local_addr, harbor_id))
local launcher = assert(skynet.launch("snlua","launcher"))
skynet.name(".launcher", launcher)

69
service/clusterd.lua Normal file
View File

@@ -0,0 +1,69 @@
local skynet = require "skynet"
local sc = require "socketchannel"
local socket = require "socket"
local cluster = require "cluster.c"
local config_name = skynet.getenv "cluster"
local node_address = {}
assert(loadfile(config_name, "t", node_address))()
local node_session = {}
local command = {}
local function read_response(sock)
local sz = socket.header(sock:read(2))
local msg = sock:read(sz)
return cluster.unpackresponse(msg) -- session, ok, data
end
local function open_channel(t, key)
local host, port = string.match(node_address[key], "([^:]+):(.*)$")
local c = sc.channel {
host = host,
port = tonumber(port),
response = read_response,
}
assert(c:connect(true))
t[key] = c
node_session[key] = 1
return c
end
local node_channel = setmetatable({}, { __index = open_channel })
function command.listen(source, addr, port)
local gate = skynet.newservice("gate")
skynet.call(gate, "lua", "open", { address = addr, port = port })
skynet.ret(skynet.pack(nil))
end
function command.req(source, node, addr, msg, sz)
local request
local c = node_channel[node]
local session = node_session[node]
-- msg is a local pointer, cluster.packrequest will free it
request, node_session[node] = cluster.packrequest(addr, session , msg, sz)
skynet.ret(c:request(request, session))
end
local request_fd = {}
function command.socket(source, subcmd, fd, msg)
if subcmd == "data" then
local addr, session, msg = cluster.unpackrequest(msg)
local msg, sz = skynet.rawcall(addr, "lua", msg)
local response = cluster.packresponse(session, msg, sz)
socket.write(fd, response)
elseif subcmd == "open" then
skynet.error(string.format("socket accept from %s", msg))
skynet.call(source, "lua", "accept", fd)
else
skynet.error(string.format("socket %s %d : %s", subcmd, fd, msg))
end
end
skynet.start(function()
skynet.dispatch("lua", function(_, source, cmd, ...)
local f = assert(command[cmd])
f(source, ...)
end)
end)

View File

@@ -85,7 +85,7 @@ function MSG.data(fd, msg, sz)
if agent then
skynet.redirect(agent, c.client, "client", 0, msg, sz)
else
skynet.send(watchdog, "lua", "socket", "data", netpack.tostring(msg, sz))
skynet.send(watchdog, "lua", "socket", "data", fd, netpack.tostring(msg, sz))
end
end

View File

@@ -88,7 +88,7 @@ function command.ERROR(address)
skynet.redirect(reply.address , 0, "response", reply.session, "")
instance[address] = nil
end
services[address] = nil
return NORET
end

View File

@@ -106,7 +106,7 @@ mallctl_int64(const char* name, size_t* newval) {
} else {
je_mallctl(name, &v, &len, NULL, 0);
}
// printf("name: %s, value: %zd\n", name, v);
// skynet_error(NULL, "name: %s, value: %zd\n", name, v);
return v;
}
@@ -117,9 +117,9 @@ mallctl_opt(const char* name, int* newval) {
if(newval) {
int ret = je_mallctl(name, &v, &len, newval, sizeof(int));
if(ret == 0) {
printf("set new value(%d) for (%s) succeed\n", *newval, name);
skynet_error(NULL, "set new value(%d) for (%s) succeed\n", *newval, name);
} else {
printf("set new value(%d) for (%s) failed: error -> %d\n", *newval, name, ret);
skynet_error(NULL, "set new value(%d) for (%s) failed: error -> %d\n", *newval, name, ret);
}
} else {
je_mallctl(name, &v, &len, NULL, 0);
@@ -196,15 +196,15 @@ void
dump_c_mem() {
int i;
size_t total = 0;
printf("dump all service mem:\n");
skynet_error(NULL, "dump all service mem:");
for(i=0; i<SLOT_SIZE; i++) {
mem_data* data = &mem_stats[i];
if(data->handle != 0 && data->allocated != 0) {
total += data->allocated;
printf("0x%x -> %zdkb\n", data->handle, data->allocated >> 10);
skynet_error(NULL, "0x%x -> %zdkb", data->handle, data->allocated >> 10);
}
}
printf("+total: %zdkb\n",total >> 10);
skynet_error(NULL, "+total: %zdkb",total >> 10);
}
char *

View File

@@ -13,12 +13,13 @@
#define PTYPE_SYSTEM 4
#define PTYPE_HARBOR 5
#define PTYPE_SOCKET 6
// read lualib/skynet.lua lualib/simplemonitor.lua
// read lualib/skynet.lua examples/simplemonitor.lua
#define PTYPE_ERROR 7
// read lualib/skynet.lua lualib/mqueue.lua
// read lualib/skynet.lua lualib/mqueue.lua lualib/snax.lua
#define PTYPE_RESERVED_QUEUE 8
#define PTYPE_RESERVED_DEBUG 9
#define PTYPE_RESERVED_LUA 10
#define PTYPE_RESERVED_SNAX 11
#define PTYPE_TAG_DONTCOPY 0x10000
#define PTYPE_TAG_ALLOCSESSION 0x20000

View File

@@ -0,0 +1,96 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/file.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include "skynet_daemon.h"
static int
check_pid(const char *pidfile) {
int pid = 0;
FILE *f = fopen(pidfile,"r");
if (f == NULL)
return 0;
int n = fscanf(f,"%d", &pid);
fclose(f);
if (n !=1 || pid == 0 || pid == getpid()) {
return 0;
}
if (kill(pid, 0) && errno == ESRCH)
return 0;
return pid;
}
static int
write_pid(const char *pidfile) {
FILE *f;
int pid = 0;
int fd = open(pidfile, O_RDWR|O_CREAT, 0644);
if (fd == -1) {
fprintf(stderr, "Can't create %s.\n", pidfile);
return 0;
}
f = fdopen(fd, "r+");
if (f == NULL) {
fprintf(stderr, "Can't open %s.\n", pidfile);
return 0;
}
if (flock(fd, LOCK_EX|LOCK_NB) == -1) {
int n = fscanf(f, "%d", &pid);
fclose(f);
if (n != 1) {
fprintf(stderr, "Can't lock and read pidfile.\n");
} else {
fprintf(stderr, "Can't lock pidfile, lock is held by pid %d.\n", pid);
}
return 0;
}
pid = getpid();
if (!fprintf(f,"%d\n", pid)) {
fprintf(stderr, "Can't write pid.\n");
close(fd);
return 0;
}
fflush(f);
return pid;
}
int
daemon_init(const char *pidfile) {
int pid = check_pid(pidfile);
if (pid) {
fprintf(stderr, "Skynet is already running, pid = %d.\n", pid);
return 1;
}
#ifdef __APPLE__
fprintf(stderr, "'daemon' is deprecated: first deprecated in OS X 10.5 , use launchd instead.\n");
#else
if (daemon(1,0)) {
fprintf(stderr, "Can't daemonize.\n");
return 1;
}
#endif
pid = write_pid(pidfile);
if (pid == 0) {
return 1;
}
return 0;
}
int
daemon_exit(const char *pidfile) {
return unlink(pidfile);
}

View File

@@ -0,0 +1,7 @@
#ifndef skynet_daemon_h
#define skynet_daemon_h
int daemon_init(const char *pidfile);
int daemon_exit(const char *pidfile);
#endif

View File

@@ -9,6 +9,7 @@
#include <string.h>
#define DEFAULT_SLOT_SIZE 4
#define MAX_SLOT_SIZE 0x40000000
struct handle_name {
char * name;
@@ -168,6 +169,7 @@ static void
_insert_name_before(struct handle_storage *s, char *name, uint32_t handle, int before) {
if (s->name_count >= s->name_cap) {
s->name_cap *= 2;
assert(s->name_cap <= MAX_SLOT_SIZE);
struct handle_name * n = skynet_malloc(s->name_cap * sizeof(struct handle_name));
int i;
for (i=0;i<before;i++) {

View File

@@ -7,18 +7,20 @@
#include <assert.h>
static struct skynet_context * REMOTE = 0;
static unsigned int HARBOR = 0;
static unsigned int HARBOR = ~0;
void
skynet_harbor_send(struct remote_message *rmsg, uint32_t source, int session) {
int type = rmsg->sz >> HANDLE_REMOTE_SHIFT;
rmsg->sz &= HANDLE_MASK;
assert(type != PTYPE_SYSTEM && type != PTYPE_HARBOR);
assert(type != PTYPE_SYSTEM && type != PTYPE_HARBOR && REMOTE);
skynet_context_send(REMOTE, rmsg, sizeof(*rmsg) , source, type , session);
}
void
skynet_harbor_register(struct remote_name *rname) {
if (REMOTE == NULL)
return;
int i;
int number = 1;
for (i=0;i<GLOBALNAME_LENGTH;i++) {
@@ -34,7 +36,7 @@ skynet_harbor_register(struct remote_name *rname) {
int
skynet_harbor_message_isremote(uint32_t handle) {
assert(HARBOR != 0);
assert(HARBOR != ~0);
int h = (handle & ~HANDLE_MASK);
return h != HARBOR && h !=0;
}

View File

@@ -4,6 +4,7 @@
struct skynet_config {
int thread;
int harbor;
const char * daemon;
const char * module_path;
const char * bootstrap;
};

View File

@@ -35,6 +35,7 @@ optboolean(const char *key, int opt) {
return strcmp(str,"true")==0;
}
*/
static const char *
optstring(const char *key,const char * opt) {
const char * str = skynet_getenv(key);
@@ -109,21 +110,16 @@ main(int argc, char *argv[]) {
}
_init_env(L);
#ifdef LUA_CACHELIB
printf("Skynet lua code cache enable\n");
#endif
config.thread = optint("thread",8);
config.module_path = optstring("cpath","./cservice/?.so");
config.harbor = optint("harbor", 1);
config.bootstrap = optstring("bootstrap","snlua bootstrap");
config.daemon = optstring("daemon", NULL);
lua_close(L);
skynet_start(&config);
skynet_globalexit();
printf("skynet exit\n");
return 0;
}

View File

@@ -34,7 +34,6 @@ struct global_queue {
struct message_queue ** queue;
// We use a separated flag array to ensure the mq is pushed.
// See the comments below.
bool * flag;
struct message_queue *list;
};
@@ -45,11 +44,14 @@ static struct global_queue *Q = NULL;
#define GP(p) ((p) % MAX_GLOBAL_MQ)
static void
void
skynet_globalmq_push(struct message_queue * queue) {
struct global_queue *q= Q;
if (q->flag[GP(q->tail)]) {
uint32_t tail = GP(__sync_fetch_and_add(&q->tail,1));
// only one thread can set the slot (change q->queue[tail] from NULL to queue)
if (!__sync_bool_compare_and_swap(&q->queue[tail], NULL, queue)) {
// The queue may full seldom, save queue in list
assert(queue->next == NULL);
struct message_queue * last;
@@ -60,14 +62,6 @@ skynet_globalmq_push(struct message_queue * queue) {
return;
}
uint32_t tail = GP(__sync_fetch_and_add(&q->tail,1));
// The thread would suspend here, and the q->queue[tail] is last version ,
// but the queue tail is increased.
// So we set q->flag[tail] after changing q->queue[tail].
q->queue[tail] = queue;
__sync_synchronize();
q->flag[tail] = true;
}
struct message_queue *
@@ -93,18 +87,18 @@ skynet_globalmq_pop() {
}
}
// Check the flag first, if the flag is false, the pushing may not complete.
if(!q->flag[head_ptr]) {
struct message_queue * mq = q->queue[head_ptr];
if (mq == NULL) {
// globalmq push not complete
return NULL;
}
__sync_synchronize();
struct message_queue * mq = q->queue[head_ptr];
if (!__sync_bool_compare_and_swap(&q->head, head, head+1)) {
return NULL;
}
q->flag[head_ptr] = false;
// only one thread can get the slot (change q->queue[head_ptr] to NULL)
if (!__sync_bool_compare_and_swap(&q->queue[head_ptr], mq, NULL)) {
return NULL;
}
return mq;
}
@@ -220,26 +214,10 @@ skynet_mq_init() {
struct global_queue *q = skynet_malloc(sizeof(*q));
memset(q,0,sizeof(*q));
q->queue = skynet_malloc(MAX_GLOBAL_MQ * sizeof(struct message_queue *));
q->flag = skynet_malloc(MAX_GLOBAL_MQ * sizeof(bool));
memset(q->flag, 0, sizeof(bool) * MAX_GLOBAL_MQ);
memset(q->queue, 0, sizeof(struct message_queue *) * MAX_GLOBAL_MQ);
Q=q;
}
void
skynet_mq_force_push(struct message_queue * queue) {
assert(queue->in_global);
skynet_globalmq_push(queue);
}
void
skynet_mq_pushglobal(struct message_queue *queue) {
LOCK(queue)
assert(queue->in_global);
skynet_globalmq_push(queue);
queue->in_global = MQ_IN_GLOBAL;
UNLOCK(queue)
}
void
skynet_mq_mark_release(struct message_queue *q) {
LOCK(q)
@@ -268,7 +246,7 @@ skynet_mq_release(struct message_queue *q, message_drop drop_func, void *ud) {
UNLOCK(q)
_drop_queue(q, drop_func, ud);
} else {
skynet_mq_force_push(q);
skynet_globalmq_push(q);
UNLOCK(q)
}
}

View File

@@ -13,6 +13,7 @@ struct skynet_message {
struct message_queue;
void skynet_globalmq_push(struct message_queue * queue);
struct message_queue * skynet_globalmq_pop(void);
struct message_queue * skynet_mq_create(uint32_t handle);
@@ -30,9 +31,6 @@ void skynet_mq_push(struct message_queue *q, struct skynet_message *message);
// return the length of message queue, for debug
int skynet_mq_length(struct message_queue *q);
void skynet_mq_force_push(struct message_queue *q);
void skynet_mq_pushglobal(struct message_queue *q);
void skynet_mq_init();
#endif

View File

@@ -52,6 +52,7 @@ struct skynet_context {
struct skynet_node {
int total;
int init;
uint32_t monitor_exit;
pthread_key_t handle_key;
};
@@ -75,8 +76,13 @@ context_dec() {
uint32_t
skynet_current_handle(void) {
void * handle = pthread_getspecific(G_NODE.handle_key);
return (uint32_t)(uintptr_t)handle;
if (G_NODE.init) {
void * handle = pthread_getspecific(G_NODE.handle_key);
return (uint32_t)(uintptr_t)handle;
} else {
uintptr_t v = (uint32_t)(-THREAD_MAIN);
return v;
}
}
static void
@@ -139,7 +145,7 @@ skynet_context_new(const char * name, const char *param) {
if (ret) {
ctx->init = true;
}
skynet_mq_force_push(queue);
skynet_globalmq_push(queue);
if (ret) {
skynet_error(ret, "LAUNCH %s %s", name, param ? param : "");
}
@@ -228,11 +234,13 @@ _dispatch_message(struct skynet_context *ctx, struct skynet_message *msg) {
CHECKCALLING_END(ctx)
}
int
skynet_context_message_dispatch(struct skynet_monitor *sm) {
struct message_queue * q = skynet_globalmq_pop();
if (q==NULL)
return 1;
struct message_queue *
skynet_context_message_dispatch(struct skynet_monitor *sm, struct message_queue *q) {
if (q == NULL) {
q = skynet_globalmq_pop();
if (q==NULL)
return NULL;
}
uint32_t handle = skynet_mq_handle(q);
@@ -240,13 +248,13 @@ skynet_context_message_dispatch(struct skynet_monitor *sm) {
if (ctx == NULL) {
struct drop_t d = { handle };
skynet_mq_release(q, drop_message, &d);
return 0;
return skynet_globalmq_pop();
}
struct skynet_message msg;
if (skynet_mq_pop(q,&msg)) {
skynet_context_release(ctx);
return 0;
return skynet_globalmq_pop();
}
skynet_monitor_trigger(sm, msg.source , handle);
@@ -258,12 +266,18 @@ skynet_context_message_dispatch(struct skynet_monitor *sm) {
}
assert(q == ctx->queue);
skynet_mq_pushglobal(q);
struct message_queue *nq = skynet_globalmq_pop();
if (nq) {
// If global mq is not empty , push q back, and return next queue (nq)
// Else (global mq is empty or block, don't push q back, and return q again (for next dispatch)
skynet_globalmq_push(q);
q = nq;
}
skynet_context_release(ctx);
skynet_monitor_trigger(sm, 0,0);
return 0;
return q;
}
static void
@@ -642,6 +656,7 @@ void
skynet_globalinit(void) {
G_NODE.total = 0;
G_NODE.monitor_exit = 0;
G_NODE.init = 1;
if (pthread_key_create(&G_NODE.handle_key, NULL)) {
fprintf(stderr, "pthread_key_create failed");
exit(1);

View File

@@ -16,7 +16,7 @@ void skynet_context_init(struct skynet_context *, uint32_t handle);
int skynet_context_push(uint32_t handle, struct skynet_message *message);
void skynet_context_send(struct skynet_context * context, void * msg, size_t sz, uint32_t source, int type, int session);
int skynet_context_newsession(struct skynet_context *);
int skynet_context_message_dispatch(struct skynet_monitor *); // return 1 when block
struct message_queue * skynet_context_message_dispatch(struct skynet_monitor *, struct message_queue *); // return next queue
int skynet_context_total();
void skynet_context_endless(uint32_t handle); // for monitor

View File

@@ -7,6 +7,7 @@
#include "skynet_timer.h"
#include "skynet_monitor.h"
#include "skynet_socket.h"
#include "skynet_daemon.h"
#include <pthread.h>
#include <unistd.h>
@@ -120,8 +121,10 @@ _worker(void *p) {
struct monitor *m = wp->m;
struct skynet_monitor *sm = m->m[id];
skynet_initthread(THREAD_WORKER);
struct message_queue * q = NULL;
for (;;) {
if (skynet_context_message_dispatch(sm)) {
q = skynet_context_message_dispatch(sm, q);
if (q == NULL) {
CHECK_ABORT
if (pthread_mutex_lock(&m->mutex) == 0) {
++ m->sleep;
@@ -195,6 +198,11 @@ bootstrap(const char * cmdline) {
void
skynet_start(struct skynet_config * config) {
if (config->daemon) {
if (daemon_init(config->daemon)) {
exit(1);
}
}
skynet_harbor_init(config->harbor);
skynet_handle_init(config->harbor);
skynet_mq_init();
@@ -206,4 +214,7 @@ skynet_start(struct skynet_config * config) {
_start(config->thread);
skynet_socket_free();
if (config->daemon) {
daemon_exit(config->daemon);
}
}

View File

@@ -16,6 +16,9 @@
typedef void (*timer_execute_func)(void *ud,void *arg);
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
#define TIME_NEAR_SHIFT 8
#define TIME_NEAR (1 << TIME_NEAR_SHIFT)
#define TIME_LEVEL_SHIFT 6
@@ -50,8 +53,7 @@ struct timer {
static struct timer * TI = NULL;
static inline struct timer_node *
link_clear(struct link_list *list)
{
link_clear(struct link_list *list) {
struct timer_node * ret = list->head.next;
list->head.next = 0;
list->tail = &(list->head);
@@ -60,23 +62,20 @@ link_clear(struct link_list *list)
}
static inline void
link(struct link_list *list,struct timer_node *node)
{
link(struct link_list *list,struct timer_node *node) {
list->tail->next = node;
list->tail = node;
node->next=0;
}
static void
add_node(struct timer *T,struct timer_node *node)
{
add_node(struct timer *T,struct timer_node *node) {
int time=node->expire;
int current_time=T->time;
if ((time|TIME_NEAR_MASK)==(current_time|TIME_NEAR_MASK)) {
link(&T->near[time&TIME_NEAR_MASK],node);
}
else {
} else {
int i;
int mask=TIME_NEAR << TIME_LEVEL_SHIFT;
for (i=0;i<3;i++) {
@@ -90,21 +89,21 @@ add_node(struct timer *T,struct timer_node *node)
}
static void
timer_add(struct timer *T,void *arg,size_t sz,int time)
{
timer_add(struct timer *T,void *arg,size_t sz,int time) {
struct timer_node *node = (struct timer_node *)skynet_malloc(sizeof(*node)+sz);
memcpy(node+1,arg,sz);
while (__sync_lock_test_and_set(&T->lock,1)) {};
LOCK(T);
node->expire=time+T->time;
add_node(T,node);
__sync_lock_release(&T->lock);
UNLOCK(T);
}
static void
timer_shift(struct timer *T) {
LOCK(T);
int mask = TIME_NEAR;
int time = (++T->time) >> TIME_NEAR_SHIFT;
int i=0;
@@ -125,50 +124,57 @@ timer_shift(struct timer *T) {
time >>= TIME_LEVEL_SHIFT;
++i;
}
UNLOCK(T);
}
static inline void
dispatch_list(struct timer_node *current) {
do {
struct timer_event * event = (struct timer_event *)(current+1);
struct skynet_message message;
message.source = 0;
message.session = event->session;
message.data = NULL;
message.sz = PTYPE_RESPONSE << HANDLE_REMOTE_SHIFT;
skynet_context_push(event->handle, &message);
struct timer_node * temp = current;
current=current->next;
skynet_free(temp);
} while (current);
}
static inline void
timer_execute(struct timer *T) {
LOCK(T);
int idx = T->time & TIME_NEAR_MASK;
while (T->near[idx].head.next) {
struct timer_node *current = link_clear(&T->near[idx]);
do {
struct timer_event * event = (struct timer_event *)(current+1);
struct skynet_message message;
message.source = 0;
message.session = event->session;
message.data = NULL;
message.sz = PTYPE_RESPONSE << HANDLE_REMOTE_SHIFT;
skynet_context_push(event->handle, &message);
struct timer_node * temp = current;
current=current->next;
skynet_free(temp);
} while (current);
UNLOCK(T);
// dispatch_list don't need lock T
dispatch_list(current);
LOCK(T);
}
UNLOCK(T);
}
static void
timer_update(struct timer *T)
{
while (__sync_lock_test_and_set(&T->lock,1)) {};
timer_update(struct timer *T) {
// try to dispatch timeout 0 (rare condition)
timer_execute(T);
// shift time first, and then dispatch timer message
timer_shift(T);
timer_execute(T);
__sync_lock_release(&T->lock);
}
static struct timer *
timer_create_timer()
{
timer_create_timer() {
struct timer *r=(struct timer *)skynet_malloc(sizeof(struct timer));
memset(r,0,sizeof(*r));

View File

@@ -815,6 +815,22 @@ report_accept(struct socket_server *ss, struct socket *s, struct socket_message
return 1;
}
static inline void
clear_closed_event(struct socket_server *ss, struct socket_message * result, int type) {
if (type == SOCKET_CLOSE || type == SOCKET_ERROR) {
int id = result->id;
int i;
for (i=ss->event_index; i<ss->event_n; i++) {
struct event *e = &ss->ev[i];
struct socket *s = e->s;
if (s) {
if (s->type == SOCKET_TYPE_INVALID && s->id == id) {
e->s = NULL;
}
}
}
}
}
// return type
int
@@ -823,9 +839,10 @@ socket_server_poll(struct socket_server *ss, struct socket_message * result, int
if (ss->checkctrl) {
if (has_cmd(ss)) {
int type = ctrl_cmd(ss, result);
if (type != -1)
if (type != -1) {
clear_closed_event(ss, result, type);
return type;
else
} else
continue;
} else {
ss->checkctrl = 0;
@@ -865,12 +882,14 @@ socket_server_poll(struct socket_server *ss, struct socket_message * result, int
int type = send_buffer(ss, s, result);
if (type == -1)
break;
clear_closed_event(ss, result, type);
return type;
}
if (e->read) {
int type = forward_message(ss, s, result);
if (type == -1)
break;
clear_closed_event(ss, result, type);
return type;
}
break;

View File

@@ -1,12 +0,0 @@
local skynet = require "skynet"
local mqueue = require "mqueue"
skynet.start(function()
local id = 0
local pingserver = skynet.newservice "pingserver"
mqueue.register(function(str)
id = id + 1
str = string.format("id = %d , %s",id, str)
return skynet.call(pingserver, "lua", "PING", str)
end)
end)