Compare commits

..

64 Commits

Author SHA1 Message Date
Cloud Wu
1b53e6e28d Release alpha 10 2015-08-17 11:21:20 +08:00
云风
77bdfb2ceb Merge pull request #325 from cloudwu/pthreadlock
add pthread lock
2015-08-17 10:25:36 +08:00
Cloud Wu
2583af26d7 add cluster.register and cluster.query 2015-08-14 23:22:00 +08:00
Cloud Wu
a38a3140dd error when send to address 0 2015-08-14 17:32:59 +08:00
Cloud Wu
bf8f9b8654 add pthread lock 2015-08-13 21:00:20 +08:00
Cloud Wu
0ce9921c25 remove unused sz 2015-08-12 21:16:02 +08:00
Cloud Wu
adc39705f3 remove unused netpack c api 2015-08-12 20:56:29 +08:00
Cloud Wu
a4f827a48d use string for msgserver request 2015-08-12 14:53:36 +08:00
Cloud Wu
7547126570 bugfix: memory leak , See Issue #323 2015-08-12 12:03:52 +08:00
Cloud Wu
926b44ddf6 remove unused parm 2015-08-11 14:09:16 +08:00
Cloud Wu
d3771edc9d The cluster message never great than 64K now 2015-08-11 14:04:15 +08:00
Cloud Wu
947727e33a add new socket message WARNING 2015-08-11 13:21:24 +08:00
云风
27148981d5 Merge pull request #320 from cloudwu/multipart
Multipart
2015-08-11 11:17:22 +08:00
Cloud Wu
6fa436e8ff add core.intcommand , See Issue #321 2015-08-10 22:06:36 +08:00
Cloud Wu
2935ba3521 Release alpha9 2015-08-10 16:17:55 +08:00
云风
5c8ea6f09f Merge pull request #318 from felixdae/cloud
not work with telnet due to \r\n
2015-08-08 16:45:21 +08:00
felixdae
c16ae57639 not work with telnet due to \r\n 2015-08-07 18:52:50 +08:00
云风
1c7d44fd4d Merge pull request #316 from niuys/patch-2
'hotfix' code cannot use '_ENV'
2015-08-07 16:14:13 +08:00
云风
ca7e38137d Merge pull request #317 from chuenlungwang/multipart
Packing multipart req number first byte is 1
2015-08-07 16:07:25 +08:00
BITMAN
5936d3616c Packing multipart req number first byte is 1 2015-08-07 13:51:10 +08:00
snail
e9cfdba22a 'hotfix' code cannot use '_ENV'
If there's no global variable or function used in any interface of a snax service,the upvalue "_ENV" for 'hotfix' is not set. This modify is not  complete, it depend's on the 'collect_uv' method having upvalue '_ENV',maybe other good method to get upvalue index of '_ENV'.
2015-08-07 10:38:57 +08:00
Cloud Wu
3156661e0b bugfix: response function for socket channel 2015-08-06 20:00:48 +08:00
Cloud Wu
b4048a8eab bugfix: typo 2015-08-05 16:42:05 +08:00
Cloud Wu
aff73cbed7 Increase message size 16M(24bit) limit to 56bit on 64bit arch 2015-08-05 12:23:35 +08:00
Cloud Wu
b5244b96aa cluster rpc support large package 2015-08-04 17:56:17 +08:00
Cloud Wu
704b016f2c bugfix: inc session before get channel 2015-08-04 17:51:35 +08:00
Cloud Wu
3b48beb428 bson bugfix 2015-07-30 15:41:17 +08:00
Cloud Wu
4cbead28d5 skynet.dispatch can replace old func 2015-07-29 16:12:49 +08:00
Cloud Wu
b3f966bcaa bugfix: multicast chan gc 2015-07-29 16:10:38 +08:00
Cloud Wu
7b54e37d12 Merge branch 'master' of github.com:cloudwu/skynet 2015-07-24 17:58:06 +08:00
Cloud Wu
e87ac18b84 expand lua stack first 2015-07-24 17:50:42 +08:00
云风
05af87ce8e Merge pull request #311 from jintiao/patch-1
fix "make cleanall" on macosx
2015-07-24 17:45:41 +08:00
jintiao
0ee61de22c skip jemalloc clean if jemalloc's makefile was missing 2015-07-24 00:48:24 +08:00
Cloud Wu
1da8a6b38d lazy init debug command 2015-07-23 18:35:29 +08:00
Cloud Wu
b2d8237363 improve unregister protocol error report 2015-07-23 18:23:47 +08:00
Cloud Wu
39f9a96b6c add cmemory.info() returns a table of c memory info 2015-07-23 16:47:35 +08:00
Cloud Wu
588c4a3508 bugfix 2015-07-22 16:49:25 +08:00
Cloud Wu
d6734890e0 Merge branch 'master' of github.com:cloudwu/skynet 2015-07-22 15:53:19 +08:00
Cloud Wu
4ebb139c2b bugfix: free message when cluster not connected 2015-07-22 15:52:26 +08:00
云风
20476d2280 Merge pull request #308 from jsenter/patch-1
Update cdummy.lua
2015-07-21 15:20:56 +08:00
Cloud Wu
3131bca6ef Merge branch 'master' of github.com:cloudwu/skynet 2015-07-21 11:31:41 +08:00
Cloud Wu
3f91484791 user log service 2015-07-21 11:31:27 +08:00
LiBei
a0ecd51230 Update cdummy.lua
误定义全局变量
2015-07-21 11:12:55 +08:00
云风
dba1db9cc4 Merge pull request #304 from JiessieDawn/master
sharedata serialization bugfix
2015-07-13 14:13:48 +08:00
cxj
538414408d sharedata serialization bugfix 2015-07-13 13:04:09 +08:00
云风
4cf05fb2e7 Merge pull request #303 from JiessieDawn/master
sproto optimize
2015-07-11 20:36:39 +08:00
cxj
d9ad981c8c sproto optimize, malloc newchunk and return directly if sz >= CHUNK_SIZE in pool_alloc, do not replace current chunk if sz >= p->current_used in pool_alloc, more safety checking 2015-07-10 20:21:07 +08:00
云风
21c941fe63 Merge pull request #302 from sanikoyes/Pr-optimize-sproto-lunpack
Pr-optimize-sproto-unpack
2015-07-09 18:24:06 +08:00
sanikoyes
ea2437e138 lunpack optimize, do not unpack twice if r <= osz 2015-07-09 18:07:32 +08:00
Cloud Wu
86bbc9c701 off by 1 error 2015-07-07 12:11:16 +08:00
Cloud Wu
95e1d9f45f Merge branch 'master' of github.com:cloudwu/skynet 2015-07-03 10:58:53 +08:00
Cloud Wu
55cf9375fc asterisk(*) should be once or not at all 2015-07-03 10:58:40 +08:00
云风
654f732cd5 Merge pull request #300 from sanikoyes/Pr-fix-login-client
Pr-fix-login-client
2015-07-03 10:28:24 +08:00
sanikoyes
d4023c8b63 fix invalid fd after reconnected, used in unpack_f 2015-07-02 16:25:10 +08:00
云风
375f8606b4 Merge pull request #298 from JiessieDawn/master
support sharedata serialization
2015-07-02 15:04:49 +08:00
cxj
d17e6f59fe add sharedata lua serialization test 2015-07-02 15:02:11 +08:00
cxj
a77d36911d change wb_table to call wb_table_metapairs for keeping consistent style 2015-07-02 14:47:50 +08:00
cxj
4352dc4047 Merge branch 'master' of https://github.com/cloudwu/skynet 2015-07-02 13:56:55 +08:00
cxj
172356be19 fix lua-seric.c wb_table 2015-07-02 13:51:03 +08:00
Cloud Wu
08dabd51c8 fix issue #299 2015-07-02 12:17:18 +08:00
cxj
bd55a58515 support sharedata serialization 2015-07-01 16:54:20 +08:00
Cloud Wu
b646a1b8a3 fix login example 2015-07-01 12:51:20 +08:00
Cloud Wu
6b312fa09a update readme 2015-07-01 11:35:05 +08:00
Cloud Wu
dad66010cd sproto bugfix, see sproto issue 34 for detail 2015-06-30 15:05:49 +08:00
64 changed files with 1054 additions and 335 deletions

View File

@@ -135,6 +135,7 @@ static void freesharedproto (lua_State *L, SharedProto *f) {
luaM_freearray(L, f->lineinfo, f->sizelineinfo); luaM_freearray(L, f->lineinfo, f->sizelineinfo);
luaM_freearray(L, f->locvars, f->sizelocvars); luaM_freearray(L, f->locvars, f->sizelocvars);
luaM_freearray(L, f->upvalues, f->sizeupvalues); luaM_freearray(L, f->upvalues, f->sizeupvalues);
luaM_free(L, f);
} }
void luaF_freeproto (lua_State *L, Proto *f) { void luaF_freeproto (lua_State *L, Proto *f) {

View File

@@ -44,6 +44,8 @@ LUAMOD_API int (luaopen_debug) (lua_State *L);
#define LUA_LOADLIBNAME "package" #define LUA_LOADLIBNAME "package"
LUAMOD_API int (luaopen_package) (lua_State *L); LUAMOD_API int (luaopen_package) (lua_State *L);
#define LUA_CACHELIB
LUAMOD_API int (luaopen_cache) (lua_State *L);
/* open all previous libraries */ /* open all previous libraries */
LUALIB_API void (luaL_openlibs) (lua_State *L); LUALIB_API void (luaL_openlibs) (lua_State *L);

View File

@@ -1,3 +1,22 @@
v1.0.0-alpha10 (2015-8-17)
-----------
* Remove the size limit of cluster RPC message.
* Remove the size limit of local message.
* Add cluster.query and clsuter.register.
* Add an option of pthread mutex lock.
* Add skynet.core.intcommand to optimize skynet.sleep etc.
* Fix a memory leak bug in lua shared proto.
* snax.msgserver use string instead of lightuserdata/size.
* Remove some unused api in netpack.
* Raise error when skynet.send to 0.
v1.0.0-alpha9 (2015-8-10)
-----------
* Improve lua serialization , support pairs metamethod.
* Bugfix : sproto (See commits log of sproto)
* Add user log service support (In config)
* Other minor bugfix (See commits log)
v1.0.0-alpha8 (2015-6-29) v1.0.0-alpha8 (2015-6-29)
----------- -----------
* Update lua 5.3.1 * Update lua 5.3.1

View File

@@ -5,7 +5,8 @@ CSERVICE_PATH ?= cservice
SKYNET_BUILD_PATH ?= . SKYNET_BUILD_PATH ?= .
CFLAGS = -g -O2 -Wall -I$(LUA_INC) $(MYCFLAGS) CFLAGS = -g -O2 -Wall -I$(LUA_INC) $(MYCFLAGS)
# CFLAGS += -DUSE_PTHREAD_LOCK
# lua # lua
@@ -79,7 +80,7 @@ $(LUA_CLIB_PATH)/socketdriver.so : lualib-src/lua-socket.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -Iservice-src $(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -Iservice-src
$(LUA_CLIB_PATH)/bson.so : lualib-src/lua-bson.c | $(LUA_CLIB_PATH) $(LUA_CLIB_PATH)/bson.so : lualib-src/lua-bson.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src $(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@ -Iskynet-src
$(LUA_CLIB_PATH)/mongo.so : lualib-src/lua-mongo.c | $(LUA_CLIB_PATH) $(LUA_CLIB_PATH)/mongo.so : lualib-src/lua-mongo.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src $(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src
@@ -109,7 +110,7 @@ $(LUA_CLIB_PATH)/crypt.so : lualib-src/lua-crypt.c lualib-src/lsha1.c | $(LUA_CL
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ $(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(LUA_CLIB_PATH)/sharedata.so : lualib-src/lua-sharedata.c | $(LUA_CLIB_PATH) $(LUA_CLIB_PATH)/sharedata.so : lualib-src/lua-sharedata.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ $(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
$(LUA_CLIB_PATH)/stm.so : lualib-src/lua-stm.c | $(LUA_CLIB_PATH) $(LUA_CLIB_PATH)/stm.so : lualib-src/lua-stm.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@ $(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
@@ -124,13 +125,15 @@ $(LUA_CLIB_PATH)/mysqlaux.so : lualib-src/lua-mysqlaux.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ $(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(LUA_CLIB_PATH)/debugchannel.so : lualib-src/lua-debugchannel.c | $(LUA_CLIB_PATH) $(LUA_CLIB_PATH)/debugchannel.so : lualib-src/lua-debugchannel.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ $(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
clean : clean :
rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so
cleanall: clean cleanall: clean
ifneq (,$(wildcard 3rd/jemalloc/Makefile))
cd 3rd/jemalloc && $(MAKE) clean cd 3rd/jemalloc && $(MAKE) clean
endif
cd 3rd/lua && $(MAKE) clean cd 3rd/lua && $(MAKE) clean
rm -f $(LUA_STATICLIB) rm -f $(LUA_STATICLIB)

View File

@@ -28,7 +28,9 @@ Run these in different console
## About Lua ## About Lua
Skynet now use Lua 5.3.0 final, http://www.lua.org/ftp/lua-5.3.0.tar.gz Skynet now use a modify version of lua 5.3.1 (http://www.lua.org/ftp/lua-5.3.1.tar.gz) .
For detail : http://lua-users.org/lists/lua-l/2014-03/msg00489.html
You can also use the other official Lua version , edit the makefile by yourself . You can also use the other official Lua version , edit the makefile by yourself .

View File

@@ -1,15 +1,17 @@
local skynet = require "skynet" local skynet = require "skynet"
local cluster = require "cluster" local cluster = require "cluster"
require "skynet.manager" -- import skynet.name
local snax = require "snax" local snax = require "snax"
skynet.start(function() skynet.start(function()
local sdb = skynet.newservice("simpledb") local sdb = skynet.newservice("simpledb")
skynet.name(".simpledb", sdb) -- register name "sdb" for simpledb, you can use cluster.query() later.
print(skynet.call(".simpledb", "lua", "SET", "a", "foobar")) -- See cluster2.lua
print(skynet.call(".simpledb", "lua", "SET", "b", "foobar2")) cluster.register("sdb", sdb)
print(skynet.call(".simpledb", "lua", "GET", "a"))
print(skynet.call(".simpledb", "lua", "GET", "b")) print(skynet.call(sdb, "lua", "SET", "a", "foobar"))
print(skynet.call(sdb, "lua", "SET", "b", "foobar2"))
print(skynet.call(sdb, "lua", "GET", "a"))
print(skynet.call(sdb, "lua", "GET", "b"))
cluster.open "db" cluster.open "db"
cluster.open "db2" cluster.open "db2"
-- unique snax service -- unique snax service

View File

@@ -2,10 +2,18 @@ local skynet = require "skynet"
local cluster = require "cluster" local cluster = require "cluster"
skynet.start(function() skynet.start(function()
local proxy = cluster.proxy("db", ".simpledb") -- query name "sdb" of cluster db.
print(skynet.call(proxy, "lua", "GET", "a")) local sdb = cluster.query("db", "sdb")
print(cluster.call("db", ".simpledb", "GET", "a")) print("db.sbd=",sdb)
print(cluster.call("db2", ".simpledb", "GET", "b")) local proxy = cluster.proxy("db", sdb)
local largekey = string.rep("X", 128*1024)
local largevalue = string.rep("R", 100 * 1024)
print(skynet.call(proxy, "lua", "SET", largekey, largevalue))
local v = skynet.call(proxy, "lua", "GET", largekey)
assert(largevalue == v)
print(cluster.call("db", sdb, "GET", "a"))
print(cluster.call("db2", sdb, "GET", "b"))
-- test snax service -- test snax service
local pingserver = cluster.snax("db", "pingserver") local pingserver = cluster.snax("db", "pingserver")

15
examples/config.userlog Normal file
View File

@@ -0,0 +1,15 @@
root = "./"
thread = 8
logger = "userlog"
logservice = "snlua"
logpath = "."
harbor = 0
start = "main" -- main script
bootstrap = "snlua bootstrap" -- The service for bootstrap
luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."examples/?.lua"
lualoader = "lualib/loader.lua"
-- preload = "./examples/preload.lua" -- run preload.lua before every lua service run
snax = root.."examples/?.lua;"..root.."test/?.lua"
-- snax_interface_g = "snax_g"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"

View File

@@ -131,7 +131,7 @@ local text = "echo"
local index = 1 local index = 1
print("connect") print("connect")
local fd = assert(socket.connect("127.0.0.1", 8888)) fd = assert(socket.connect("127.0.0.1", 8888))
last = "" last = ""
local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index) local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index)
@@ -151,7 +151,7 @@ socket.close(fd)
index = index + 1 index = index + 1
print("connect again") print("connect again")
local fd = assert(socket.connect("127.0.0.1", 8888)) fd = assert(socket.connect("127.0.0.1", 8888))
last = "" last = ""
local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index) local handshake = string.format("%s@%s#%s:%d", crypt.base64encode(token.user), crypt.base64encode(token.server),crypt.base64encode(subid) , index)

View File

@@ -17,7 +17,8 @@ function server.login_handler(uid, secret)
end end
internal_id = internal_id + 1 internal_id = internal_id + 1
local username = msgserver.username(uid, internal_id, servername) local id = internal_id -- don't use internal_id directly
local username = msgserver.username(uid, id, servername)
-- you can use a pool to alloc new agent -- you can use a pool to alloc new agent
local agent = skynet.newservice "msgagent" local agent = skynet.newservice "msgagent"
@@ -25,11 +26,11 @@ function server.login_handler(uid, secret)
username = username, username = username,
agent = agent, agent = agent,
uid = uid, uid = uid,
subid = internal_id, subid = id,
} }
-- trash subid (no used) -- trash subid (no used)
skynet.call(agent, "lua", "login", uid, internal_id, secret) skynet.call(agent, "lua", "login", uid, id, secret)
users[uid] = u users[uid] = u
username_map[username] = u username_map[username] = u
@@ -37,7 +38,7 @@ function server.login_handler(uid, secret)
msgserver.login(username, secret) msgserver.login(username, secret)
-- you should return unique subid -- you should return unique subid
return internal_id return id
end end
-- call by agent -- call by agent
@@ -73,9 +74,9 @@ function server.disconnect_handler(username)
end end
-- call by self (when recv a request from client) -- call by self (when recv a request from client)
function server.request_handler(username, msg, sz) function server.request_handler(username, msg)
local u = username_map[username] local u = username_map[username]
return skynet.tostring(skynet.rawcall(u.agent, "client", msg, sz)) return skynet.tostring(skynet.rawcall(u.agent, "client", msg))
end end
-- call by self (when gate open) -- call by self (when gate open)

View File

@@ -37,6 +37,16 @@ skynet.start(function()
skynet.error(string.format("b[%d]=%s", k,v)) skynet.error(string.format("b[%d]=%s", k,v))
end end
-- test lua serialization
local s = skynet.packstring(obj)
local nobj = skynet.unpack(s)
for k,v in pairs(nobj) do
skynet.error(string.format("nobj[%s]=%s", k,v))
end
for k,v in ipairs(nobj.b) do
skynet.error(string.format("nobj.b[%d]=%s", k,v))
end
for i = 1, 5 do for i = 1, 5 do
skynet.sleep(100) skynet.sleep(100)
skynet.error("second " ..i) skynet.error("second " ..i)

15
examples/userlog.lua Normal file
View File

@@ -0,0 +1,15 @@
local skynet = require "skynet"
require "skynet.manager"
skynet.register_protocol {
name = "text",
id = skynet.PTYPE_TEXT,
unpack = skynet.tostring,
dispatch = function(_, address, msg)
print(string.format("%x(%.2f): %s", address, skynet.time(), msg))
end
}
skynet.start(function()
skynet.register ".logger"
end)

View File

@@ -32,6 +32,11 @@ function SOCKET.error(fd, msg)
close_agent(fd) close_agent(fd)
end end
function SOCKET.warning(fd, size)
-- size K bytes havn't send out in fd
print("socket warning", fd, size)
end
function SOCKET.data(fd, msg) function SOCKET.data(fd, msg)
end end

View File

@@ -8,6 +8,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include "atomic.h"
#define DEFAULT_CAP 64 #define DEFAULT_CAP 64
#define MAX_NUMBER 1024 #define MAX_NUMBER 1024
@@ -243,12 +244,16 @@ append_key(struct bson *bs, int type, const char *key, size_t sz) {
write_string(bs, key, sz); write_string(bs, key, sz);
} }
static inline int
is_32bit(int64_t v) {
return v >= INT32_MIN && v <= INT32_MAX;
}
static void static void
append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) { append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) {
if (lua_isinteger(L, -1)) { if (lua_isinteger(L, -1)) {
int64_t i = lua_tointeger(L, -1); int64_t i = lua_tointeger(L, -1);
int si = i >> 31; if (is_32bit(i)) {
if (si == 0 || si == -1) {
append_key(bs, BSON_INT32, key, sz); append_key(bs, BSON_INT32, key, sz);
write_int32(bs, i); write_int32(bs, i);
} else { } else {
@@ -1136,7 +1141,7 @@ lobjectid(lua_State *L) {
} else { } else {
time_t ti = time(NULL); time_t ti = time(NULL);
// old_counter is a static var, use atom inc. // old_counter is a static var, use atom inc.
uint32_t id = __sync_fetch_and_add(&oid_counter,1); uint32_t id = ATOM_FINC(&oid_counter);
oid[2] = (ti>>24) & 0xff; oid[2] = (ti>>24) & 0xff;
oid[3] = (ti>>16) & 0xff; oid[3] = (ti>>16) & 0xff;

View File

@@ -128,11 +128,8 @@ lusleep(lua_State *L) {
#define QUEUE_SIZE 1024 #define QUEUE_SIZE 1024
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
struct queue { struct queue {
int lock; pthread_mutex_t lock;
int head; int head;
int tail; int tail;
char * queue[QUEUE_SIZE]; char * queue[QUEUE_SIZE];
@@ -153,7 +150,7 @@ readline_stdin(void * arg) {
memcpy(str, tmp, n); memcpy(str, tmp, n);
str[n] = 0; str[n] = 0;
LOCK(q); pthread_mutex_lock(&q->lock);
q->queue[q->tail] = str; q->queue[q->tail] = str;
if (++q->tail >= QUEUE_SIZE) { if (++q->tail >= QUEUE_SIZE) {
@@ -163,7 +160,7 @@ readline_stdin(void * arg) {
// queue overflow // queue overflow
exit(1); exit(1);
} }
UNLOCK(q); pthread_mutex_unlock(&q->lock);
} }
return NULL; return NULL;
} }
@@ -171,16 +168,16 @@ readline_stdin(void * arg) {
static int static int
lreadstdin(lua_State *L) { lreadstdin(lua_State *L) {
struct queue *q = lua_touserdata(L, lua_upvalueindex(1)); struct queue *q = lua_touserdata(L, lua_upvalueindex(1));
LOCK(q); pthread_mutex_lock(&q->lock);
if (q->head == q->tail) { if (q->head == q->tail) {
UNLOCK(q); pthread_mutex_unlock(&q->lock);
return 0; return 0;
} }
char * str = q->queue[q->head]; char * str = q->queue[q->head];
if (++q->head >= QUEUE_SIZE) { if (++q->head >= QUEUE_SIZE) {
q->head = 0; q->head = 0;
} }
UNLOCK(q); pthread_mutex_unlock(&q->lock);
lua_pushstring(L, str); lua_pushstring(L, str);
free(str); free(str);
return 1; return 1;
@@ -201,6 +198,7 @@ luaopen_clientsocket(lua_State *L) {
struct queue * q = lua_newuserdata(L, sizeof(*q)); struct queue * q = lua_newuserdata(L, sizeof(*q));
memset(q, 0, sizeof(*q)); memset(q, 0, sizeof(*q));
pthread_mutex_init(&q->lock, NULL);
lua_pushcclosure(L, lreadstdin, 1); lua_pushcclosure(L, lreadstdin, 1);
lua_setfield(L, -2, "readstdin"); lua_setfield(L, -2, "readstdin");

View File

@@ -1,6 +1,7 @@
#include <lua.h> #include <lua.h>
#include <lauxlib.h> #include <lauxlib.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include "skynet.h" #include "skynet.h"
@@ -15,7 +16,8 @@
uint32_t next_session uint32_t next_session
*/ */
#define TEMP_LENGTH 0x10007 #define TEMP_LENGTH 0x8200
#define MULTI_PART 0x8000
static void static void
fill_uint32(uint8_t * buf, uint32_t n) { fill_uint32(uint8_t * buf, uint32_t n) {
@@ -26,30 +28,75 @@ fill_uint32(uint8_t * buf, uint32_t n) {
} }
static void static void
fill_header(lua_State *L, uint8_t *buf, int sz, void *msg) { fill_header(lua_State *L, uint8_t *buf, int sz) {
if (sz >= 0x10000) { assert(sz < 0x10000);
skynet_free(msg);
luaL_error(L, "request message is too long %d", sz);
}
buf[0] = (sz >> 8) & 0xff; buf[0] = (sz >> 8) & 0xff;
buf[1] = sz & 0xff; buf[1] = sz & 0xff;
} }
static void /*
packreq_number(lua_State *L, int session, void * msg, size_t sz) { The request package :
size <= 0x8000 (32K) and address is id
WORD sz+9
BYTE 0
DWORD addr
DWORD session
PADDING msg(sz)
size > 0x8000 and address is id
DWORD 13
BYTE 1 ; multireq
DWORD addr
DWORD session
DWORD sz
size <= 0x8000 (32K) and address is string
WORD sz+6+namelen
BYTE 0x80
BYTE namelen
STRING name
DWORD session
PADDING msg(sz)
size > 0x8000 and address is string
DWORD 10 + namelen
BYTE 0x81
BYTE namelen
STRING name
DWORD session
DWORD sz
multi req
WORD sz + 5
BYTE 2/3 ; 2:multipart, 3:multipart end
DWORD SESSION
PADDING msgpart(sz)
*/
static int
packreq_number(lua_State *L, int session, void * msg, uint32_t sz) {
uint32_t addr = (uint32_t)lua_tointeger(L,1); uint32_t addr = (uint32_t)lua_tointeger(L,1);
uint8_t buf[TEMP_LENGTH]; uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+9, msg); if (sz < MULTI_PART) {
buf[2] = 0; fill_header(L, buf, sz+9);
fill_uint32(buf+3, addr); buf[2] = 0;
fill_uint32(buf+7, (uint32_t)session); fill_uint32(buf+3, addr);
memcpy(buf+11,msg,sz); fill_uint32(buf+7, (uint32_t)session);
memcpy(buf+11,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+11); lua_pushlstring(L, (const char *)buf, sz+11);
return 0;
} else {
int part = (sz - 1) / MULTI_PART + 1;
fill_header(L, buf, 13);
buf[2] = 1;
fill_uint32(buf+3, addr);
fill_uint32(buf+7, (uint32_t)session);
fill_uint32(buf+11, sz);
lua_pushlstring(L, (const char *)buf, 15);
return part;
}
} }
static void static int
packreq_string(lua_State *L, int session, void * msg, size_t sz) { packreq_string(lua_State *L, int session, void * msg, uint32_t sz) {
size_t namelen = 0; size_t namelen = 0;
const char *name = lua_tolstring(L, 1, &namelen); const char *name = lua_tolstring(L, 1, &namelen);
if (name == NULL || namelen < 1 || namelen > 255) { if (name == NULL || namelen < 1 || namelen > 255) {
@@ -58,13 +105,53 @@ packreq_string(lua_State *L, int session, void * msg, size_t sz) {
} }
uint8_t buf[TEMP_LENGTH]; uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+5+namelen, msg); if (sz < MULTI_PART) {
buf[2] = (uint8_t)namelen; fill_header(L, buf, sz+6+namelen);
memcpy(buf+3, name, namelen); buf[2] = 0x80;
fill_uint32(buf+3+namelen, (uint32_t)session); buf[3] = (uint8_t)namelen;
memcpy(buf+7+namelen,msg,sz); memcpy(buf+4, name, namelen);
fill_uint32(buf+4+namelen, (uint32_t)session);
memcpy(buf+8+namelen,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+7+namelen); lua_pushlstring(L, (const char *)buf, sz+8+namelen);
return 0;
} else {
int part = (sz - 1) / MULTI_PART + 1;
fill_header(L, buf, 10+namelen);
buf[2] = 0x81;
buf[3] = (uint8_t)namelen;
memcpy(buf+4, name, namelen);
fill_uint32(buf+4+namelen, (uint32_t)session);
fill_uint32(buf+8+namelen, sz);
lua_pushlstring(L, (const char *)buf, 12+namelen);
return part;
}
}
static void
packreq_multi(lua_State *L, int session, void * msg, uint32_t sz) {
uint8_t buf[TEMP_LENGTH];
int part = (sz - 1) / MULTI_PART + 1;
int i;
char *ptr = msg;
for (i=0;i<part;i++) {
uint32_t s;
if (sz > MULTI_PART) {
s = MULTI_PART;
buf[2] = 2;
} else {
s = sz;
buf[2] = 3; // the last multi part
}
fill_header(L, buf, s+5);
fill_uint32(buf+3, (uint32_t)session);
memcpy(buf+7, ptr, s);
lua_pushlstring(L, (const char *)buf, s+7);
lua_rawseti(L, -2, i+1);
sz -= s;
ptr += s;
}
} }
static int static int
@@ -73,23 +160,33 @@ lpackrequest(lua_State *L) {
if (msg == NULL) { if (msg == NULL) {
return luaL_error(L, "Invalid request message"); return luaL_error(L, "Invalid request message");
} }
size_t sz = (size_t)luaL_checkinteger(L,4); uint32_t sz = (uint32_t)luaL_checkinteger(L,4);
int session = luaL_checkinteger(L,2); int session = luaL_checkinteger(L,2);
if (session <= 0) { if (session <= 0) {
skynet_free(msg);
return luaL_error(L, "Invalid request session %d", session); return luaL_error(L, "Invalid request session %d", session);
} }
int addr_type = lua_type(L,1); int addr_type = lua_type(L,1);
int multipak;
if (addr_type == LUA_TNUMBER) { if (addr_type == LUA_TNUMBER) {
packreq_number(L, session, msg, sz); multipak = packreq_number(L, session, msg, sz);
} else { } else {
packreq_string(L, session, msg, sz); multipak = packreq_string(L, session, msg, sz);
} }
int current_session = session;
if (++session < 0) { if (++session < 0) {
session = 1; session = 1;
} }
skynet_free(msg);
lua_pushinteger(L, session); lua_pushinteger(L, session);
return 2; if (multipak) {
lua_createtable(L, multipak, 0);
packreq_multi(L, current_session, msg, sz);
skynet_free(msg);
return 3;
} else {
skynet_free(msg);
return 2;
}
} }
/* /*
@@ -98,6 +195,7 @@ lpackrequest(lua_State *L) {
uint32_t or string addr uint32_t or string addr
int session int session
string msg string msg
boolean padding
*/ */
static inline uint32_t static inline uint32_t
@@ -106,44 +204,122 @@ unpack_uint32(const uint8_t * buf) {
} }
static int static int
unpackreq_number(lua_State *L, const uint8_t * buf, size_t sz) { unpackreq_number(lua_State *L, const uint8_t * buf, int sz) {
if (sz < 9) { if (sz < 9) {
return luaL_error(L, "Invalid cluster message"); return luaL_error(L, "Invalid cluster message (size=%d)", sz);
} }
uint32_t address = unpack_uint32(buf+1); uint32_t address = unpack_uint32(buf+1);
uint32_t session = unpack_uint32(buf+5); uint32_t session = unpack_uint32(buf+5);
lua_pushinteger(L, (uint32_t)address); lua_pushinteger(L, address);
lua_pushinteger(L, (uint32_t)session); lua_pushinteger(L, session);
lua_pushlstring(L, (const char *)buf+9, sz-9); lua_pushlstring(L, (const char *)buf+9, sz-9);
return 3; return 3;
} }
static int static int
unpackreq_string(lua_State *L, const uint8_t * buf, size_t sz) { unpackmreq_number(lua_State *L, const uint8_t * buf, int sz) {
size_t namesz = buf[0]; if (sz != 13) {
if (sz < namesz + 5) { return luaL_error(L, "Invalid cluster message size %d (multi req must be 13)", sz);
return luaL_error(L, "Invalid cluster message");
} }
lua_pushlstring(L, (const char *)buf+1, namesz); uint32_t address = unpack_uint32(buf+1);
uint32_t session = unpack_uint32(buf + namesz + 1); uint32_t session = unpack_uint32(buf+5);
uint32_t size = unpack_uint32(buf+9);
lua_pushinteger(L, address);
lua_pushinteger(L, session);
lua_pushinteger(L, size);
lua_pushboolean(L, 1); // padding multi part
return 4;
}
static int
unpackmreq_part(lua_State *L, const uint8_t * buf, int sz) {
if (sz < 5) {
return luaL_error(L, "Invalid cluster multi part message");
}
int padding = (buf[0] == 2);
uint32_t session = unpack_uint32(buf+1);
lua_pushboolean(L, 0); // no address
lua_pushinteger(L, session);
lua_pushlstring(L, (const char *)buf+5, sz-5);
lua_pushboolean(L, padding);
return 4;
}
static int
unpackreq_string(lua_State *L, const uint8_t * buf, int sz) {
if (sz < 2) {
return luaL_error(L, "Invalid cluster message (size=%d)", sz);
}
size_t namesz = buf[1];
if (sz < namesz + 6) {
return luaL_error(L, "Invalid cluster message (size=%d)", sz);
}
lua_pushlstring(L, (const char *)buf+2, namesz);
uint32_t session = unpack_uint32(buf + namesz + 2);
lua_pushinteger(L, (uint32_t)session); lua_pushinteger(L, (uint32_t)session);
lua_pushlstring(L, (const char *)buf+1+namesz+4, sz - namesz - 5); lua_pushlstring(L, (const char *)buf+2+namesz+4, sz - namesz - 6);
return 3; return 3;
} }
static int
unpackmreq_string(lua_State *L, const uint8_t * buf, int sz) {
if (sz < 2) {
return luaL_error(L, "Invalid cluster message (size=%d)", sz);
}
size_t namesz = buf[1];
if (sz < namesz + 10) {
return luaL_error(L, "Invalid cluster message (size=%d)", sz);
}
lua_pushlstring(L, (const char *)buf+2, namesz);
uint32_t session = unpack_uint32(buf + namesz + 2);
uint32_t size = unpack_uint32(buf + namesz + 6);
lua_pushinteger(L, session);
lua_pushinteger(L, size);
lua_pushboolean(L, 1); // padding multipart
return 4;
}
static int static int
lunpackrequest(lua_State *L) { lunpackrequest(lua_State *L) {
size_t sz; size_t ssz;
const char *msg = luaL_checklstring(L,1,&sz); const char *msg = luaL_checklstring(L,1,&ssz);
if (msg[0] == 0) { int sz = (int)ssz;
switch (msg[0]) {
case 0:
return unpackreq_number(L, (const uint8_t *)msg, sz); return unpackreq_number(L, (const uint8_t *)msg, sz);
} else { case 1:
return unpackmreq_number(L, (const uint8_t *)msg, sz);
case 2:
case 3:
return unpackmreq_part(L, (const uint8_t *)msg, sz);
case '\x80':
return unpackreq_string(L, (const uint8_t *)msg, sz); return unpackreq_string(L, (const uint8_t *)msg, sz);
case '\x81':
return unpackmreq_string(L, (const uint8_t *)msg, sz);
default:
return luaL_error(L, "Invalid req package type %d", msg[0]);
} }
} }
/*
DWORD session
BYTE type
0: error
1: ok
2: multi begin
3: multi part
4: multi end
PADDING msg
type = 0, error msg
type = 1, msg
type = 2, DWORD size
type = 3/4, msg
*/
/* /*
int session int session
boolean ok boolean ok
@@ -162,16 +338,56 @@ lpackresponse(lua_State *L) {
if (lua_type(L,3) == LUA_TSTRING) { if (lua_type(L,3) == LUA_TSTRING) {
msg = (void *)lua_tolstring(L, 3, &sz); msg = (void *)lua_tolstring(L, 3, &sz);
if (sz > 0x1000) {
sz = 0x1000;
}
} else { } else {
msg = lua_touserdata(L,3); msg = lua_touserdata(L,3);
sz = (size_t)luaL_checkinteger(L, 4); sz = (size_t)luaL_checkinteger(L, 4);
} }
if (!ok) {
if (sz > MULTI_PART) {
// truncate the error msg if too long
sz = MULTI_PART;
}
} else {
if (sz > MULTI_PART) {
// return
int part = (sz - 1) / MULTI_PART + 1;
lua_createtable(L, part+1, 0);
uint8_t buf[TEMP_LENGTH];
// multi part begin
fill_header(L, buf, 9);
fill_uint32(buf+2, session);
buf[6] = 2;
fill_uint32(buf+7, (uint32_t)sz);
lua_pushlstring(L, (const char *)buf, 11);
lua_rawseti(L, -2, 1);
char * ptr = msg;
int i;
for (i=0;i<part;i++) {
int s;
if (sz > MULTI_PART) {
s = MULTI_PART;
buf[6] = 3;
} else {
s = sz;
buf[6] = 4;
}
fill_header(L, buf, s+5);
fill_uint32(buf+2, session);
memcpy(buf+7,ptr,s);
lua_pushlstring(L, (const char *)buf, s+7);
lua_rawseti(L, -2, i+2);
sz -= s;
ptr += s;
}
return 1;
}
}
uint8_t buf[TEMP_LENGTH]; uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+5, msg); fill_header(L, buf, sz+5);
fill_uint32(buf+2, session); fill_uint32(buf+2, session);
buf[6] = ok; buf[6] = ok;
memcpy(buf+7,msg,sz); memcpy(buf+7,msg,sz);
@@ -186,6 +402,7 @@ lpackresponse(lua_State *L) {
return integer session return integer session
boolean ok boolean ok
string msg string msg
boolean padding
*/ */
static int static int
lunpackresponse(lua_State *L) { lunpackresponse(lua_State *L) {
@@ -196,10 +413,66 @@ lunpackresponse(lua_State *L) {
} }
uint32_t session = unpack_uint32((const uint8_t *)buf); uint32_t session = unpack_uint32((const uint8_t *)buf);
lua_pushinteger(L, (lua_Integer)session); lua_pushinteger(L, (lua_Integer)session);
lua_pushboolean(L, buf[4]); switch(buf[4]) {
lua_pushlstring(L, buf+5, sz-5); case 0: // error
lua_pushboolean(L, 0);
lua_pushlstring(L, buf+5, sz-5);
return 3;
case 1: // ok
case 4: // multi end
lua_pushboolean(L, 1);
lua_pushlstring(L, buf+5, sz-5);
return 3;
case 2: // multi begin
if (sz != 9) {
return 0;
}
sz = unpack_uint32((const uint8_t *)buf+5);
lua_pushboolean(L, 1);
lua_pushinteger(L, sz);
lua_pushboolean(L, 1);
return 4;
case 3: // multi part
lua_pushboolean(L, 1);
lua_pushlstring(L, buf+5, sz-5);
lua_pushboolean(L, 1);
return 4;
default:
return 0;
}
}
return 3; static int
lconcat(lua_State *L) {
if (!lua_istable(L,1))
return 0;
if (lua_geti(L,1,1) != LUA_TNUMBER)
return 0;
int sz = lua_tointeger(L,-1);
lua_pop(L,1);
char * buff = skynet_malloc(sz);
int idx = 2;
int offset = 0;
while(lua_geti(L,1,idx) == LUA_TSTRING) {
size_t s;
const char * str = lua_tolstring(L, -1, &s);
if (s+offset > sz) {
skynet_free(buff);
return 0;
}
memcpy(buff+offset, str, s);
lua_pop(L,1);
offset += s;
++idx;
}
if (offset != sz) {
skynet_free(buff);
return 0;
}
// buff/sz will send to other service, See clusterd.lua
lua_pushlightuserdata(L, buff);
lua_pushinteger(L, sz);
return 2;
} }
int int
@@ -209,6 +482,7 @@ luaopen_cluster_core(lua_State *L) {
{ "unpackrequest", lunpackrequest }, { "unpackrequest", lunpackrequest },
{ "packresponse", lpackresponse }, { "packresponse", lpackresponse },
{ "unpackresponse", lunpackresponse }, { "unpackresponse", lunpackresponse },
{ "concat", lconcat },
{ NULL, NULL }, { NULL, NULL },
}; };
luaL_checkversion(L); luaL_checkversion(L);

View File

@@ -4,10 +4,9 @@
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "spinlock.h"
#define METANAME "debugchannel" #define METANAME "debugchannel"
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
struct command { struct command {
struct command * next; struct command * next;
@@ -15,7 +14,7 @@ struct command {
}; };
struct channel { struct channel {
int lock; struct spinlock lock;
int ref; int ref;
struct command * head; struct command * head;
struct command * tail; struct command * tail;
@@ -26,6 +25,7 @@ channel_new() {
struct channel * c = malloc(sizeof(*c)); struct channel * c = malloc(sizeof(*c));
memset(c, 0 , sizeof(*c)); memset(c, 0 , sizeof(*c));
c->ref = 1; c->ref = 1;
SPIN_INIT(c)
return c; return c;
} }
@@ -33,21 +33,21 @@ channel_new() {
static struct channel * static struct channel *
channel_connect(struct channel *c) { channel_connect(struct channel *c) {
struct channel * ret = NULL; struct channel * ret = NULL;
LOCK(c) SPIN_LOCK(c)
if (c->ref == 1) { if (c->ref == 1) {
++c->ref; ++c->ref;
ret = c; ret = c;
} }
UNLOCK(c) SPIN_UNLOCK(c)
return ret; return ret;
} }
static struct channel * static struct channel *
channel_release(struct channel *c) { channel_release(struct channel *c) {
LOCK(c) SPIN_LOCK(c)
--c->ref; --c->ref;
if (c->ref > 0) { if (c->ref > 0) {
UNLOCK(c) SPIN_UNLOCK(c)
return c; return c;
} }
// never unlock while reference is 0 // never unlock while reference is 0
@@ -59,6 +59,8 @@ channel_release(struct channel *c) {
free(p); free(p);
p = next; p = next;
} }
SPIN_UNLOCK(c)
SPIN_DESTROY(c)
free(c); free(c);
return NULL; return NULL;
} }
@@ -67,9 +69,9 @@ channel_release(struct channel *c) {
static struct command * static struct command *
channel_read(struct channel *c, double timeout) { channel_read(struct channel *c, double timeout) {
struct command * ret = NULL; struct command * ret = NULL;
LOCK(c) SPIN_LOCK(c)
if (c->head == NULL) { if (c->head == NULL) {
UNLOCK(c) SPIN_UNLOCK(c)
int ti = (int)(timeout * 100000); int ti = (int)(timeout * 100000);
usleep(ti); usleep(ti);
return NULL; return NULL;
@@ -79,7 +81,7 @@ channel_read(struct channel *c, double timeout) {
if (c->head == NULL) { if (c->head == NULL) {
c->tail = NULL; c->tail = NULL;
} }
UNLOCK(c) SPIN_UNLOCK(c)
return ret; return ret;
} }
@@ -90,14 +92,14 @@ channel_write(struct channel *c, const char * s, size_t sz) {
cmd->sz = sz; cmd->sz = sz;
cmd->next = NULL; cmd->next = NULL;
memcpy(cmd+1, s, sz); memcpy(cmd+1, s, sz);
LOCK(c) SPIN_LOCK(c)
if (c->tail == NULL) { if (c->tail == NULL) {
c->head = c->tail = cmd; c->head = c->tail = cmd;
} else { } else {
c->tail->next = cmd; c->tail->next = cmd;
c->tail = cmd; c->tail = cmd;
} }
UNLOCK(c) SPIN_UNLOCK(c)
} }
struct channel_box { struct channel_box {

View File

@@ -42,6 +42,7 @@ luaopen_memory(lua_State *L) {
{ "block", lblock }, { "block", lblock },
{ "dumpinfo", ldumpinfo }, { "dumpinfo", ldumpinfo },
{ "dump", ldump }, { "dump", ldump },
{ "info", dump_mem_lua },
{ NULL, NULL }, { NULL, NULL },
}; };

View File

@@ -5,6 +5,8 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "atomic.h"
struct mc_package { struct mc_package {
int reference; int reference;
uint32_t size; uint32_t size;
@@ -116,7 +118,7 @@ static int
mc_closelocal(lua_State *L) { mc_closelocal(lua_State *L) {
struct mc_package *pack = lua_touserdata(L,1); struct mc_package *pack = lua_touserdata(L,1);
int ref = __sync_sub_and_fetch(&pack->reference, 1); int ref = ATOM_DEC(&pack->reference);
if (ref <= 0) { if (ref <= 0) {
skynet_free(pack->data); skynet_free(pack->data);
skynet_free(pack); skynet_free(pack);

View File

@@ -19,6 +19,7 @@
#define TYPE_ERROR 3 #define TYPE_ERROR 3
#define TYPE_OPEN 4 #define TYPE_OPEN 4
#define TYPE_CLOSE 5 #define TYPE_CLOSE 5
#define TYPE_WARNING 6
/* /*
Each package is uint16 + data , uint16 (serialized in big-endian) is the number of bytes comprising the data . Each package is uint16 + data , uint16 (serialized in big-endian) is the number of bytes comprising the data .
@@ -371,6 +372,11 @@ lfilter(lua_State *L) {
lua_pushinteger(L, message->id); lua_pushinteger(L, message->id);
pushstring(L, buffer, size); pushstring(L, buffer, size);
return 4; return 4;
case SKYNET_SOCKET_TYPE_WARNING:
lua_pushvalue(L, lua_upvalueindex(TYPE_WARNING));
lua_pushinteger(L, message->id);
lua_pushinteger(L, message->ud);
return 4;
default: default:
// never get here // never get here
return 1; return 1;
@@ -442,57 +448,6 @@ lpack(lua_State *L) {
return 2; return 2;
} }
static int
lpack_string(lua_State *L) {
uint8_t tmp[SMALLSTRING+2];
size_t len;
uint8_t *buffer;
const char * ptr = tolstring(L, &len, 1);
if (len > 0x10000) {
return luaL_error(L, "Invalid size (too long) of data : %d", (int)len);
}
if (len <= SMALLSTRING) {
buffer = tmp;
} else {
buffer = lua_newuserdata(L, len + 2);
}
write_size(buffer, len);
memcpy(buffer+2, ptr, len);
lua_pushlstring(L, (const char *)buffer, len+2);
return 1;
}
static int
lpack_padding(lua_State *L) {
uint8_t tmp[SMALLSTRING+2];
size_t content_sz;
uint8_t *buffer;
const char * ptr = tolstring(L, &content_sz, 2);
size_t cookie_sz = 0;
const char * cookie = luaL_checklstring(L,1,&cookie_sz);
size_t len = cookie_sz + content_sz;
if (len > 0x10000) {
return luaL_error(L, "Invalid size (too long) of data : %d", (int)len);
}
if (len <= SMALLSTRING) {
buffer = tmp;
} else {
buffer = lua_newuserdata(L, len + 2);
}
write_size(buffer, len);
memcpy(buffer+2, ptr, content_sz);
memcpy(buffer+2+content_sz, cookie, cookie_sz);
lua_pushlstring(L, (const char *)buffer, len+2);
return 1;
}
static int static int
ltostring(lua_State *L) { ltostring(lua_State *L) {
void * ptr = lua_touserdata(L, 1); void * ptr = lua_touserdata(L, 1);
@@ -500,19 +455,8 @@ ltostring(lua_State *L) {
if (ptr == NULL) { if (ptr == NULL) {
lua_pushliteral(L, ""); lua_pushliteral(L, "");
} else { } else {
if (lua_isnumber(L, 3)) { lua_pushlstring(L, (const char *)ptr, size);
int offset = lua_tointeger(L, 3); skynet_free(ptr);
if (offset < 0) {
return luaL_error(L, "Invalid offset %d", offset);
}
if (offset > size) {
offset = size;
}
lua_pushlstring(L, (const char *)ptr + offset, size-offset);
} else {
lua_pushlstring(L, (const char *)ptr, size);
skynet_free(ptr);
}
} }
return 1; return 1;
} }
@@ -523,8 +467,6 @@ luaopen_netpack(lua_State *L) {
luaL_Reg l[] = { luaL_Reg l[] = {
{ "pop", lpop }, { "pop", lpop },
{ "pack", lpack }, { "pack", lpack },
{ "pack_string", lpack_string },
{ "pack_padding", lpack_padding },
{ "clear", lclear }, { "clear", lclear },
{ "tostring", ltostring }, { "tostring", ltostring },
{ NULL, NULL }, { NULL, NULL },
@@ -537,8 +479,9 @@ luaopen_netpack(lua_State *L) {
lua_pushliteral(L, "error"); lua_pushliteral(L, "error");
lua_pushliteral(L, "open"); lua_pushliteral(L, "open");
lua_pushliteral(L, "close"); lua_pushliteral(L, "close");
lua_pushliteral(L, "warning");
lua_pushcclosure(L, lfilter, 5); lua_pushcclosure(L, lfilter, 6);
lua_setfield(L, -2, "filter"); lua_setfield(L, -2, "filter");
return 1; return 1;

View File

@@ -254,14 +254,41 @@ wb_table_hash(lua_State *L, struct write_block * wb, int index, int depth, int a
wb_nil(wb); wb_nil(wb);
} }
static void
wb_table_metapairs(lua_State *L, struct write_block *wb, int index, int depth) {
uint8_t n = COMBINE_TYPE(TYPE_TABLE, 0);
wb_push(wb, &n, 1);
lua_pushvalue(L, index);
lua_call(L, 1, 3);
for(;;) {
lua_pushvalue(L, -2);
lua_pushvalue(L, -2);
lua_copy(L, -5, -3);
lua_call(L, 2, 2);
int type = lua_type(L, -2);
if (type == LUA_TNIL) {
lua_pop(L, 4);
break;
}
pack_one(L, wb, -2, depth);
pack_one(L, wb, -1, depth);
lua_pop(L, 1);
}
wb_nil(wb);
}
static void static void
wb_table(lua_State *L, struct write_block *wb, int index, int depth) { wb_table(lua_State *L, struct write_block *wb, int index, int depth) {
luaL_checkstack(L, LUA_MINSTACK, NULL); luaL_checkstack(L, LUA_MINSTACK, NULL);
if (index < 0) { if (index < 0) {
index = lua_gettop(L) + index + 1; index = lua_gettop(L) + index + 1;
} }
int array_size = wb_table_array(L, wb, index, depth); if (luaL_getmetafield(L, index, "__pairs") != LUA_TNIL) {
wb_table_hash(L, wb, index, depth, array_size); wb_table_metapairs(L, wb, index, depth);
} else {
int array_size = wb_table_array(L, wb, index, depth);
wb_table_hash(L, wb, index, depth, array_size);
}
} }
static void static void

View File

@@ -4,6 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include "atomic.h"
#define KEYTYPE_INTEGER 0 #define KEYTYPE_INTEGER 0
#define KEYTYPE_STRING 1 #define KEYTYPE_STRING 1
@@ -376,6 +377,7 @@ pconv(lua_State *L) {
static void static void
convert_stringmap(struct context *ctx, struct table *tbl) { convert_stringmap(struct context *ctx, struct table *tbl) {
lua_State *L = ctx->L; lua_State *L = ctx->L;
lua_checkstack(L, ctx->string_index + LUA_MINSTACK);
lua_settop(L, ctx->string_index + 1); lua_settop(L, ctx->string_index + 1);
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
struct state * s = lua_newuserdata(L, sizeof(*s)); struct state * s = lua_newuserdata(L, sizeof(*s));
@@ -662,7 +664,7 @@ releaseobj(lua_State *L) {
struct ctrl *c = lua_touserdata(L, 1); struct ctrl *c = lua_touserdata(L, 1);
struct table *tbl = c->root; struct table *tbl = c->root;
struct state *s = lua_touserdata(tbl->L, 1); struct state *s = lua_touserdata(tbl->L, 1);
__sync_fetch_and_sub(&s->ref, 1); ATOM_DEC(&s->ref);
c->root = NULL; c->root = NULL;
c->update = NULL; c->update = NULL;
@@ -673,7 +675,7 @@ static int
lboxconf(lua_State *L) { lboxconf(lua_State *L) {
struct table * tbl = get_table(L,1); struct table * tbl = get_table(L,1);
struct state * s = lua_touserdata(tbl->L, 1); struct state * s = lua_touserdata(tbl->L, 1);
__sync_fetch_and_add(&s->ref, 1); ATOM_INC(&s->ref);
struct ctrl * c = lua_newuserdata(L, sizeof(*c)); struct ctrl * c = lua_newuserdata(L, sizeof(*c));
c->root = tbl; c->root = tbl;
@@ -718,7 +720,7 @@ static int
lincref(lua_State *L) { lincref(lua_State *L) {
struct table *tbl = get_table(L,1); struct table *tbl = get_table(L,1);
struct state * s = lua_touserdata(tbl->L, 1); struct state * s = lua_touserdata(tbl->L, 1);
int ref = __sync_add_and_fetch(&s->ref, 1); int ref = ATOM_INC(&s->ref);
lua_pushinteger(L , ref); lua_pushinteger(L , ref);
return 1; return 1;
@@ -728,7 +730,7 @@ static int
ldecref(lua_State *L) { ldecref(lua_State *L) {
struct table *tbl = get_table(L,1); struct table *tbl = get_table(L,1);
struct state * s = lua_touserdata(tbl->L, 1); struct state * s = lua_touserdata(tbl->L, 1);
int ref = __sync_sub_and_fetch(&s->ref, 1); int ref = ATOM_DEC(&s->ref);
lua_pushinteger(L , ref); lua_pushinteger(L , ref);
return 1; return 1;

View File

@@ -118,6 +118,28 @@ _command(lua_State *L) {
return 0; return 0;
} }
static int
_intcommand(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
const char * cmd = luaL_checkstring(L,1);
const char * result;
const char * parm = NULL;
char tmp[64]; // for integer parm
if (lua_gettop(L) == 2) {
int32_t n = (int32_t)luaL_checkinteger(L,2);
sprintf(tmp, "%d", n);
parm = tmp;
}
result = skynet_command(context, cmd, parm);
if (result) {
lua_Integer r = strtoll(result, NULL, 0);
lua_pushinteger(L, r);
return 1;
}
return 0;
}
static int static int
_genid(lua_State *L) { _genid(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1)); struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
@@ -150,6 +172,9 @@ _send(lua_State *L) {
uint32_t dest = (uint32_t)lua_tointeger(L, 1); uint32_t dest = (uint32_t)lua_tointeger(L, 1);
const char * dest_string = NULL; const char * dest_string = NULL;
if (dest == 0) { if (dest == 0) {
if (lua_type(L,1) == LUA_TNUMBER) {
return luaL_error(L, "Invalid service address 0");
}
dest_string = get_dest_string(L, 1); dest_string = get_dest_string(L, 1);
} }
@@ -310,6 +335,7 @@ luaopen_skynet_core(lua_State *L) {
{ "genid", _genid }, { "genid", _genid },
{ "redirect", _redirect }, { "redirect", _redirect },
{ "command" , _command }, { "command" , _command },
{ "intcommand", _intcommand },
{ "error", _error }, { "error", _error },
{ "tostring", _tostring }, { "tostring", _tostring },
{ "harbor", _harbor }, { "harbor", _harbor },

View File

@@ -7,6 +7,7 @@
#include "rwlock.h" #include "rwlock.h"
#include "skynet_malloc.h" #include "skynet_malloc.h"
#include "atomic.h"
struct stm_object { struct stm_object {
struct rwlock lock; struct rwlock lock;
@@ -45,7 +46,7 @@ static void
stm_releasecopy(struct stm_copy *copy) { stm_releasecopy(struct stm_copy *copy) {
if (copy == NULL) if (copy == NULL)
return; return;
if (__sync_sub_and_fetch(&copy->reference, 1) == 0) { if (ATOM_DEC(&copy->reference) == 0) {
skynet_free(copy->msg); skynet_free(copy->msg);
skynet_free(copy); skynet_free(copy);
} }
@@ -70,7 +71,7 @@ stm_release(struct stm_object *obj) {
static void static void
stm_releasereader(struct stm_object *obj) { stm_releasereader(struct stm_object *obj) {
rwlock_rlock(&obj->lock); rwlock_rlock(&obj->lock);
if (__sync_sub_and_fetch(&obj->reference,1) == 0) { if (ATOM_DEC(&obj->reference) == 0) {
// last reader, no writer. so no need to unlock // last reader, no writer. so no need to unlock
assert(obj->copy == NULL); assert(obj->copy == NULL);
skynet_free(obj); skynet_free(obj);
@@ -82,7 +83,7 @@ stm_releasereader(struct stm_object *obj) {
static void static void
stm_grab(struct stm_object *obj) { stm_grab(struct stm_object *obj) {
rwlock_rlock(&obj->lock); rwlock_rlock(&obj->lock);
int ref = __sync_fetch_and_add(&obj->reference,1); int ref = ATOM_FINC(&obj->reference);
rwlock_runlock(&obj->lock); rwlock_runlock(&obj->lock);
assert(ref > 0); assert(ref > 0);
} }
@@ -92,7 +93,7 @@ stm_copy(struct stm_object *obj) {
rwlock_rlock(&obj->lock); rwlock_rlock(&obj->lock);
struct stm_copy * ret = obj->copy; struct stm_copy * ret = obj->copy;
if (ret) { if (ret) {
int ref = __sync_fetch_and_add(&ret->reference,1); int ref = ATOM_FINC(&ret->reference);
assert(ref > 0); assert(ref > 0);
} }
rwlock_runlock(&obj->lock); rwlock_runlock(&obj->lock);

View File

@@ -487,10 +487,10 @@ lunpack(lua_State *L) {
return luaL_error(L, "Invalid unpack stream"); return luaL_error(L, "Invalid unpack stream");
if (r > osz) { if (r > osz) {
output = expand_buffer(L, osz, r); output = expand_buffer(L, osz, r);
r = sproto_unpack(buffer, sz, output, r);
if (r < 0)
return luaL_error(L, "Invalid unpack stream");
} }
r = sproto_unpack(buffer, sz, output, r);
if (r < 0)
return luaL_error(L, "Invalid unpack stream");
lua_pushlstring(L, output, r); lua_pushlstring(L, output, r);
return 1; return 1;
} }

View File

@@ -83,7 +83,7 @@ static void *
pool_alloc(struct pool *p, size_t sz) { pool_alloc(struct pool *p, size_t sz) {
// align by 8 // align by 8
sz = (sz + 7) & ~7; sz = (sz + 7) & ~7;
if (sz > CHUNK_SIZE) { if (sz >= CHUNK_SIZE) {
return pool_newchunk(p, sz); return pool_newchunk(p, sz);
} }
if (p->current == NULL) { if (p->current == NULL) {
@@ -97,7 +97,7 @@ pool_alloc(struct pool *p, size_t sz) {
return ret; return ret;
} }
if (sz > p->current_used) { if (sz >= p->current_used) {
return pool_newchunk(p, sz); return pool_newchunk(p, sz);
} else { } else {
void * ret = pool_newchunk(p, CHUNK_SIZE); void * ret = pool_newchunk(p, CHUNK_SIZE);
@@ -152,7 +152,7 @@ struct_field(const uint8_t * stream, size_t sz) {
sz -= header; sz -= header;
stream += header; stream += header;
for (i=0;i<fn;i++) { for (i=0;i<fn;i++) {
int value= toword(field + i * SIZEOF_FIELD + SIZEOF_HEADER); int value= toword(field + i * SIZEOF_FIELD);
uint32_t dsz; uint32_t dsz;
if (value != 0) if (value != 0)
continue; continue;
@@ -305,7 +305,7 @@ import_type(struct sproto *s, struct sproto_type *t, const uint8_t * stream) {
if (stream == NULL) if (stream == NULL)
return NULL; return NULL;
tag = f->tag; tag = f->tag;
if (tag < last) if (tag <= last)
return NULL; // tag must in ascending order return NULL; // tag must in ascending order
if (tag > last+1) { if (tag > last+1) {
++maxn; ++maxn;
@@ -394,7 +394,7 @@ create_from_bundle(struct sproto *s, const uint8_t * stream, size_t sz) {
const uint8_t * protocoldata = NULL; const uint8_t * protocoldata = NULL;
int fn = struct_field(stream, sz); int fn = struct_field(stream, sz);
int i; int i;
if (fn < 0) if (fn < 0 || fn > 2)
return NULL; return NULL;
stream += SIZEOF_HEADER; stream += SIZEOF_HEADER;

View File

@@ -33,6 +33,16 @@ function cluster.snax(node, name, address)
return snax.bind(handle, name) return snax.bind(handle, name)
end end
function cluster.register(name, addr)
assert(type(name) == "string")
assert(addr == nil or type(addr) == "number")
return skynet.call(clusterd, "lua", "register", name, addr)
end
function cluster.query(node, name)
return skynet.call(clusterd, "lua", "req", node, 0, skynet.pack(name))
end
skynet.init(function() skynet.init(function()
clusterd = skynet.uniqueservice("clusterd") clusterd = skynet.uniqueservice("clusterd")
end) end)

View File

@@ -8,7 +8,9 @@ local dispatch = setmetatable({} , {__mode = "kv" })
local chan = {} local chan = {}
local chan_meta = { local chan_meta = {
__index = chan, __index = chan,
__gc = unsubscribe, __gc = function(self)
self:unsubscribe()
end,
__tostring = function (self) __tostring = function (self)
return string.format("[Multicast:%x]",self.channel) return string.format("[Multicast:%x]",self.channel)
end, end,

View File

@@ -386,7 +386,8 @@ end
local function _recv_decode_packet_resp(self) local function _recv_decode_packet_resp(self)
return function(sock) return function(sock)
return true, _recv_packet(self,sock) -- don't return more than 2 results
return true, (_recv_packet(self,sock))
end end
end end

View File

@@ -248,18 +248,16 @@ function suspend(co, result, command, param, size)
end end
function skynet.timeout(ti, func) function skynet.timeout(ti, func)
local session = c.command("TIMEOUT",tostring(ti)) local session = c.intcommand("TIMEOUT",ti)
assert(session) assert(session)
session = tonumber(session)
local co = co_create(func) local co = co_create(func)
assert(session_id_coroutine[session] == nil) assert(session_id_coroutine[session] == nil)
session_id_coroutine[session] = co session_id_coroutine[session] = co
end end
function skynet.sleep(ti) function skynet.sleep(ti)
local session = c.command("TIMEOUT",tostring(ti)) local session = c.intcommand("TIMEOUT",ti)
assert(session) assert(session)
session = tonumber(session)
local succ, ret = coroutine_yield("SLEEP", session) local succ, ret = coroutine_yield("SLEEP", session)
sleep_session[coroutine.running()] = nil sleep_session[coroutine.running()] = nil
if succ then if succ then
@@ -273,7 +271,7 @@ function skynet.sleep(ti)
end end
function skynet.yield() function skynet.yield()
return skynet.sleep("0") return skynet.sleep(0)
end end
function skynet.wait() function skynet.wait()
@@ -301,11 +299,11 @@ function skynet.localname(name)
end end
function skynet.now() function skynet.now()
return tonumber(c.command("NOW")) return c.intcommand("NOW")
end end
function skynet.starttime() function skynet.starttime()
return tonumber(c.command("STARTTIME")) return c.intcommand("STARTTIME")
end end
function skynet.time() function skynet.time()
@@ -415,9 +413,14 @@ function skynet.wakeup(co)
end end
function skynet.dispatch(typename, func) function skynet.dispatch(typename, func)
local p = assert(proto[typename],tostring(typename)) local p = proto[typename]
assert(p.dispatch == nil, tostring(typename)) if func then
p.dispatch = func local ret = p.dispatch
p.dispatch = func
return ret
else
return p and p.dispatch
end
end end
local function unknown_request(session, address, msg, sz, prototype) local function unknown_request(session, address, msg, sz, prototype)
@@ -466,7 +469,15 @@ local function raw_dispatch_message(prototype, msg, sz, session, source, ...)
suspend(co, coroutine.resume(co, true, msg, sz)) suspend(co, coroutine.resume(co, true, msg, sz))
end end
else else
local p = assert(proto[prototype], prototype) local p = proto[prototype]
if p == nil then
if session ~= 0 then
c.send(source, skynet.PTYPE_ERROR, session, "")
else
unknown_request(session, source, msg, sz, prototype)
end
return
end
local f = p.dispatch local f = p.dispatch
if f then if f then
local ref = watching_service[source] local ref = watching_service[source]
@@ -630,7 +641,7 @@ function skynet.endless()
end end
function skynet.mqlen() function skynet.mqlen()
return tonumber(c.command "MQLEN") return c.intcommand "MQLEN"
end end
function skynet.task(ret) function skynet.task(ret)

View File

@@ -10,7 +10,10 @@ function skynet.info_func(func)
internal_info_func = func internal_info_func = func
end end
local dbgcmd = {} local dbgcmd
local function init_dbgcmd()
dbgcmd = {}
function dbgcmd.MEM() function dbgcmd.MEM()
local kb, bytes = collectgarbage "count" local kb, bytes = collectgarbage "count"
@@ -63,8 +66,15 @@ function dbgcmd.REMOTEDEBUG(...)
remotedebug.start(export, ...) remotedebug.start(export, ...)
end end
function dbgcmd.SUPPORT(pname)
return skynet.ret(skynet.pack(skynet.dispatch(pname) ~= nil))
end
return dbgcmd
end -- function init_dbgcmd
local function _debug_dispatch(session, address, cmd, ...) local function _debug_dispatch(session, address, cmd, ...)
local f = dbgcmd[cmd] local f = (dbgcmd or init_dbgcmd())[cmd] -- lazy init dbgcmd
assert(f, cmd) assert(f, cmd)
f(...) f(...)
end end

View File

@@ -114,6 +114,12 @@ function gateserver.start(handler)
close_fd(fd) close_fd(fd)
end end
function MSG.warning(fd, size)
if handler.warning then
handler.warning(fd, size)
end
end
skynet.register_protocol { skynet.register_protocol {
name = "socket", name = "socket",
id = skynet.PTYPE_SOCKET, -- PTYPE_SOCKET = 6 id = skynet.PTYPE_SOCKET, -- PTYPE_SOCKET = 6

View File

@@ -49,7 +49,9 @@ local function collect_all_uv(funcs)
collect_uv(v[4], global, envid(v[4])) collect_uv(v[4], global, envid(v[4]))
end end
end end
if not global["_ENV"] then
global["_ENV"] = {func = collect_uv, index = 1}
end
return global return global
end end

View File

@@ -70,7 +70,7 @@ Config for server.start:
conf.login_handler(uid, secret) -> subid : the function when a new user login, alloc a subid for it. (may call by login server) conf.login_handler(uid, secret) -> subid : the function when a new user login, alloc a subid for it. (may call by login server)
conf.logout_handler(uid, subid) : the functon when a user logout. (may call by agent) conf.logout_handler(uid, subid) : the functon when a user logout. (may call by agent)
conf.kick_handler(uid, subid) : the functon when a user logout. (may call by login server) conf.kick_handler(uid, subid) : the functon when a user logout. (may call by login server)
conf.request_handler(username, session, msg, sz) : the function when recv a new request. conf.request_handler(username, session, msg) : the function when recv a new request.
conf.register_handler(servername) : call when gate open conf.register_handler(servername) : call when gate open
conf.disconnect_handler(username) : call when a connection disconnect (afk) conf.disconnect_handler(username) : call when a connection disconnect (afk)
]] ]]
@@ -234,10 +234,10 @@ function server.start(conf)
end end
end end
local function do_request(fd, msg, sz) local function do_request(fd, message)
local u = assert(connection[fd], "invalid fd") local u = assert(connection[fd], "invalid fd")
local msg_sz = sz - 4 local session = string.unpack(">I4", message, -4)
local session = netpack.tostring(msg, sz, msg_sz) message = message:sub(1,-5)
local p = u.response[session] local p = u.response[session]
if p then if p then
-- session can be reuse in the same connection -- session can be reuse in the same connection
@@ -256,21 +256,20 @@ function server.start(conf)
if p == nil then if p == nil then
p = { fd } p = { fd }
u.response[session] = p u.response[session] = p
local ok, result = pcall(conf.request_handler, u.username, msg, msg_sz) local ok, result = pcall(conf.request_handler, u.username, message)
result = result or ""
-- NOTICE: YIELD here, socket may close. -- NOTICE: YIELD here, socket may close.
result = result or ""
if not ok then if not ok then
skynet.error(result) skynet.error(result)
result = "\0" .. session result = string.pack(">BI4", 0, session)
else else
result = result .. '\1' .. session result = result .. string.pack(">BI4", 1, session)
end end
p[2] = netpack.pack_string(result) p[2] = string.pack(">s2",result)
p[3] = u.version p[3] = u.version
p[4] = u.index p[4] = u.index
else else
netpack.tostring(msg, sz) -- request before, so free msg
-- update version/index, change return fd. -- update version/index, change return fd.
-- resend response. -- resend response.
p[1] = fd p[1] = fd
@@ -292,10 +291,11 @@ function server.start(conf)
end end
local function request(fd, msg, sz) local function request(fd, msg, sz)
local ok, err = pcall(do_request, fd, msg, sz) local message = netpack.tostring(msg, sz)
local ok, err = pcall(do_request, fd, message)
-- not atomic, may yield -- not atomic, may yield
if not ok then if not ok then
skynet.error(string.format("Invalid package %s : %s", err, netpack.tostring(msg, sz))) skynet.error(string.format("Invalid package %s : %s", err, message))
if connection[fd] then if connection[fd] then
gateserver.closeclient(fd) gateserver.closeclient(fd)
end end

View File

@@ -133,6 +133,25 @@ socket_message[6] = function(id, size, data, address)
s.callback(str, address) s.callback(str, address)
end end
local function default_warning(id, size)
local s = socket_pool[id]
local last = s.warningsize or 0
if last + 64 < size then -- if size increase 64K
s.warningsize = size
skynet.error(string.format("WARNING: %d K bytes need to send out (fd = %d)", size, id))
end
s.warningsize = size
end
-- SKYNET_SOCKET_TYPE_WARNING
socket_message[7] = function(id, size)
local s = socket_pool[id]
if s then
local warning = s.warning or default_warning
warning(id, size)
end
end
skynet.register_protocol { skynet.register_protocol {
name = "socket", name = "socket",
id = skynet.PTYPE_SOCKET, -- PTYPE_SOCKET = 6 id = skynet.PTYPE_SOCKET, -- PTYPE_SOCKET = 6
@@ -404,4 +423,10 @@ end
socket.sendto = assert(driver.udp_send) socket.sendto = assert(driver.udp_send)
socket.udp_address = assert(driver.udp_address) socket.udp_address = assert(driver.udp_address)
function socket.warning(id, callback)
local obj = socket_pool[id]
assert(obj)
obj.warning = callback
end
return socket return socket

View File

@@ -81,15 +81,27 @@ local function dispatch_by_session(self)
local response = self.__response local response = self.__response
-- response() return session -- response() return session
while self.__sock do while self.__sock do
local ok , session, result_ok, result_data = pcall(response, self.__sock) local ok , session, result_ok, result_data, padding = pcall(response, self.__sock)
if ok and session then if ok and session then
local co = self.__thread[session] local co = self.__thread[session]
self.__thread[session] = nil
if co then if co then
self.__result[co] = result_ok if padding and result_ok then
self.__result_data[co] = result_data -- If padding is true, append result_data to a table (self.__result_data[co])
skynet.wakeup(co) local result = self.__result_data[co] or {}
self.__result_data[co] = result
table.insert(result, result_data)
else
self.__thread[session] = nil
self.__result[co] = result_ok
if result_ok and self.__result_data[co] then
table.insert(self.__result_data[co], result_data)
else
self.__result_data[co] = result_data
end
skynet.wakeup(co)
end
else else
self.__thread[session] = nil
skynet.error("socket: unknown session :", session) skynet.error("socket: unknown session :", session)
end end
else else
@@ -127,11 +139,23 @@ local function dispatch_by_order(self)
wakeup_all(self) wakeup_all(self)
end end
else else
local ok, result_ok, result_data = pcall(func, self.__sock) local ok, result_ok, result_data, padding = pcall(func, self.__sock)
if ok then if ok then
self.__result[co] = result_ok if padding and result_ok then
self.__result_data[co] = result_data -- if padding is true, wait for next result_data
skynet.wakeup(co) -- self.__result_data[co] is a table
local result = self.__result_data[co] or {}
self.__result_data[co] = result
table.insert(result, result_data)
else
self.__result[co] = result_ok
if result_ok and self.__result_data[co] then
table.insert(self.__result_data[co], result_data)
else
self.__result_data[co] = result_data
end
skynet.wakeup(co)
end
else else
close_channel_socket(self) close_channel_socket(self)
local errmsg local errmsg
@@ -314,13 +338,27 @@ local function wait_for_response(self, response)
end end
end end
function channel:request(request, response) local socket_write = socket.write
assert(block_connect(self, true)) -- connect once local socket_lwrite = socket.lwrite
if not socket.write(self.__sock[1], request) then function channel:request(request, response, padding)
close_channel_socket(self) assert(block_connect(self, true)) -- connect once
wakeup_all(self) local fd = self.__sock[1]
error(socket_error)
if padding then
-- padding may be a table, to support multi part request
-- multi part request use low priority socket write
-- socket_lwrite returns nothing
socket_lwrite(fd , request)
for _,v in ipairs(padding) do
socket_lwrite(fd, v)
end
else
if not socket_write(fd , request) then
close_channel_socket(self)
wakeup_all(self)
error(socket_error)
end
end end
if response == nil then if response == nil then

View File

@@ -81,7 +81,7 @@ end
local typedef = P { local typedef = P {
"ALL", "ALL",
FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^0 * typename * mainkey^0)), FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^-1 * typename * mainkey^0)),
STRUCT = P"{" * multipat(V"FIELD" + V"TYPE") * P"}", STRUCT = P"{" * multipat(V"FIELD" + V"TYPE") * P"}",
TYPE = namedpat("type", P"." * name * blank0 * V"STRUCT" ), TYPE = namedpat("type", P"." * name * blank0 * V"STRUCT" ),
SUBPROTO = Ct((C"request" + C"response") * blanks * (typename + V"STRUCT")), SUBPROTO = Ct((C"request" + C"response") * blanks * (typename + V"STRUCT")),

View File

@@ -262,6 +262,9 @@ dispatch_socket_message(struct gate *g, const struct skynet_socket_message * mes
skynet_socket_start(ctx, message->ud); skynet_socket_start(ctx, message->ud);
} }
break; break;
case SKYNET_SOCKET_TYPE_WARNING:
skynet_error(ctx, "fd (%d) send buffer (%d)K", message->id, message->ud);
break;
} }
} }

View File

@@ -1,6 +1,7 @@
#include "skynet.h" #include "skynet.h"
#include "skynet_harbor.h" #include "skynet_harbor.h"
#include "skynet_socket.h" #include "skynet_socket.h"
#include "skynet_handle.h"
/* /*
harbor listen the PTYPE_HARBOR (in text) harbor listen the PTYPE_HARBOR (in text)
@@ -323,9 +324,13 @@ forward_local_messsage(struct harbor *h, void *msg, int sz) {
static void static void
send_remote(struct skynet_context * ctx, int fd, const char * buffer, size_t sz, struct remote_message_header * cookie) { send_remote(struct skynet_context * ctx, int fd, const char * buffer, size_t sz, struct remote_message_header * cookie) {
uint32_t sz_header = sz+sizeof(*cookie); size_t sz_header = sz+sizeof(*cookie);
if (sz_header > UINT32_MAX) {
skynet_error(ctx, "remote message from :%08x to :%08x is too large.", cookie->source, cookie->destination);
return;
}
uint8_t * sendbuf = skynet_malloc(sz_header+4); uint8_t * sendbuf = skynet_malloc(sz_header+4);
to_bigendian(sendbuf, sz_header); to_bigendian(sendbuf, (uint32_t)sz_header);
memcpy(sendbuf+4, buffer, sz); memcpy(sendbuf+4, buffer, sz);
header_to_message(cookie, sendbuf+4+sz); header_to_message(cookie, sendbuf+4+sz);
@@ -657,6 +662,13 @@ mainloop(struct skynet_context * context, void * ud, int type, int session, uint
case SKYNET_SOCKET_TYPE_CONNECT: case SKYNET_SOCKET_TYPE_CONNECT:
// fd forward to this service // fd forward to this service
break; break;
case SKYNET_SOCKET_TYPE_WARNING: {
int id = harbor_id(h, message->id);
if (id) {
skynet_error(context, "message havn't send to Harbor (%d) reach %d K", id, message->ud);
}
break;
}
default: default:
skynet_error(context, "recv invalid socket message type %d", type); skynet_error(context, "recv invalid socket message type %d", type);
break; break;

View File

@@ -4,6 +4,7 @@ require "skynet.manager" -- import skynet.launch, ...
local globalname = {} local globalname = {}
local queryname = {} local queryname = {}
local harbor = {} local harbor = {}
local harbor_service
skynet.register_protocol { skynet.register_protocol {
name = "harbor", name = "harbor",

View File

@@ -11,7 +11,7 @@ local command = {}
local function read_response(sock) local function read_response(sock)
local sz = socket.header(sock:read(2)) local sz = socket.header(sock:read(2))
local msg = sock:read(sz) local msg = sock:read(sz)
return cluster.unpackresponse(msg) -- session, ok, data return cluster.unpackresponse(msg) -- session, ok, data, padding
end end
local function open_channel(t, key) local function open_channel(t, key)
@@ -24,7 +24,6 @@ local function open_channel(t, key)
} }
assert(c:connect(true)) assert(c:connect(true))
t[key] = c t[key] = c
node_session[key] = 1
return c return c
end end
@@ -63,19 +62,25 @@ function command.listen(source, addr, port)
end end
local function send_request(source, node, addr, msg, sz) local function send_request(source, node, addr, msg, sz)
local request local session = node_session[node] or 1
local c = node_channel[node]
local session = node_session[node]
-- msg is a local pointer, cluster.packrequest will free it -- msg is a local pointer, cluster.packrequest will free it
request, node_session[node] = cluster.packrequest(addr, session , msg, sz) local request, new_session, padding = cluster.packrequest(addr, session, msg, sz)
node_session[node] = new_session
return c:request(request, session) -- node_channel[node] may yield or throw error
local c = node_channel[node]
return c:request(request, session, padding)
end end
function command.req(...) function command.req(...)
local ok, msg, sz = pcall(send_request, ...) local ok, msg, sz = pcall(send_request, ...)
if ok then if ok then
skynet.ret(msg, sz) if type(msg) == "table" then
skynet.ret(cluster.concat(msg))
else
skynet.ret(msg)
end
else else
skynet.error(msg) skynet.error(msg)
skynet.response()(false) skynet.response()(false)
@@ -92,23 +97,78 @@ function command.proxy(source, node, name)
skynet.ret(skynet.pack(proxy[fullname])) skynet.ret(skynet.pack(proxy[fullname]))
end end
local request_fd = {} local register_name = {}
function command.register(source, name, addr)
assert(register_name[name] == nil)
addr = addr or source
local old_name = register_name[addr]
if old_name then
register_name[old_name] = nil
end
register_name[addr] = name
register_name[name] = addr
skynet.ret(nil)
skynet.error(string.format("Register [%s] :%08x", name, addr))
end
local large_request = {}
function command.socket(source, subcmd, fd, msg) function command.socket(source, subcmd, fd, msg)
if subcmd == "data" then if subcmd == "data" then
local addr, session, msg = cluster.unpackrequest(msg) local sz
local ok , msg, sz = pcall(skynet.rawcall, addr, "lua", msg) local addr, session, msg, padding = cluster.unpackrequest(msg)
local response if padding then
local req = large_request[session] or { addr = addr }
large_request[session] = req
table.insert(req, msg)
return
else
local req = large_request[session]
if req then
large_request[session] = nil
table.insert(req, msg)
msg,sz = cluster.concat(req)
addr = req.addr
end
if not msg then
local response = cluster.packresponse(session, false, "Invalid large req")
socket.write(fd, response)
return
end
end
local ok, response
if addr == 0 then
local name = skynet.unpack(msg, sz)
local addr = register_name[name]
if addr then
ok = true
msg, sz = skynet.pack(addr)
else
ok = false
msg = "name not found"
end
else
ok , msg, sz = pcall(skynet.rawcall, addr, "lua", msg, sz)
end
if ok then if ok then
response = cluster.packresponse(session, true, msg, sz) response = cluster.packresponse(session, true, msg, sz)
if type(response) == "table" then
for _, v in ipairs(response) do
socket.lwrite(fd, v)
end
else
socket.write(fd, response)
end
else else
response = cluster.packresponse(session, false, msg) response = cluster.packresponse(session, false, msg)
socket.write(fd, response)
end end
socket.write(fd, response)
elseif subcmd == "open" then elseif subcmd == "open" then
skynet.error(string.format("socket accept from %s", msg)) skynet.error(string.format("socket accept from %s", msg))
skynet.call(source, "lua", "accept", fd) skynet.call(source, "lua", "accept", fd)
else else
large_request = {}
skynet.error(string.format("socket %s %d : %s", subcmd, fd, msg)) skynet.error(string.format("socket %s %d : %s", subcmd, fd, msg))
end end
end end

View File

@@ -2,7 +2,11 @@ local skynet = require "skynet"
local memory = require "memory" local memory = require "memory"
memory.dumpinfo() memory.dumpinfo()
memory.dump() --memory.dump()
local info = memory.info()
for k,v in pairs(info) do
print(string.format(":%08x %gK",k,v/1024))
end
print("Total memory:", memory.total()) print("Total memory:", memory.total())
print("Total block:", memory.block()) print("Total block:", memory.block())

View File

@@ -228,6 +228,7 @@ function COMMAND.debug(address, fd)
skynet.fork(function() skynet.fork(function()
repeat repeat
local cmdline = socket.readline(fd, "\n") local cmdline = socket.readline(fd, "\n")
cmdline = cmdline:gsub("(.*)\r$", "%1")
if not cmdline then if not cmdline then
skynet.send(agent, "lua", "cmd", "cont") skynet.send(agent, "lua", "cmd", "cont")
break break

View File

@@ -63,6 +63,10 @@ function handler.error(fd, msg)
skynet.send(watchdog, "lua", "socket", "error", fd, msg) skynet.send(watchdog, "lua", "socket", "error", fd, msg)
end end
function handler.warning(fd, size)
skynet.send(watchdog, "lua", "socket", "warning", fd, size)
end
local CMD = {} local CMD = {}
function CMD.forward(source, fd, client, address) function CMD.forward(source, fd, client, address)

14
skynet-src/atomic.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef SKYNET_ATOMIC_H
#define SKYNET_ATOMIC_H
#define ATOM_CAS(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval)
#define ATOM_CAS_POINTER(ptr, oval, nval) __sync_bool_compare_and_swap(ptr, oval, nval)
#define ATOM_INC(ptr) __sync_add_and_fetch(ptr, 1)
#define ATOM_FINC(ptr) __sync_fetch_and_add(ptr, 1)
#define ATOM_DEC(ptr) __sync_sub_and_fetch(ptr, 1)
#define ATOM_FDEC(ptr) __sync_fetch_and_sub(ptr, 1)
#define ATOM_ADD(ptr,n) __sync_add_and_fetch(ptr, n)
#define ATOM_SUB(ptr,n) __sync_sub_and_fetch(ptr, n)
#define ATOM_AND(ptr,n) __sync_and_and_fetch(ptr, n)
#endif

View File

@@ -2,9 +2,11 @@
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <lua.h>
#include "malloc_hook.h" #include "malloc_hook.h"
#include "skynet.h" #include "skynet.h"
#include "atomic.h"
static size_t _used_memory = 0; static size_t _used_memory = 0;
static size_t _memory_block = 0; static size_t _memory_block = 0;
@@ -31,11 +33,11 @@ get_allocated_field(uint32_t handle) {
ssize_t old_alloc = data->allocated; ssize_t old_alloc = data->allocated;
if(old_handle == 0 || old_alloc <= 0) { if(old_handle == 0 || old_alloc <= 0) {
// data->allocated may less than zero, because it may not count at start. // data->allocated may less than zero, because it may not count at start.
if(!__sync_bool_compare_and_swap(&data->handle, old_handle, handle)) { if(!ATOM_CAS(&data->handle, old_handle, handle)) {
return 0; return 0;
} }
if (old_alloc < 0) { if (old_alloc < 0) {
__sync_bool_compare_and_swap(&data->allocated, old_alloc, 0); ATOM_CAS(&data->allocated, old_alloc, 0);
} }
} }
if(data->handle != handle) { if(data->handle != handle) {
@@ -46,21 +48,21 @@ get_allocated_field(uint32_t handle) {
inline static void inline static void
update_xmalloc_stat_alloc(uint32_t handle, size_t __n) { update_xmalloc_stat_alloc(uint32_t handle, size_t __n) {
__sync_add_and_fetch(&_used_memory, __n); ATOM_ADD(&_used_memory, __n);
__sync_add_and_fetch(&_memory_block, 1); ATOM_INC(&_memory_block);
ssize_t* allocated = get_allocated_field(handle); ssize_t* allocated = get_allocated_field(handle);
if(allocated) { if(allocated) {
__sync_add_and_fetch(allocated, __n); ATOM_ADD(allocated, __n);
} }
} }
inline static void inline static void
update_xmalloc_stat_free(uint32_t handle, size_t __n) { update_xmalloc_stat_free(uint32_t handle, size_t __n) {
__sync_sub_and_fetch(&_used_memory, __n); ATOM_SUB(&_used_memory, __n);
__sync_sub_and_fetch(&_memory_block, 1); ATOM_DEC(&_memory_block);
ssize_t* allocated = get_allocated_field(handle); ssize_t* allocated = get_allocated_field(handle);
if(allocated) { if(allocated) {
__sync_sub_and_fetch(allocated, __n); ATOM_SUB(allocated, __n);
} }
} }
@@ -224,3 +226,17 @@ skynet_lalloc(void *ud, void *ptr, size_t osize, size_t nsize) {
return skynet_realloc(ptr, nsize); return skynet_realloc(ptr, nsize);
} }
} }
int
dump_mem_lua(lua_State *L) {
int i;
lua_newtable(L);
for(i=0; i<SLOT_SIZE; i++) {
mem_data* data = &mem_stats[i];
if(data->handle != 0 && data->allocated != 0) {
lua_pushinteger(L, data->allocated);
lua_rawseti(L, -2, (lua_Integer)data->handle);
}
}
return 1;
}

View File

@@ -2,6 +2,7 @@
#define SKYNET_MALLOC_HOOK_H #define SKYNET_MALLOC_HOOK_H
#include <stdlib.h> #include <stdlib.h>
#include <lua.h>
extern size_t malloc_used_memory(void); extern size_t malloc_used_memory(void);
extern size_t malloc_memory_block(void); extern size_t malloc_memory_block(void);
@@ -9,6 +10,7 @@ extern void memory_info_dump(void);
extern size_t mallctl_int64(const char* name, size_t* newval); extern size_t mallctl_int64(const char* name, size_t* newval);
extern int mallctl_opt(const char* name, int* newval); extern int mallctl_opt(const char* name, int* newval);
extern void dump_c_mem(void); extern void dump_c_mem(void);
extern int dump_mem_lua(lua_State *L);
#endif /* SKYNET_MALLOC_HOOK_H */ #endif /* SKYNET_MALLOC_HOOK_H */

View File

@@ -1,6 +1,8 @@
#ifndef SKYNET_RWLOCK_H #ifndef SKYNET_RWLOCK_H
#define SKYNET_RWLOCK_H #define SKYNET_RWLOCK_H
#ifndef USE_PTHREAD_LOCK
struct rwlock { struct rwlock {
int write; int write;
int read; int read;
@@ -45,4 +47,42 @@ rwlock_runlock(struct rwlock *lock) {
__sync_sub_and_fetch(&lock->read,1); __sync_sub_and_fetch(&lock->read,1);
} }
#else
#include <pthread.h>
// only for some platform doesn't have __sync_*
// todo: check the result of pthread api
struct rwlock {
pthread_rwlock_t lock;
};
static inline void
rwlock_init(struct rwlock *lock) {
pthread_rwlock_init(&lock->lock, NULL);
}
static inline void
rwlock_rlock(struct rwlock *lock) {
pthread_rwlock_rdlock(&lock->lock);
}
static inline void
rwlock_wlock(struct rwlock *lock) {
pthread_rwlock_wrlock(&lock->lock);
}
static inline void
rwlock_wunlock(struct rwlock *lock) {
pthread_rwlock_unlock(&lock->lock);
}
static inline void
rwlock_runlock(struct rwlock *lock) {
pthread_rwlock_unlock(&lock->lock);
}
#endif
#endif #endif

View File

@@ -1,5 +1,6 @@
#include "skynet.h" #include "skynet.h"
#include "skynet_env.h" #include "skynet_env.h"
#include "spinlock.h"
#include <lua.h> #include <lua.h>
#include <lauxlib.h> #include <lauxlib.h>
@@ -8,18 +9,15 @@
#include <assert.h> #include <assert.h>
struct skynet_env { struct skynet_env {
int lock; struct spinlock lock;
lua_State *L; lua_State *L;
}; };
static struct skynet_env *E = NULL; static struct skynet_env *E = NULL;
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
const char * const char *
skynet_getenv(const char *key) { skynet_getenv(const char *key) {
LOCK(E) SPIN_LOCK(E)
lua_State *L = E->L; lua_State *L = E->L;
@@ -27,14 +25,14 @@ skynet_getenv(const char *key) {
const char * result = lua_tostring(L, -1); const char * result = lua_tostring(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
UNLOCK(E) SPIN_UNLOCK(E)
return result; return result;
} }
void void
skynet_setenv(const char *key, const char *value) { skynet_setenv(const char *key, const char *value) {
LOCK(E) SPIN_LOCK(E)
lua_State *L = E->L; lua_State *L = E->L;
lua_getglobal(L, key); lua_getglobal(L, key);
@@ -43,12 +41,12 @@ skynet_setenv(const char *key, const char *value) {
lua_pushstring(L,value); lua_pushstring(L,value);
lua_setglobal(L,key); lua_setglobal(L,key);
UNLOCK(E) SPIN_UNLOCK(E)
} }
void void
skynet_env_init() { skynet_env_init() {
E = skynet_malloc(sizeof(*E)); E = skynet_malloc(sizeof(*E));
E->lock = 0; SPIN_INIT(E)
E->L = luaL_newstate(); E->L = luaL_newstate();
} }

View File

@@ -54,7 +54,7 @@ skynet_error(struct skynet_context * context, const char *msg, ...) {
} }
smsg.session = 0; smsg.session = 0;
smsg.data = data; smsg.data = data;
smsg.sz = len | (PTYPE_TEXT << HANDLE_REMOTE_SHIFT); smsg.sz = len | ((size_t)PTYPE_TEXT << MESSAGE_TYPE_SHIFT);
skynet_context_push(logger, &smsg); skynet_context_push(logger, &smsg);
} }

View File

@@ -3,7 +3,9 @@
#include <stdint.h> #include <stdint.h>
#include "skynet_harbor.h" // reserve high 8 bits for remote id
#define HANDLE_MASK 0xffffff
#define HANDLE_REMOTE_SHIFT 24
struct skynet_context; struct skynet_context;

View File

@@ -1,6 +1,8 @@
#include "skynet.h" #include "skynet.h"
#include "skynet_harbor.h" #include "skynet_harbor.h"
#include "skynet_server.h" #include "skynet_server.h"
#include "skynet_mq.h"
#include "skynet_handle.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
@@ -11,8 +13,8 @@ static unsigned int HARBOR = ~0;
void void
skynet_harbor_send(struct remote_message *rmsg, uint32_t source, int session) { skynet_harbor_send(struct remote_message *rmsg, uint32_t source, int session) {
int type = rmsg->sz >> HANDLE_REMOTE_SHIFT; int type = rmsg->sz >> MESSAGE_TYPE_SHIFT;
rmsg->sz &= HANDLE_MASK; rmsg->sz &= MESSAGE_TYPE_MASK;
assert(type != PTYPE_SYSTEM && type != PTYPE_HARBOR && REMOTE); assert(type != PTYPE_SYSTEM && type != PTYPE_HARBOR && REMOTE);
skynet_context_send(REMOTE, rmsg, sizeof(*rmsg) , source, type , session); skynet_context_send(REMOTE, rmsg, sizeof(*rmsg) , source, type , session);
} }

View File

@@ -7,10 +7,6 @@
#define GLOBALNAME_LENGTH 16 #define GLOBALNAME_LENGTH 16
#define REMOTE_MAX 256 #define REMOTE_MAX 256
// reserve high 8 bits for remote id
#define HANDLE_MASK 0xffffff
#define HANDLE_REMOTE_SHIFT 24
struct remote_name { struct remote_name {
char name[GLOBALNAME_LENGTH]; char name[GLOBALNAME_LENGTH];
uint32_t handle; uint32_t handle;

View File

@@ -1,6 +1,7 @@
#include "skynet.h" #include "skynet.h"
#include "skynet_module.h" #include "skynet_module.h"
#include "spinlock.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
@@ -13,7 +14,7 @@
struct modules { struct modules {
int count; int count;
int lock; struct spinlock lock;
const char * path; const char * path;
struct skynet_module m[MAX_MODULE_TYPE]; struct skynet_module m[MAX_MODULE_TYPE];
}; };
@@ -95,7 +96,7 @@ skynet_module_query(const char * name) {
if (result) if (result)
return result; return result;
while(__sync_lock_test_and_set(&M->lock,1)) {} SPIN_LOCK(M)
result = _query(name); // double check result = _query(name); // double check
@@ -114,21 +115,22 @@ skynet_module_query(const char * name) {
} }
} }
__sync_lock_release(&M->lock); SPIN_UNLOCK(M)
return result; return result;
} }
void void
skynet_module_insert(struct skynet_module *mod) { skynet_module_insert(struct skynet_module *mod) {
while(__sync_lock_test_and_set(&M->lock,1)) {} SPIN_LOCK(M)
struct skynet_module * m = _query(mod->name); struct skynet_module * m = _query(mod->name);
assert(m == NULL && M->count < MAX_MODULE_TYPE); assert(m == NULL && M->count < MAX_MODULE_TYPE);
int index = M->count; int index = M->count;
M->m[index] = *mod; M->m[index] = *mod;
++M->count; ++M->count;
__sync_lock_release(&M->lock);
SPIN_UNLOCK(M)
} }
void * void *
@@ -164,7 +166,8 @@ skynet_module_init(const char *path) {
struct modules *m = skynet_malloc(sizeof(*m)); struct modules *m = skynet_malloc(sizeof(*m));
m->count = 0; m->count = 0;
m->path = skynet_strdup(path); m->path = skynet_strdup(path);
m->lock = 0;
SPIN_INIT(m)
M = m; M = m;
} }

View File

@@ -3,6 +3,7 @@
#include "skynet_monitor.h" #include "skynet_monitor.h"
#include "skynet_server.h" #include "skynet_server.h"
#include "skynet.h" #include "skynet.h"
#include "atomic.h"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -30,7 +31,7 @@ void
skynet_monitor_trigger(struct skynet_monitor *sm, uint32_t source, uint32_t destination) { skynet_monitor_trigger(struct skynet_monitor *sm, uint32_t source, uint32_t destination) {
sm->source = source; sm->source = source;
sm->destination = destination; sm->destination = destination;
__sync_fetch_and_add(&sm->version , 1); ATOM_INC(&sm->version);
} }
void void

View File

@@ -1,6 +1,7 @@
#include "skynet.h" #include "skynet.h"
#include "skynet_mq.h" #include "skynet_mq.h"
#include "skynet_handle.h" #include "skynet_handle.h"
#include "spinlock.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -18,11 +19,11 @@
#define MQ_OVERLOAD 1024 #define MQ_OVERLOAD 1024
struct message_queue { struct message_queue {
struct spinlock lock;
uint32_t handle; uint32_t handle;
int cap; int cap;
int head; int head;
int tail; int tail;
int lock;
int release; int release;
int in_global; int in_global;
int overload; int overload;
@@ -34,19 +35,16 @@ struct message_queue {
struct global_queue { struct global_queue {
struct message_queue *head; struct message_queue *head;
struct message_queue *tail; struct message_queue *tail;
int lock; struct spinlock lock;
}; };
static struct global_queue *Q = NULL; static struct global_queue *Q = NULL;
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
void void
skynet_globalmq_push(struct message_queue * queue) { skynet_globalmq_push(struct message_queue * queue) {
struct global_queue *q= Q; struct global_queue *q= Q;
LOCK(q) SPIN_LOCK(q)
assert(queue->next == NULL); assert(queue->next == NULL);
if(q->tail) { if(q->tail) {
q->tail->next = queue; q->tail->next = queue;
@@ -54,14 +52,14 @@ skynet_globalmq_push(struct message_queue * queue) {
} else { } else {
q->head = q->tail = queue; q->head = q->tail = queue;
} }
UNLOCK(q) SPIN_UNLOCK(q)
} }
struct message_queue * struct message_queue *
skynet_globalmq_pop() { skynet_globalmq_pop() {
struct global_queue *q = Q; struct global_queue *q = Q;
LOCK(q) SPIN_LOCK(q)
struct message_queue *mq = q->head; struct message_queue *mq = q->head;
if(mq) { if(mq) {
q->head = mq->next; q->head = mq->next;
@@ -71,7 +69,7 @@ skynet_globalmq_pop() {
} }
mq->next = NULL; mq->next = NULL;
} }
UNLOCK(q) SPIN_UNLOCK(q)
return mq; return mq;
} }
@@ -83,7 +81,7 @@ skynet_mq_create(uint32_t handle) {
q->cap = DEFAULT_QUEUE_SIZE; q->cap = DEFAULT_QUEUE_SIZE;
q->head = 0; q->head = 0;
q->tail = 0; q->tail = 0;
q->lock = 0; SPIN_INIT(q)
// When the queue is create (always between service create and service init) , // When the queue is create (always between service create and service init) ,
// set in_global flag to avoid push it to global queue . // set in_global flag to avoid push it to global queue .
// If the service init success, skynet_context_new will call skynet_mq_force_push to push it to global queue. // If the service init success, skynet_context_new will call skynet_mq_force_push to push it to global queue.
@@ -100,6 +98,7 @@ skynet_mq_create(uint32_t handle) {
static void static void
_release(struct message_queue *q) { _release(struct message_queue *q) {
assert(q->next == NULL); assert(q->next == NULL);
SPIN_DESTROY(q)
skynet_free(q->queue); skynet_free(q->queue);
skynet_free(q); skynet_free(q);
} }
@@ -113,11 +112,11 @@ int
skynet_mq_length(struct message_queue *q) { skynet_mq_length(struct message_queue *q) {
int head, tail,cap; int head, tail,cap;
LOCK(q) SPIN_LOCK(q)
head = q->head; head = q->head;
tail = q->tail; tail = q->tail;
cap = q->cap; cap = q->cap;
UNLOCK(q) SPIN_UNLOCK(q)
if (head <= tail) { if (head <= tail) {
return tail - head; return tail - head;
@@ -138,7 +137,7 @@ skynet_mq_overload(struct message_queue *q) {
int int
skynet_mq_pop(struct message_queue *q, struct skynet_message *message) { skynet_mq_pop(struct message_queue *q, struct skynet_message *message) {
int ret = 1; int ret = 1;
LOCK(q) SPIN_LOCK(q)
if (q->head != q->tail) { if (q->head != q->tail) {
*message = q->queue[q->head++]; *message = q->queue[q->head++];
@@ -167,7 +166,7 @@ skynet_mq_pop(struct message_queue *q, struct skynet_message *message) {
q->in_global = 0; q->in_global = 0;
} }
UNLOCK(q) SPIN_UNLOCK(q)
return ret; return ret;
} }
@@ -190,7 +189,7 @@ expand_queue(struct message_queue *q) {
void void
skynet_mq_push(struct message_queue *q, struct skynet_message *message) { skynet_mq_push(struct message_queue *q, struct skynet_message *message) {
assert(message); assert(message);
LOCK(q) SPIN_LOCK(q)
q->queue[q->tail] = *message; q->queue[q->tail] = *message;
if (++ q->tail >= q->cap) { if (++ q->tail >= q->cap) {
@@ -206,25 +205,26 @@ skynet_mq_push(struct message_queue *q, struct skynet_message *message) {
skynet_globalmq_push(q); skynet_globalmq_push(q);
} }
UNLOCK(q) SPIN_UNLOCK(q)
} }
void void
skynet_mq_init() { skynet_mq_init() {
struct global_queue *q = skynet_malloc(sizeof(*q)); struct global_queue *q = skynet_malloc(sizeof(*q));
memset(q,0,sizeof(*q)); memset(q,0,sizeof(*q));
SPIN_INIT(q);
Q=q; Q=q;
} }
void void
skynet_mq_mark_release(struct message_queue *q) { skynet_mq_mark_release(struct message_queue *q) {
LOCK(q) SPIN_LOCK(q)
assert(q->release == 0); assert(q->release == 0);
q->release = 1; q->release = 1;
if (q->in_global != MQ_IN_GLOBAL) { if (q->in_global != MQ_IN_GLOBAL) {
skynet_globalmq_push(q); skynet_globalmq_push(q);
} }
UNLOCK(q) SPIN_UNLOCK(q)
} }
static void static void
@@ -238,13 +238,13 @@ _drop_queue(struct message_queue *q, message_drop drop_func, void *ud) {
void void
skynet_mq_release(struct message_queue *q, message_drop drop_func, void *ud) { skynet_mq_release(struct message_queue *q, message_drop drop_func, void *ud) {
LOCK(q) SPIN_LOCK(q)
if (q->release) { if (q->release) {
UNLOCK(q) SPIN_UNLOCK(q)
_drop_queue(q, drop_func, ud); _drop_queue(q, drop_func, ud);
} else { } else {
skynet_globalmq_push(q); skynet_globalmq_push(q);
UNLOCK(q) SPIN_UNLOCK(q)
} }
} }

View File

@@ -11,6 +11,10 @@ struct skynet_message {
size_t sz; size_t sz;
}; };
// type is encoding in skynet_message.sz high 8bit
#define MESSAGE_TYPE_MASK (SIZE_MAX >> 8)
#define MESSAGE_TYPE_SHIFT ((sizeof(size_t)-1) * 8)
struct message_queue; struct message_queue;
void skynet_globalmq_push(struct message_queue * queue); void skynet_globalmq_push(struct message_queue * queue);

View File

@@ -10,6 +10,8 @@
#include "skynet_monitor.h" #include "skynet_monitor.h"
#include "skynet_imp.h" #include "skynet_imp.h"
#include "skynet_log.h" #include "skynet_log.h"
#include "spinlock.h"
#include "atomic.h"
#include <pthread.h> #include <pthread.h>
@@ -21,16 +23,18 @@
#ifdef CALLING_CHECK #ifdef CALLING_CHECK
#define CHECKCALLING_BEGIN(ctx) assert(__sync_lock_test_and_set(&ctx->calling,1) == 0); #define CHECKCALLING_BEGIN(ctx) if (!(spinlock_trylock(&ctx->calling))) { assert(0); }
#define CHECKCALLING_END(ctx) __sync_lock_release(&ctx->calling); #define CHECKCALLING_END(ctx) spinlock_unlock(&ctx->calling);
#define CHECKCALLING_INIT(ctx) ctx->calling = 0; #define CHECKCALLING_INIT(ctx) spinlock_init(&ctx->calling);
#define CHECKCALLING_DECL int calling; #define CHECKCALLING_DESTROY(ctx) spinlock_destroy(&ctx->calling);
#define CHECKCALLING_DECL struct spinlock calling;
#else #else
#define CHECKCALLING_BEGIN(ctx) #define CHECKCALLING_BEGIN(ctx)
#define CHECKCALLING_END(ctx) #define CHECKCALLING_END(ctx)
#define CHECKCALLING_INIT(ctx) #define CHECKCALLING_INIT(ctx)
#define CHECKCALLING_DESTROY(ctx)
#define CHECKCALLING_DECL #define CHECKCALLING_DECL
#endif #endif
@@ -68,12 +72,12 @@ skynet_context_total() {
static void static void
context_inc() { context_inc() {
__sync_fetch_and_add(&G_NODE.total,1); ATOM_INC(&G_NODE.total);
} }
static void static void
context_dec() { context_dec() {
__sync_fetch_and_sub(&G_NODE.total,1); ATOM_DEC(&G_NODE.total);
} }
uint32_t uint32_t
@@ -179,7 +183,7 @@ skynet_context_newsession(struct skynet_context *ctx) {
void void
skynet_context_grab(struct skynet_context *ctx) { skynet_context_grab(struct skynet_context *ctx) {
__sync_add_and_fetch(&ctx->ref,1); ATOM_INC(&ctx->ref);
} }
void void
@@ -197,13 +201,14 @@ delete_context(struct skynet_context *ctx) {
} }
skynet_module_instance_release(ctx->mod, ctx->instance); skynet_module_instance_release(ctx->mod, ctx->instance);
skynet_mq_mark_release(ctx->queue); skynet_mq_mark_release(ctx->queue);
CHECKCALLING_DESTROY(ctx)
skynet_free(ctx); skynet_free(ctx);
context_dec(); context_dec();
} }
struct skynet_context * struct skynet_context *
skynet_context_release(struct skynet_context *ctx) { skynet_context_release(struct skynet_context *ctx) {
if (__sync_sub_and_fetch(&ctx->ref,1) == 0) { if (ATOM_DEC(&ctx->ref) == 0) {
delete_context(ctx); delete_context(ctx);
return NULL; return NULL;
} }
@@ -246,8 +251,8 @@ dispatch_message(struct skynet_context *ctx, struct skynet_message *msg) {
assert(ctx->init); assert(ctx->init);
CHECKCALLING_BEGIN(ctx) CHECKCALLING_BEGIN(ctx)
pthread_setspecific(G_NODE.handle_key, (void *)(uintptr_t)(ctx->handle)); pthread_setspecific(G_NODE.handle_key, (void *)(uintptr_t)(ctx->handle));
int type = msg->sz >> HANDLE_REMOTE_SHIFT; int type = msg->sz >> MESSAGE_TYPE_SHIFT;
size_t sz = msg->sz & HANDLE_MASK; size_t sz = msg->sz & MESSAGE_TYPE_MASK;
if (ctx->logfile) { if (ctx->logfile) {
skynet_log_output(ctx->logfile, msg->source, type, msg->session, msg->data, sz); skynet_log_output(ctx->logfile, msg->source, type, msg->session, msg->data, sz);
} }
@@ -560,7 +565,7 @@ cmd_logon(struct skynet_context * context, const char * param) {
if (lastf == NULL) { if (lastf == NULL) {
f = skynet_log_open(context, handle); f = skynet_log_open(context, handle);
if (f) { if (f) {
if (!__sync_bool_compare_and_swap(&ctx->logfile, NULL, f)) { if (!ATOM_CAS_POINTER(&ctx->logfile, NULL, f)) {
// logfile opens in other thread, close this one. // logfile opens in other thread, close this one.
fclose(f); fclose(f);
} }
@@ -581,7 +586,7 @@ cmd_logoff(struct skynet_context * context, const char * param) {
FILE * f = ctx->logfile; FILE * f = ctx->logfile;
if (f) { if (f) {
// logfile may close in other thread // logfile may close in other thread
if (__sync_bool_compare_and_swap(&ctx->logfile, f, NULL)) { if (ATOM_CAS_POINTER(&ctx->logfile, f, NULL)) {
skynet_log_close(context, f, handle); skynet_log_close(context, f, handle);
} }
} }
@@ -662,13 +667,13 @@ _filter_args(struct skynet_context * context, int type, int *session, void ** da
*data = msg; *data = msg;
} }
*sz |= type << HANDLE_REMOTE_SHIFT; *sz |= (size_t)type << MESSAGE_TYPE_SHIFT;
} }
int int
skynet_send(struct skynet_context * context, uint32_t source, uint32_t destination , int type, int session, void * data, size_t sz) { skynet_send(struct skynet_context * context, uint32_t source, uint32_t destination , int type, int session, void * data, size_t sz) {
if ((sz & HANDLE_MASK) != sz) { if ((sz & MESSAGE_TYPE_MASK) != sz) {
skynet_error(context, "The message to %x is too large (sz = %lu)", destination, sz); skynet_error(context, "The message to %x is too large", destination);
skynet_free(data); skynet_free(data);
return -1; return -1;
} }
@@ -751,7 +756,7 @@ skynet_context_send(struct skynet_context * ctx, void * msg, size_t sz, uint32_t
smsg.source = source; smsg.source = source;
smsg.session = session; smsg.session = session;
smsg.data = msg; smsg.data = msg;
smsg.sz = sz | type << HANDLE_REMOTE_SHIFT; smsg.sz = sz | (size_t)type << MESSAGE_TYPE_SHIFT;
skynet_mq_push(ctx->queue, &smsg); skynet_mq_push(ctx->queue, &smsg);
} }

View File

@@ -33,7 +33,7 @@ skynet_socket_free() {
static void static void
forward_message(int type, bool padding, struct socket_message * result) { forward_message(int type, bool padding, struct socket_message * result) {
struct skynet_socket_message *sm; struct skynet_socket_message *sm;
int sz = sizeof(*sm); size_t sz = sizeof(*sm);
if (padding) { if (padding) {
if (result->data) { if (result->data) {
sz += strlen(result->data); sz += strlen(result->data);
@@ -56,7 +56,7 @@ forward_message(int type, bool padding, struct socket_message * result) {
message.source = 0; message.source = 0;
message.session = 0; message.session = 0;
message.data = sm; message.data = sm;
message.sz = sz | PTYPE_SOCKET << HANDLE_REMOTE_SHIFT; message.sz = sz | ((size_t)PTYPE_SOCKET << MESSAGE_TYPE_SHIFT);
if (skynet_context_push((uint32_t)result->opaque, &message)) { if (skynet_context_push((uint32_t)result->opaque, &message)) {
// todo: report somewhere to close socket // todo: report somewhere to close socket
@@ -109,10 +109,13 @@ check_wsz(struct skynet_context *ctx, int id, void *buffer, int64_t wsz) {
if (wsz < 0) { if (wsz < 0) {
return -1; return -1;
} else if (wsz > 1024 * 1024) { } else if (wsz > 1024 * 1024) {
int kb4 = wsz / 1024 / 4; struct skynet_socket_message tmp;
if (kb4 % 256 == 0) { tmp.type = SKYNET_SOCKET_TYPE_WARNING;
skynet_error(ctx, "%d Mb bytes on socket %d need to send out", (int)(wsz / (1024 * 1024)), id); tmp.id = id;
} tmp.ud = (int)(wsz / 1024);
tmp.buffer = NULL;
skynet_send(ctx, 0, skynet_context_handle(ctx), PTYPE_SOCKET, 0 , &tmp, sizeof(tmp));
// skynet_error(ctx, "%d Mb bytes on socket %d need to send out", (int)(wsz / (1024 * 1024)), id);
} }
return 0; return 0;
} }

View File

@@ -9,6 +9,7 @@ struct skynet_context;
#define SKYNET_SOCKET_TYPE_ACCEPT 4 #define SKYNET_SOCKET_TYPE_ACCEPT 4
#define SKYNET_SOCKET_TYPE_ERROR 5 #define SKYNET_SOCKET_TYPE_ERROR 5
#define SKYNET_SOCKET_TYPE_UDP 6 #define SKYNET_SOCKET_TYPE_UDP 6
#define SKYNET_SOCKET_TYPE_WARNING 7
struct skynet_socket_message { struct skynet_socket_message {
int type; int type;

View File

@@ -8,6 +8,7 @@
#include "skynet_monitor.h" #include "skynet_monitor.h"
#include "skynet_socket.h" #include "skynet_socket.h"
#include "skynet_daemon.h" #include "skynet_daemon.h"
#include "skynet_harbor.h"
#include <pthread.h> #include <pthread.h>
#include <unistd.h> #include <unistd.h>

View File

@@ -4,6 +4,7 @@
#include "skynet_mq.h" #include "skynet_mq.h"
#include "skynet_server.h" #include "skynet_server.h"
#include "skynet_handle.h" #include "skynet_handle.h"
#include "spinlock.h"
#include <time.h> #include <time.h>
#include <assert.h> #include <assert.h>
@@ -17,9 +18,6 @@
typedef void (*timer_execute_func)(void *ud,void *arg); 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_SHIFT 8
#define TIME_NEAR (1 << TIME_NEAR_SHIFT) #define TIME_NEAR (1 << TIME_NEAR_SHIFT)
#define TIME_LEVEL_SHIFT 6 #define TIME_LEVEL_SHIFT 6
@@ -45,7 +43,7 @@ struct link_list {
struct timer { struct timer {
struct link_list near[TIME_NEAR]; struct link_list near[TIME_NEAR];
struct link_list t[4][TIME_LEVEL]; struct link_list t[4][TIME_LEVEL];
int lock; struct spinlock lock;
uint32_t time; uint32_t time;
uint32_t current; uint32_t current;
uint32_t starttime; uint32_t starttime;
@@ -97,12 +95,12 @@ timer_add(struct timer *T,void *arg,size_t sz,int time) {
struct timer_node *node = (struct timer_node *)skynet_malloc(sizeof(*node)+sz); struct timer_node *node = (struct timer_node *)skynet_malloc(sizeof(*node)+sz);
memcpy(node+1,arg,sz); memcpy(node+1,arg,sz);
LOCK(T); SPIN_LOCK(T);
node->expire=time+T->time; node->expire=time+T->time;
add_node(T,node); add_node(T,node);
UNLOCK(T); SPIN_UNLOCK(T);
} }
static void static void
@@ -146,7 +144,7 @@ dispatch_list(struct timer_node *current) {
message.source = 0; message.source = 0;
message.session = event->session; message.session = event->session;
message.data = NULL; message.data = NULL;
message.sz = PTYPE_RESPONSE << HANDLE_REMOTE_SHIFT; message.sz = (size_t)PTYPE_RESPONSE << MESSAGE_TYPE_SHIFT;
skynet_context_push(event->handle, &message); skynet_context_push(event->handle, &message);
@@ -162,16 +160,16 @@ timer_execute(struct timer *T) {
while (T->near[idx].head.next) { while (T->near[idx].head.next) {
struct timer_node *current = link_clear(&T->near[idx]); struct timer_node *current = link_clear(&T->near[idx]);
UNLOCK(T); SPIN_UNLOCK(T);
// dispatch_list don't need lock T // dispatch_list don't need lock T
dispatch_list(current); dispatch_list(current);
LOCK(T); SPIN_LOCK(T);
} }
} }
static void static void
timer_update(struct timer *T) { timer_update(struct timer *T) {
LOCK(T); SPIN_LOCK(T);
// try to dispatch timeout 0 (rare condition) // try to dispatch timeout 0 (rare condition)
timer_execute(T); timer_execute(T);
@@ -181,7 +179,7 @@ timer_update(struct timer *T) {
timer_execute(T); timer_execute(T);
UNLOCK(T); SPIN_UNLOCK(T);
} }
static struct timer * static struct timer *
@@ -201,7 +199,8 @@ timer_create_timer() {
} }
} }
r->lock = 0; SPIN_INIT(r)
r->current = 0; r->current = 0;
return r; return r;
@@ -214,7 +213,7 @@ skynet_timeout(uint32_t handle, int time, int session) {
message.source = 0; message.source = 0;
message.session = session; message.session = session;
message.data = NULL; message.data = NULL;
message.sz = PTYPE_RESPONSE << HANDLE_REMOTE_SHIFT; message.sz = (size_t)PTYPE_RESPONSE << MESSAGE_TYPE_SHIFT;
if (skynet_context_push(handle, &message)) { if (skynet_context_push(handle, &message)) {
return -1; return -1;

View File

@@ -2,6 +2,7 @@
#include "socket_server.h" #include "socket_server.h"
#include "socket_poll.h" #include "socket_poll.h"
#include "atomic.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
@@ -237,13 +238,13 @@ static int
reserve_id(struct socket_server *ss) { reserve_id(struct socket_server *ss) {
int i; int i;
for (i=0;i<MAX_SOCKET;i++) { for (i=0;i<MAX_SOCKET;i++) {
int id = __sync_add_and_fetch(&(ss->alloc_id), 1); int id = ATOM_INC(&(ss->alloc_id));
if (id < 0) { if (id < 0) {
id = __sync_and_and_fetch(&(ss->alloc_id), 0x7fffffff); id = ATOM_AND(&(ss->alloc_id), 0x7fffffff);
} }
struct socket *s = &ss->slot[HASH_ID(id)]; struct socket *s = &ss->slot[HASH_ID(id)];
if (s->type == SOCKET_TYPE_INVALID) { if (s->type == SOCKET_TYPE_INVALID) {
if (__sync_bool_compare_and_swap(&s->type, SOCKET_TYPE_INVALID, SOCKET_TYPE_RESERVE)) { if (ATOM_CAS(&s->type, SOCKET_TYPE_INVALID, SOCKET_TYPE_RESERVE)) {
s->id = id; s->id = id;
s->fd = -1; s->fd = -1;
return id; return id;
@@ -1265,7 +1266,7 @@ send_request(struct socket_server *ss, struct request_package *request, char typ
static int static int
open_request(struct socket_server *ss, struct request_package *req, uintptr_t opaque, const char *addr, int port) { open_request(struct socket_server *ss, struct request_package *req, uintptr_t opaque, const char *addr, int port) {
int len = strlen(addr); int len = strlen(addr);
if (len + sizeof(req->u.open) > 256) { if (len + sizeof(req->u.open) >= 256) {
fprintf(stderr, "socket-server : Invalid addr %s.\n",addr); fprintf(stderr, "socket-server : Invalid addr %s.\n",addr);
return -1; return -1;
} }

77
skynet-src/spinlock.h Normal file
View File

@@ -0,0 +1,77 @@
#ifndef SKYNET_SPINLOCK_H
#define SKYNET_SPINLOCK_H
#define SPIN_INIT(q) spinlock_init(&(q)->lock);
#define SPIN_LOCK(q) spinlock_lock(&(q)->lock);
#define SPIN_UNLOCK(q) spinlock_unlock(&(q)->lock);
#define SPIN_DESTROY(q) spinlock_destroy(&(q)->lock);
#ifndef USE_PTHREAD_LOCK
struct spinlock {
int lock;
};
static inline void
spinlock_init(struct spinlock *lock) {
lock->lock = 0;
}
static inline void
spinlock_lock(struct spinlock *lock) {
while (__sync_lock_test_and_set(&lock->lock,1)) {}
}
static inline int
spinlock_trylock(struct spinlock *lock) {
return __sync_lock_test_and_set(&lock->lock,1) == 0;
}
static inline void
spinlock_unlock(struct spinlock *lock) {
__sync_lock_release(&lock->lock);
}
static inline void
spinlock_destroy(struct spinlock *lock) {
}
#else
#include <pthread.h>
// we use mutex instead of spinlock for some reason
// you can also replace to pthread_spinlock
struct spinlock {
pthread_mutex_t lock;
};
static inline void
spinlock_init(struct spinlock *lock) {
pthread_mutex_init(&lock->lock, NULL);
}
static inline void
spinlock_lock(struct spinlock *lock) {
pthread_mutex_lock(&lock->lock);
}
static inline int
spinlock_trylock(struct spinlock *lock) {
return pthread_mutex_trylock(&lock->lock) == 0;
}
static inline void
spinlock_unlock(struct spinlock *lock) {
pthread_mutex_unlock(&lock->lock);
}
static inline void
spinlock_destroy(struct spinlock *lock) {
pthread_mutex_destroy(&lock->lock);
}
#endif
#endif