Compare commits

...

290 Commits

Author SHA1 Message Date
Cloud Wu
6a54fe8293 1.0.0 rc4 2016-06-13 15:13:17 +08:00
Cloud Wu
2020ce3c9c update jemalloc to 4.2.1 2016-06-13 15:08:33 +08:00
云风
2557559d5c Merge pull request #512 from cloudwu/createindex
add createindexes , for detail see pr #511
2016-06-13 13:12:57 +08:00
Cloud Wu
bb0143e476 add some assert 2016-06-13 12:29:01 +08:00
Cloud Wu
fd2c814fe0 default key ascending 2016-06-13 12:13:02 +08:00
Cloud Wu
bd3d9b70ec change arg name 2016-06-13 12:05:52 +08:00
Cloud Wu
ee1a218870 typo 2016-06-13 12:01:54 +08:00
Cloud Wu
84ee3da79a add mongo.createIndexs, and fix the bug in old API createIndex. For detail, see PR #511 2016-06-13 11:55:31 +08:00
云风
fdee7de36d Merge pull request #509 from dpull/master
重新设计debug.lua接口
2016-06-12 16:41:18 +08:00
dpull
bf5b74b6ca 重新设计debug.lua接口 2016-06-12 16:29:47 +08:00
Cloud Wu
d9b0347741 don't close fd twice 2016-06-12 15:07:56 +08:00
Cloud Wu
9546537256 debug console support simple http 2016-06-12 14:51:18 +08:00
Cloud Wu
f84fe84b96 update userlog 2016-06-12 13:48:53 +08:00
Cloud Wu
ea9bc53261 reopen log file when recv signal HUP 2016-06-12 13:40:23 +08:00
Cloud Wu
0edb839c95 Lua 5.3.3 released 2016-06-07 09:43:43 +08:00
Cloud Wu
b8bb327f98 make coroutine_pool weak would be better 2016-06-06 16:23:39 +08:00
cloudwu
27d69334ee Merge pull request #506 from rickone/master
Update socketchannel.lua
2016-06-05 01:07:42 +08:00
rickone
838e63ab62 Update socketchannel.lua
request的时候可能会连接失败,这时raise的不是socket_error,上层处理不太统一。
2016-06-04 16:26:07 +08:00
Cloud Wu
ba264700dc update jemalloc to 4.2.0 2016-05-31 09:36:21 +08:00
Cloud Wu
e00ad7ab79 update to lua 5.3.3 rc3 2016-05-31 09:30:21 +08:00
Cloud Wu
de176b735f update to lua 5.3.3 rc2 2016-05-19 13:16:19 +08:00
cloudwu
cc3e985834 Merge pull request #502 from pigparadise/cloudwu
lua_bson的encode方法增加对有自定义__pairs的table的支持
2016-05-19 13:19:21 +08:00
LiuYang
3b5f45eea2 lua_bson的encode方法增加对有自定义__pairs的table的支持 2016-05-19 13:10:33 +08:00
cloudwu
c3056b04c1 Merge pull request #498 from asanosoyokaze/patch-1
add vararg for INFO debug console command
2016-05-16 19:35:02 +08:00
David Feng
58755a6772 add vararg for INFO debug console command 2016-05-16 18:57:40 +08:00
Cloud Wu
1cf976c4e4 add debug console command : ping 2016-05-13 09:46:44 +08:00
Cloud Wu
5be836527c bugfix issue #494 2016-05-11 22:02:10 +08:00
Cloud Wu
e9f397945d bugfix issue #494 2016-05-10 16:59:34 +08:00
Cloud Wu
78df0b8161 refine code 2016-05-09 19:16:29 +08:00
cloudwu
db17245005 Merge pull request #493 from chenkete/master
修复redis auth操作没有进行compose_message的bug,该bug导致skynet连接twemproxy时,auth失败
2016-05-09 19:17:56 +08:00
chenkete
4edb586077 修复redis auth操作没有进行compose_message的bug,该bug导致skynet连接twemproxy时,auth失败 2016-05-09 17:16:37 +08:00
Cloud Wu
ed1a8313f4 1.0.0 rc3 2016-05-09 10:06:32 +08:00
Cloud Wu
c450b7b5d7 update jemaloc to 4.1.1 2016-05-09 09:56:30 +08:00
Cloud Wu
56846b7dda new script to check deadloop service 2016-05-09 09:47:01 +08:00
Cloud Wu
fb232cc43e update lua to 5.3.3 rc1 2016-05-09 09:45:40 +08:00
Cloud Wu
a5c79cc4bd move skynet.memlimit from skynet.manager to skynet 2016-05-07 09:23:01 +08:00
Cloud Wu
4b96ade660 support sandbox memory limit 2016-05-06 23:40:44 +08:00
Cloud Wu
76d1e6fa1f memory warning 2016-05-06 20:37:51 +08:00
Cloud Wu
a6299a0748 optimize skynet.error 2016-05-06 20:10:11 +08:00
Cloud Wu
6cc558bb82 output Exit when new service exit 2016-05-06 19:45:50 +08:00
Cloud Wu
84b08bf286 detect console fd closed 2016-05-06 19:37:16 +08:00
Cloud Wu
4ada09b93c add pcall in launcher 2016-05-06 14:06:38 +08:00
Cloud Wu
2862568eca typo in history 2016-04-29 16:25:12 +08:00
cloudwu
ed2e16a346 Merge pull request #491 from asanosoyokaze/patch-go
skynet.pcall support vararg; sharedata loader can use custom args
2016-04-27 21:44:59 +08:00
David Feng
45d46b9072 skynet.pcall support vararg; sharedata loader can use custom args 2016-04-27 20:53:05 +08:00
Cloud Wu
4924c6d30b Merge branch 'master' of github.com:cloudwu/skynet 2016-04-20 22:35:29 +08:00
Cloud Wu
6b2eb80188 fix #487 2016-04-20 22:35:01 +08:00
cloudwu
298e4baf0e Merge pull request #485 from dpull/patch-1
给dbgcmd增加扩展性
2016-04-20 10:24:54 +08:00
Cloud Wu
c5fb93823a update sproto, fix bug in sproto.default 2016-04-20 10:11:55 +08:00
Acai
f238113677 给dbgcmd增加扩展性
我们项目增加了一个dbgcmd的指令,主要用于热更新,但在升级skynet版本时,需要记得合并这个差异,感觉挺挫的。

但现有的debug.lua并不利于扩展,于是呢,我想通过给debug.lua增加一个upvalue来解决这个问题。

其实也是解决的挺挫的 :)
2016-04-19 21:11:31 +08:00
Cloud Wu
f56d777cc2 for compatible 2016-04-18 12:05:46 +08:00
Cloud Wu
b124d4c1b8 skynet.getenv can return empty string 2016-04-18 11:55:39 +08:00
cloudwu
4fe098713f Merge pull request #483 from t0350/master
bugfix, error when use lua apicheck
2016-04-08 10:34:45 +08:00
caijietao
146f8ea09d bugfix, error when use lua apicheck 2016-04-08 10:29:34 +08:00
Cloud Wu
69b5bd8c13 update sproto. support encode empty table 2016-04-07 10:12:30 +08:00
cloudwu
dd7e962c94 Merge pull request #480 from rickone/master
Update redis.lua
2016-04-01 14:33:10 +08:00
rickone
5332021086 Update redis.lua
exec执行时其中一条出错,看不到错误信息
2016-04-01 12:39:09 +08:00
Cloud Wu
8de3149485 request global name from master, see issue #476 2016-04-01 10:22:57 +08:00
cloudwu
e3fee604e1 Merge pull request #478 from xjdrew/skynet_init
skynet.init按照顺序初始化
2016-03-31 17:51:29 +08:00
xjdrew
dd152fc910 skynet.init按照顺序初始化 2016-03-31 17:33:47 +08:00
Cloud Wu
c4b45acae3 sproto: check args 2016-03-29 12:34:55 +08:00
cloudwu
cf50a582f2 Merge pull request #474 from felixonmars/patch-1
Improve some English in README
2016-03-24 17:53:00 +08:00
Felix Yan
ca5e855c34 Improve some English in README 2016-03-24 17:48:43 +08:00
Cloud Wu
13d1d9fc9d update jemalloc to 4.1.0 2016-03-24 16:29:00 +08:00
Cloud Wu
242ff32bca lua 5.3.2 bugfix 2/3 2016-03-24 16:19:06 +08:00
cloudwu
ba451c1cd2 Merge pull request #465 from mrvon/master
skynet.coroutine
2016-03-11 15:28:56 +08:00
dennis
e5490522ce this line is useless 2016-03-09 17:50:33 +08:00
dennis
ae717c3e7d Merge remote-tracking branch 'upstream/master' 2016-03-09 17:48:16 +08:00
cloudwu
1a7df9108a Merge pull request #463 from great90/master
delete unused local variable
2016-03-08 11:34:25 +08:00
great90
7771e180ec delete unused local variable
delete unused local variable table "udp_socket"
2016-03-08 11:25:59 +08:00
great90
82bbb1c944 Merge pull request #3 from cloudwu/master
release rc2
2016-03-08 11:21:18 +08:00
Cloud Wu
cbf22ac9f3 release rc2 2016-03-07 11:46:30 +08:00
great90
bacaf10f1b Merge pull request #2 from cloudwu/master
update from cloudwu
2016-03-02 09:08:40 +08:00
Cloud Wu
8f7fa6a562 merge sproto 2016-02-25 14:40:24 +08:00
cloudwu
7b96eb28eb Merge pull request #455 from niuys/patch-2
error deal for query containing multi statement
2016-02-22 16:15:51 +08:00
snail
14ccf96eb0 error deal for query containing multi statement
A query may execute multi sql statements.If an error occurs for any sql, the result should return the error info.
2016-02-22 11:23:35 +08:00
dennis
6303886b8c Merge remote-tracking branch 'upstream/master' 2016-02-15 10:12:09 +08:00
Cloud Wu
ea8557296b fix issue #450 2016-02-13 19:20:07 +08:00
cloudwu
2a821fb62a Merge pull request #445 from DavidFeng/patch
fix
2016-01-27 13:55:14 +08:00
David Feng
d982009260 fix 2016-01-27 10:35:48 +08:00
cloudwu
a3f028ee3d Merge pull request #444 from DavidFeng/patch-1
修复调试模块调试结束后定时器没有取消的问题
2016-01-22 11:05:04 +08:00
David Feng
d34b092cdd remotedebug.lua call skynet.timeout() only in debug hook
定时器在debug结束后没有取消。
2016-01-22 10:28:03 +08:00
David Feng
77f4071191 remove unused local variables 2016-01-22 10:26:13 +08:00
cloudwu
653b29145d Merge pull request #442 from DavidFeng/patch-2
change socket.write to socketdriver.send
2016-01-20 22:05:23 +08:00
David Feng
96e0a4e3cc change socket.write to socketdriver.send
这样改过之后可以直接调试使用了gate服务的模块。
因为gate服务注册了socket类型的消息,所以不能和socket模块一块使用;而debug模块只使用到了socket模块的write函数,所以这样修改后对debug的功能并没有影响,但改过之后就可以调试gate服务了。
2016-01-20 19:24:58 +08:00
Cloud Wu
1da92850a0 bugfix: dispatch local global message queue 2016-01-19 17:14:52 +08:00
Cloud Wu
9747cf9aee don't assert here 2016-01-19 16:16:18 +08:00
Cloud Wu
7f45b3fd10 correct maxsz 2016-01-13 13:13:31 +08:00
cloudwu
217ab47577 Merge pull request #435 from niuys/patch-1
reduce needless 'add_string' call
2016-01-11 15:56:52 +08:00
snail
532f47444b reduce needless 'add_string' call
Short strings in lua proto are reused most of the time. The string in SSM may be added by one service and used by other service,  there is no need to call `add_string`,which will call 'new_string' first.
2016-01-11 15:06:51 +08:00
Cloud Wu
24f9ee1560 work thread for channel may not create if you never connect 2016-01-08 18:34:45 +08:00
Cloud Wu
d7a76c7c72 If no content-length, read all. see issue #431 2016-01-07 16:01:17 +08:00
Cloud Wu
c175d66e23 remove unused function 2016-01-06 16:55:15 +08:00
dennis
30cbcfd013 Merge remote-tracking branch 'upstream/master' 2016-01-06 15:57:42 +08:00
Cloud Wu
05003e3e2a sproto.attach also need ud 2016-01-05 17:51:48 +08:00
Cloud Wu
64c2cb1b51 sproto dispatch support ud 2016-01-05 16:06:20 +08:00
cloudwu
7f0e4eac8a Merge pull request #428 from fztcjjl/master
fix comment error
2016-01-04 16:07:50 +08:00
Cloud Wu
141a4d0992 lua 5.3.2 bugfix,see http://lua-users.org/lists/lua-l/2016-01/msg00000.html 2016-01-04 16:01:03 +08:00
fztcjjl
645ce72e7e fix comment error 2016-01-04 14:55:28 +08:00
cloudwu
fca4d67a43 Merge pull request #425 from DeanHH/patch-1
Update skynet_mq.c
2016-01-01 00:08:23 +08:00
DeanHH
014cbb9676 Update skynet_mq.c
Comment error:-)
2015-12-31 17:31:08 +08:00
Dennis
a39e822184 Merge pull request #1 from cloudwu/master
update from origin
2015-12-30 09:51:58 +08:00
Cloud Wu
a3a7d129ab V1.0.0 RC 2015-12-28 13:55:01 +08:00
cloudwu
2e69370594 Merge pull request #418 from m2q1n9/master
fix a debug_console error
2015-12-28 00:15:29 +08:00
m2q1n9
bcdfcde72f fix code indent 2015-12-27 22:38:58 +08:00
Cloud Wu
0c4ea81709 EAGAIN and EWOULDBLOCK may be not the same value, see issue #420 2015-12-27 19:31:32 +08:00
m2q1n9
b9ad559992 fix a debug_console error 2015-12-25 17:24:50 +08:00
Cloud Wu
f0ac66787e socket channel connect should wait for last closing 2015-12-23 20:22:46 +08:00
Cloud Wu
5a1b2e51f7 exit dispatch_by_order when close channel 2015-12-23 19:55:42 +08:00
Cloud Wu
7acf6d8767 remove unused varargs 2015-12-18 23:28:55 +08:00
Cloud Wu
20610723a1 add debug api to show current service c memory 2015-12-17 22:13:51 +08:00
Cloud Wu
9d6bde01a3 profile support skynet coroutine 2015-12-17 20:41:02 +08:00
Cloud Wu
4a80a75fd6 skynet.coroutine.status may return blocked 2015-12-17 17:11:54 +08:00
Cloud Wu
872491e968 Add skynet.coroutine module 2015-12-17 16:25:24 +08:00
cloudwu
41252e8c21 Merge pull request #414 from DavidFeng/patch-1
fix typo
2015-12-17 16:16:38 +08:00
David Feng
a9fc577560 fix typo
fix a little mistake
2015-12-17 15:53:39 +08:00
Cloud Wu
4f8427a23f close socket when sp_add failed 2015-12-17 10:04:38 +08:00
cloudwu
8ff5bcb372 Merge pull request #410 from kezhuw/bugfix_dangling_c_pointer_to_lua_string
Fix dangling c pointer to lua string value
2015-12-15 00:56:40 +08:00
Kezhu Wang
bfe8eeb4b3 Fix dangling c pointer to lua string value
Lua string object referenced by C pointer from lua_tolstring() was
removed from stack by lua_settop(L,0).

Lua 5.3 Reference Manual says:

> Because Lua has garbage collection, there is no guarantee that the
> pointer returned by lua_tolstring will be valid after the
> corresponding Lua value is removed from the stack.

That is it.

Introduced in commit 9937081854.
2015-12-14 16:16:37 +08:00
Cloud Wu
ccb9cdbc9d update sproto schema 2015-12-14 12:25:26 +08:00
cloudwu
4006faac29 Merge pull request #407 from linse073/patch-3
loginserver.lua中的launch_slave的lua消息处理函数的return问题
2015-12-08 13:31:16 +08:00
linse073
03617f23a1 loginserver.lua中的launch_slave的lua消息处理函数的return问题
之前可能是我没有表述清楚,这两个return我猜想是不是手误加上去的,因为之前都没有见过需要在消息处理函数里面return skynet.ret调用的结果,实际去掉后测试也是没有问题的,和是不是两次pcall的调用应该是没有关系的。
2015-12-07 21:00:19 +08:00
Cloud Wu
d4d188541f add socket.close_fd 2015-12-06 16:48:28 +08:00
Cloud Wu
3a2766dd0e return results, see pr #403 2015-12-04 10:47:30 +08:00
Cloud Wu
1431f55d28 update readme 2015-12-03 15:37:43 +08:00
cloudwu
22c0d3ab73 Merge pull request #396 from niuys/patch-6
close file handle clearly
2015-12-01 21:52:38 +08:00
snail
940a7ac58c close file handle clearly
Although 'f'  would be closed after collected, maybe it's better to close it clearly
2015-12-01 20:17:03 +08:00
Cloud Wu
05605e62a9 core.querytype doesn't raise error, see issue #395 2015-12-01 17:09:32 +08:00
Cloud Wu
3a527f0a66 update lua to 5.3.2 2015-11-30 20:31:56 +08:00
Cloud Wu
e47a4921fa bugfix. remote publish first, see issue #391 2015-11-27 18:13:50 +08:00
Cloud Wu
c180036bed use async dns resolve in httpc, and dns resolve cache by ttl. see about issue #253 2015-11-25 13:09:41 +08:00
Cloud Wu
d35388581f big number in sproto 2015-11-23 16:12:57 +08:00
Cloud Wu
2c3f3ac3c6 more sproto wire protocol examples 2015-11-23 12:47:29 +08:00
cloudwu
09670ee733 Merge pull request #383 from DavidFeng/patch-1
fix typo
2015-11-22 19:39:30 +08:00
David Feng
fbbda08bb2 fix typo 2015-11-21 15:36:25 +08:00
Cloud Wu
0f454fe248 Merge branch 'master' of github.com:cloudwu/skynet 2015-11-19 22:51:55 +08:00
Cloud Wu
91c720ad6f add assert for socket fd reuse 2015-11-19 22:51:43 +08:00
Cloud Wu
3335ea11d7 dummy luaS_expandshr 2015-11-19 21:02:46 +08:00
Cloud Wu
8d83881808 use CLOCK_MONOTONIC maybe better 2015-11-18 10:19:51 +08:00
Cloud Wu
f4437948ca fix Issue #377 2015-11-16 22:42:44 +08:00
Cloud Wu
2252409eaa add skynet_now() for 64bit time 2015-11-16 19:48:38 +08:00
Cloud Wu
87bc0815f6 bugfix: add lightuserdata 2015-11-13 17:28:02 +08:00
Cloud Wu
30859a1244 make cache 2015-11-13 13:25:33 +08:00
Cloud Wu
107be7ee8c rewrite redis driver , avoid table.concat 2015-11-13 12:30:46 +08:00
Cloud Wu
86d9d52308 Merge branch 'gitfancode-master' 2015-11-13 11:05:09 +08:00
Cloud Wu
9982cb6652 Merge branch 'master' of https://github.com/gitfancode/skynet into gitfancode-master 2015-11-13 11:04:51 +08:00
Cloud Wu
ce50c47c2b socket.send support strings table 2015-11-13 11:04:02 +08:00
xiefan
34d9b5555d reds pipeline v2(support function as pipeline params)
fix a bug & add function as pipeline params
2015-11-13 08:16:47 +08:00
xiefan
85062632bb Merge remote-tracking branch 'cloudwu/master' 2015-11-13 08:14:49 +08:00
xiefan
d2396f9d20 Revert "redis pipeline"
This reverts commit 471aecd708.
2015-11-13 08:10:33 +08:00
xiefan
471aecd708 redis pipeline
redis pipeline
2015-11-12 20:45:19 +08:00
Cloud Wu
d283d7fcaa check close return value 2015-11-12 18:34:50 +08:00
Cloud Wu
b72f0921d4 remove unused local function 2015-11-12 16:21:44 +08:00
Cloud Wu
6be649c5cb Merge branch 'master' of github.com:cloudwu/skynet 2015-11-12 15:42:05 +08:00
Cloud Wu
5edde990d6 bugfix: skynet.fork use table.pack to pack table 2015-11-12 15:41:41 +08:00
cloudwu
77813b446c Merge pull request #374 from huanzai/master
Update lua-netpack.c
2015-11-12 12:08:49 +08:00
huanzai
7138144a68 Update lua-netpack.c
当长度等于0x10000时,read_size读出的值为0
2015-11-12 11:15:50 +08:00
Cloud Wu
fa729d593b lua alloc use raw allocator 2015-11-12 10:53:14 +08:00
Cloud Wu
9f3baf2ee3 fix issue #372 2015-11-11 15:06:10 +08:00
Cloud Wu
7521fe0530 socket.shutdown abandon unsend buffer now, see issue #371 2015-11-11 10:44:50 +08:00
Cloud Wu
c28ae25c70 release 1.0.0 beta 2015-11-10 12:19:04 +08:00
Cloud Wu
9382454bcd update jemalloc to 4.0.4 2015-11-10 12:12:42 +08:00
Cloud Wu
d83fc0c00f sproto support all integer representation 2015-11-02 19:50:51 +08:00
云风
31340cf346 Merge pull request #369 from kexiao8/patch-1
repeated “struct table" of line 19
2015-11-01 19:27:16 +08:00
kexiao8
d1b26a60eb repeated “struct table" of line 19 2015-10-31 17:43:33 +08:00
Cloud Wu
ac4d51b779 bugfix issue #368 2015-10-29 11:22:26 +08:00
云风
0efab15f45 Merge pull request #366 from fztcjjl/master
add a callback for mysql auth
2015-10-28 20:49:44 +08:00
Cloud Wu
0199ba1382 sharedata support filename string 2015-10-28 17:37:06 +08:00
Cloud Wu
935863f434 report connect failed reason 2015-10-28 16:12:01 +08:00
Cloud Wu
13d920e185 body may contain ascii 0, see issue #365 2015-10-27 15:40:15 +08:00
Cloud Wu
a4af35f442 fix issue #364 2015-10-27 14:00:25 +08:00
云风
b1060478f7 Merge pull request #363 from nbwk1988/master
add hmac_md5
2015-10-27 11:39:55 +08:00
nbwk1988
1999a03ff7 优化hmac 2015-10-27 10:44:23 +08:00
nbwk1988
f5740e00b1 add hmac_md5
add hmac_md5
2015-10-26 16:12:10 +08:00
fztcjjl
1653b3213a add a callback for mysql auth 2015-10-24 06:37:25 +08:00
fztcjjl
fe3954fb04 add a callback for mysql auth 2015-10-24 01:35:16 +08:00
great90
716ecccaed Merge pull request #1 from cloudwu/master
update skynet
2015-10-23 14:33:54 +08:00
Cloud Wu
26cbebfcfd verify callback overflow 2015-10-21 12:58:57 +08:00
Cloud Wu
2d27df6f46 change name 2015-10-15 14:08:01 +08:00
Cloud Wu
bab91a3067 bugfix: don't use global wait_response 2015-10-15 14:01:50 +08:00
Cloud Wu
c1c032eab4 bugfix: socketchannel order mode may blocked. (used by redis driver) 2015-10-14 20:12:30 +08:00
Cloud Wu
7486e53232 avoid circular reference while encodeing bson 2015-10-14 15:44:09 +08:00
Cloud Wu
9aaa35ef14 avoid lua stack overflow 2015-10-14 15:24:51 +08:00
Cloud Wu
d2f2e299d5 call socket.abandon while auth error, see issue #355 2015-10-12 14:40:42 +08:00
Cloud Wu
d7e4e43a1b use spinlock macro 2015-10-12 13:07:09 +08:00
Cloud Wu
878110f9f7 add codecache.mode() 2015-10-12 12:29:19 +08:00
云风
60692e58dc Merge pull request #354 from xjdrew/bugfix_warning
bugfix: remove Wformat warning
2015-10-10 15:55:14 +03:00
xjdrew
515326dadc bugfix: remove Wformat warning 2015-10-10 18:39:42 +08:00
云风
4ee59edc44 Merge pull request #352 from xjdrew/gate
gate: application could control when to start receiving data
2015-10-09 05:05:33 +03:00
xjdrew
8dd9923cf6 gate: application could control when to start receiving data 2015-10-08 16:55:29 +08:00
Cloud Wu
8c1011c503 Add sproto:exist_type and sproto:exist_proto 2015-10-08 15:30:15 +08:00
Cloud Wu
8924b86ad7 check empty group, See pr #351 2015-10-08 15:15:35 +08:00
云风
14bc029864 Merge pull request #348 from xjdrew/unused_code
removte unused code
2015-10-05 05:17:29 +03:00
Cloud Wu
79e73d907e add target update3rd 2015-10-05 10:09:22 +08:00
Cloud Wu
3a06dcf534 update jemalloc to 4.0.3 2015-10-05 10:05:36 +08:00
Cloud Wu
97fd5053c9 update lpeg to 1.0.0 2015-10-05 09:56:12 +08:00
云风
3a3159d429 Merge pull request #347 from zhengfangxin/master
delete two clear_closed_event call
2015-10-05 04:51:22 +03:00
xjdrew
97ff6afc84 removte unused code 2015-09-29 17:29:33 +08:00
zhengfangxin
cb9feb34bd delete two no need call clear_closed_event 2015-09-26 21:03:38 +08:00
云风
48f79fe6d4 Merge pull request #345 from great90/master
从check_wsz发送的SKYNET_SOCKET_TYPE_WARNING消息会assert失败,导致coredump
2015-09-22 09:37:54 +08:00
great90
63942496fd 从check_wsz发送的SKYNET_SOCKET_TYPE_WARNING消息会assert失败,导致coredump 2015-09-21 23:50:18 +08:00
云风
bf9fc0c7e9 Merge pull request #343 from bingo235/master
gateserver close
2015-09-21 12:59:30 +08:00
bingo
325452a242 Signed-off-by: bingo <heidan725@qq.com> 2015-09-21 11:21:36 +08:00
Cloud Wu
752a501f68 bugfix: remove DONTCOPY tag from type 2015-09-21 10:40:09 +08:00
Cloud Wu
008351573a raise error when DH param is 0 2015-09-18 14:13:16 +08:00
Cloud Wu
00dbf6e996 DH key exchange can't be 0 , avoid attack 2015-09-18 14:10:12 +08:00
Cloud Wu
8cc5638f14 Merge branch 'master' of github.com:cloudwu/skynet 2015-09-15 14:52:44 +08:00
Cloud Wu
b8f419eb69 more error message for socket, and close listen socket when reach limit of open files. See Issue #339 2015-09-15 14:52:30 +08:00
云风
8f284e2d7f Merge pull request #340 from sanikoyes/Pr-missing-exitshr
add missing luaS_exitshr call
2015-09-14 18:05:56 +08:00
sanikoyes
846d55eaef add missing luaS_exitshr call 2015-09-14 18:03:04 +08:00
Cloud Wu
6c33f7bc44 see pr #332 2015-09-04 12:14:09 +08:00
Cloud Wu
7797de85b4 bugfix: See PR #332 2015-08-31 16:36:57 +08:00
云风
7ec452c782 Merge pull request #332 from niuys/patch-4
'response' not released
2015-08-30 22:08:37 +08:00
snail
7f9c3c8c9a local function is better
local function is the same as " local a; a = function"
2015-08-30 18:17:41 +08:00
snail
bad3472124 'response' not released
'response' not released after src service died, and defined error.
2015-08-30 16:47:34 +08:00
Cloud Wu
4f665d2469 init global string table, See issue #331 2015-08-30 12:13:23 +08:00
Cloud Wu
633e5fbe32 fix issue #331 2015-08-29 15:24:24 +08:00
云风
c1c5cd39e5 Merge pull request #328 from cloudwu/shrtbl
global shared string table
2015-08-27 21:16:47 +08:00
云风
03f5da6bb5 Merge pull request #329 from niuys/patch-3
uncomplete buffer not free
2015-08-27 18:15:12 +08:00
snail
1bfddda435 uncomplete buffer not free
'uncomplete' buffer not freed in clear
2015-08-27 18:04:56 +08:00
Cloud Wu
9b0e496afe minor amend 2015-08-27 13:49:31 +08:00
Cloud Wu
010d1c1d4f avoid dead loop 2015-08-24 11:50:40 +08:00
Cloud Wu
eb587c63d3 fix issue #327 2015-08-21 19:42:09 +08:00
Cloud Wu
bb6d5d826e add TString struct size 2015-08-21 15:59:51 +08:00
Cloud Wu
9acce94464 disable lua apicheck 2015-08-21 13:55:43 +08:00
Cloud Wu
c0862d8445 add global share string table 2015-08-21 13:52:04 +08:00
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
170 changed files with 5929 additions and 2573 deletions

View File

@@ -1,4 +1,10 @@
HISTORY for LPeg 0.12
HISTORY for LPeg 1.0
* Changes from version 0.12 to 1.0
---------------------------------
+ group "names" can be any Lua value
+ some bugs fixed
+ other small improvements
* Changes from version 0.11 to 0.12
---------------------------------

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpcap.c,v 1.5 2014/12/12 16:58:47 roberto Exp $
** $Id: lpcap.c,v 1.6 2015/06/15 16:09:57 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
@@ -126,7 +126,7 @@ static Capture *findback (CapState *cs, Capture *cap) {
continue; /* opening an enclosing capture: skip and get previous */
if (captype(cap) == Cgroup) {
getfromktable(cs, cap->idx); /* get group name */
if (lua_equal(L, -2, -1)) { /* right group? */
if (lp_equal(L, -2, -1)) { /* right group? */
lua_pop(L, 2); /* remove reference name and group name */
return cap;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpcap.h,v 1.1 2013/03/21 20:25:12 roberto Exp $
** $Id: lpcap.h,v 1.2 2015/02/27 17:13:17 roberto Exp $
*/
#if !defined(lpcap_h)
@@ -18,7 +18,7 @@ typedef enum CapKind {
typedef struct Capture {
const char *s; /* subject position */
short idx; /* extra info about capture (group name, arg index, etc.) */
unsigned short idx; /* extra info (group name, arg index, etc.) */
byte kind; /* kind of capture */
byte siz; /* size of full capture + 1 (0 = not a full capture) */
} Capture;

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpcode.c,v 1.21 2014/12/12 17:01:29 roberto Exp $
** $Id: lpcode.c,v 1.23 2015/06/12 18:36:47 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
@@ -431,11 +431,11 @@ typedef struct CompileState {
/*
** code generation is recursive; 'opt' indicates that the code is
** being generated under a 'IChoice' operator jumping to its end
** (that is, the match is "optional").
** 'tt' points to a previous test protecting this code. 'fl' is
** the follow set of the pattern.
** code generation is recursive; 'opt' indicates that the code is being
** generated as the last thing inside an optional pattern (so, if that
** code is optional too, it can reuse the 'IChoice' already in place for
** the outer pattern). 'tt' points to a previous test protecting this
** code (or NOINST). 'fl' is the follow set of the pattern.
*/
static void codegen (CompileState *compst, TTree *tree, int opt, int tt,
const Charset *fl);
@@ -638,13 +638,13 @@ static void codebehind (CompileState *compst, TTree *tree) {
/*
** Choice; optimizations:
** - when p1 is headfail
** - when first(p1) and first(p2) are disjoint; than
** - when p1 is headfail or
** when first(p1) and first(p2) are disjoint, than
** a character not in first(p1) cannot go to p1, and a character
** in first(p1) cannot go to p2 (at it is not in first(p2)).
** (The optimization is not valid if p1 accepts the empty string,
** as then there is no character at all...)
** - when p2 is empty and opt is true; a IPartialCommit can resuse
** - when p2 is empty and opt is true; a IPartialCommit can reuse
** the Choice already active in the stack.
*/
static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt,
@@ -671,7 +671,7 @@ static void codechoice (CompileState *compst, TTree *p1, TTree *p2, int opt,
}
else {
/* <p1 / p2> ==
test(fail(p1)) -> L1; choice L1; <p1>; commit L2; L1: <p2>; L2: */
test(first(p1)) -> L1; choice L1; <p1>; commit L2; L1: <p2>; L2: */
int pcommit;
int test = codetestset(compst, &cs1, e1);
int pchoice = addoffsetinst(compst, IChoice);
@@ -759,7 +759,7 @@ static void coderep (CompileState *compst, TTree *tree, int opt,
/* L1: test (fail(p1)) -> L2; <p>; jmp L1; L2: */
int jmp;
int test = codetestset(compst, &st, 0);
codegen(compst, tree, opt, test, fullset);
codegen(compst, tree, 0, test, fullset);
jmp = addoffsetinst(compst, IJmp);
jumptohere(compst, test);
jumptothere(compst, jmp, test);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpcode.h,v 1.6 2013/11/28 14:56:02 roberto Exp $
** $Id: lpcode.h,v 1.7 2015/06/12 18:24:45 roberto Exp $
*/
#if !defined(lpcode_h)
@@ -24,7 +24,15 @@ int sizei (const Instruction *i);
#define PEnullable 0
#define PEnofail 1
/*
** nofail(t) implies that 't' cannot fail with any input
*/
#define nofail(t) checkaux(t, PEnofail)
/*
** (not nullable(t)) implies 't' cannot match without consuming
** something
*/
#define nullable(t) checkaux(t, PEnullable)
#define fixedlen(t) fixedlenx(t, 0, 0)

View File

@@ -10,7 +10,7 @@
</head>
<body>
<!-- $Id: lpeg.html,v 1.72 2014/12/12 17:11:35 roberto Exp $ -->
<!-- $Id: lpeg.html,v 1.75 2015/09/28 17:17:41 roberto Exp $ -->
<div id="container">
@@ -22,7 +22,7 @@
</div>
<div id="product_name"><big><strong>LPeg</strong></big></div>
<div id="product_description">
Parsing Expression Grammars For Lua, version 0.12
Parsing Expression Grammars For Lua, version 1.0
</div>
</div> <!-- id="product" -->
@@ -195,13 +195,16 @@ Returns a string with the running version of LPeg.
<h3><a name="f-setstack"></a><code>lpeg.setmaxstack (max)</code></h3>
<p>
Sets the maximum size for the backtrack stack used by LPeg to
Sets a limit for the size of the backtrack stack used by LPeg to
track calls and choices.
(The default limit is 400.)
Most well-written patterns need little backtrack levels and
therefore you seldom need to change this maximum;
but a few useful patterns may need more space.
Before changing this maximum you should try to rewrite your
therefore you seldom need to change this limit;
before changing it you should try to rewrite your
pattern to avoid the need for extra space.
Nevertheless, a few useful patterns may overflow.
Also, with recursive grammars,
subjects with deep recursion may also need larger limits.
</p>
@@ -682,7 +685,8 @@ argument given in the call to <code>lpeg.match</code>.
Creates a <em>back capture</em>.
This pattern matches the empty string and
produces the values produced by the <em>most recent</em>
<a href="#cap-g">group capture</a> named <code>name</code>.
<a href="#cap-g">group capture</a> named <code>name</code>
(where <code>name</code> can be any Lua value).
</p>
<p>
@@ -762,7 +766,8 @@ Creates a <em>group capture</em>.
It groups all values returned by <code>patt</code>
into a single capture.
The group may be anonymous (if no name is given)
or named with the given name.
or named with the given name
(which can be any non-nil Lua value).
</p>
<p>
@@ -1375,13 +1380,13 @@ and the new term for each repetition.
<h2><a name="download"></a>Download</h2>
<p>LPeg
<a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-0.12.1.tar.gz">source code</a>.</p>
<a href="http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.0.tar.gz">source code</a>.</p>
<h2><a name="license">License</a></h2>
<p>
Copyright &copy; 2014 Lua.org, PUC-Rio.
Copyright &copy; 2007-2015 Lua.org, PUC-Rio.
</p>
<p>
Permission is hereby granted, free of charge,
@@ -1419,7 +1424,7 @@ THE SOFTWARE.
<div id="about">
<p><small>
$Id: lpeg.html,v 1.72 2014/12/12 17:11:35 roberto Exp $
$Id: lpeg.html,v 1.75 2015/09/28 17:17:41 roberto Exp $
</small></p>
</div> <!-- id="about" -->

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpprint.c,v 1.7 2013/04/12 16:29:49 roberto Exp $
** $Id: lpprint.c,v 1.9 2015/06/15 16:09:57 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
@@ -52,7 +52,7 @@ static void printjmp (const Instruction *op, const Instruction *p) {
}
static void printinst (const Instruction *op, const Instruction *p) {
void printinst (const Instruction *op, const Instruction *p) {
const char *const names[] = {
"any", "char", "set",
"testany", "testchar", "testset",
@@ -221,10 +221,10 @@ void printtree (TTree *tree, int ident) {
void printktable (lua_State *L, int idx) {
int n, i;
lua_getfenv(L, idx);
lua_getuservalue(L, idx);
if (lua_isnil(L, -1)) /* no ktable? */
return;
n = lua_objlen(L, -1);
n = lua_rawlen(L, -1);
printf("[");
for (i = 1; i <= n; i++) {
printf("%d = ", i);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpprint.h,v 1.1 2013/03/21 20:25:12 roberto Exp $
** $Id: lpprint.h,v 1.2 2015/06/12 18:18:08 roberto Exp $
*/
@@ -18,6 +18,7 @@ void printtree (TTree *tree, int ident);
void printktable (lua_State *L, int idx);
void printcharset (const byte *st);
void printcaplist (Capture *cap, Capture *limit);
void printinst (const Instruction *op, const Instruction *p);
#else

View File

@@ -1,5 +1,5 @@
/*
** $Id: lptree.c,v 1.13 2014/12/12 16:59:10 roberto Exp $
** $Id: lptree.c,v 1.21 2015/09/28 17:01:25 roberto Exp $
** Copyright 2013, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
@@ -126,6 +126,189 @@ static void finalfix (lua_State *L, int postable, TTree *g, TTree *t) {
}
/*
** {===================================================================
** KTable manipulation
**
** - The ktable of a pattern 'p' can be shared by other patterns that
** contain 'p' and no other constants. Because of this sharing, we
** should not add elements to a 'ktable' unless it was freshly created
** for the new pattern.
**
** - The maximum index in a ktable is USHRT_MAX, because trees and
** patterns use unsigned shorts to store those indices.
** ====================================================================
*/
/*
** Create a new 'ktable' to the pattern at the top of the stack.
*/
static void newktable (lua_State *L, int n) {
lua_createtable(L, n, 0); /* create a fresh table */
lua_setuservalue(L, -2); /* set it as 'ktable' for pattern */
}
/*
** Add element 'idx' to 'ktable' of pattern at the top of the stack;
** Return index of new element.
** If new element is nil, does not add it to table (as it would be
** useless) and returns 0, as ktable[0] is always nil.
*/
static int addtoktable (lua_State *L, int idx) {
if (lua_isnil(L, idx)) /* nil value? */
return 0;
else {
int n;
lua_getuservalue(L, -1); /* get ktable from pattern */
n = lua_rawlen(L, -1);
if (n >= USHRT_MAX)
luaL_error(L, "too many Lua values in pattern");
lua_pushvalue(L, idx); /* element to be added */
lua_rawseti(L, -2, ++n);
lua_pop(L, 1); /* remove 'ktable' */
return n;
}
}
/*
** Return the number of elements in the ktable at 'idx'.
** In Lua 5.2/5.3, default "environment" for patterns is nil, not
** a table. Treat it as an empty table. In Lua 5.1, assumes that
** the environment has no numeric indices (len == 0)
*/
static int ktablelen (lua_State *L, int idx) {
if (!lua_istable(L, idx)) return 0;
else return lua_rawlen(L, idx);
}
/*
** Concatentate the contents of table 'idx1' into table 'idx2'.
** (Assume that both indices are negative.)
** Return the original length of table 'idx2' (or 0, if no
** element was added, as there is no need to correct any index).
*/
static int concattable (lua_State *L, int idx1, int idx2) {
int i;
int n1 = ktablelen(L, idx1);
int n2 = ktablelen(L, idx2);
if (n1 + n2 > USHRT_MAX)
luaL_error(L, "too many Lua values in pattern");
if (n1 == 0) return 0; /* nothing to correct */
for (i = 1; i <= n1; i++) {
lua_rawgeti(L, idx1, i);
lua_rawseti(L, idx2 - 1, n2 + i); /* correct 'idx2' */
}
return n2;
}
/*
** When joining 'ktables', constants from one of the subpatterns must
** be renumbered; 'correctkeys' corrects their indices (adding 'n'
** to each of them)
*/
static void correctkeys (TTree *tree, int n) {
if (n == 0) return; /* no correction? */
tailcall:
switch (tree->tag) {
case TOpenCall: case TCall: case TRunTime: case TRule: {
if (tree->key > 0)
tree->key += n;
break;
}
case TCapture: {
if (tree->key > 0 && tree->cap != Carg && tree->cap != Cnum)
tree->key += n;
break;
}
default: break;
}
switch (numsiblings[tree->tag]) {
case 1: /* correctkeys(sib1(tree), n); */
tree = sib1(tree); goto tailcall;
case 2:
correctkeys(sib1(tree), n);
tree = sib2(tree); goto tailcall; /* correctkeys(sib2(tree), n); */
default: assert(numsiblings[tree->tag] == 0); break;
}
}
/*
** Join the ktables from p1 and p2 the ktable for the new pattern at the
** top of the stack, reusing them when possible.
*/
static void joinktables (lua_State *L, int p1, TTree *t2, int p2) {
int n1, n2;
lua_getuservalue(L, p1); /* get ktables */
lua_getuservalue(L, p2);
n1 = ktablelen(L, -2);
n2 = ktablelen(L, -1);
if (n1 == 0 && n2 == 0) /* are both tables empty? */
lua_pop(L, 2); /* nothing to be done; pop tables */
else if (n2 == 0 || lp_equal(L, -2, -1)) { /* 2nd table empty or equal? */
lua_pop(L, 1); /* pop 2nd table */
lua_setuservalue(L, -2); /* set 1st ktable into new pattern */
}
else if (n1 == 0) { /* first table is empty? */
lua_setuservalue(L, -3); /* set 2nd table into new pattern */
lua_pop(L, 1); /* pop 1st table */
}
else {
lua_createtable(L, n1 + n2, 0); /* create ktable for new pattern */
/* stack: new p; ktable p1; ktable p2; new ktable */
concattable(L, -3, -1); /* from p1 into new ktable */
concattable(L, -2, -1); /* from p2 into new ktable */
lua_setuservalue(L, -4); /* new ktable becomes 'p' environment */
lua_pop(L, 2); /* pop other ktables */
correctkeys(t2, n1); /* correction for indices from p2 */
}
}
/*
** copy 'ktable' of element 'idx' to new tree (on top of stack)
*/
static void copyktable (lua_State *L, int idx) {
lua_getuservalue(L, idx);
lua_setuservalue(L, -2);
}
/*
** merge 'ktable' from 'stree' at stack index 'idx' into 'ktable'
** from tree at the top of the stack, and correct corresponding
** tree.
*/
static void mergektable (lua_State *L, int idx, TTree *stree) {
int n;
lua_getuservalue(L, -1); /* get ktables */
lua_getuservalue(L, idx);
n = concattable(L, -1, -2);
lua_pop(L, 2); /* remove both ktables */
correctkeys(stree, n);
}
/*
** Create a new 'ktable' to the pattern at the top of the stack, adding
** all elements from pattern 'p' (if not 0) plus element 'idx' to it.
** Return index of new element.
*/
static int addtonewktable (lua_State *L, int p, int idx) {
newktable(L, 1);
if (p)
mergektable(L, p, NULL);
return addtoktable(L, idx);
}
/* }====================================================== */
/*
** {======================================================
** Tree generation
@@ -155,7 +338,7 @@ static Pattern *getpattern (lua_State *L, int idx) {
static int getsize (lua_State *L, int idx) {
return (lua_objlen(L, idx) - sizeof(Pattern)) / sizeof(TTree) + 1;
return (lua_rawlen(L, idx) - sizeof(Pattern)) / sizeof(TTree) + 1;
}
@@ -168,12 +351,16 @@ static TTree *gettree (lua_State *L, int idx, int *len) {
/*
** create a pattern
** create a pattern. Set its uservalue (the 'ktable') equal to its
** metatable. (It could be any empty sequence; the metatable is at
** hand here, so we use it.)
*/
static TTree *newtree (lua_State *L, int len) {
size_t size = (len - 1) * sizeof(TTree) + sizeof(Pattern);
Pattern *p = (Pattern *)lua_newuserdata(L, size);
luaL_getmetatable(L, PATTERN_T);
lua_pushvalue(L, -1);
lua_setuservalue(L, -3);
lua_setmetatable(L, -2);
p->code = NULL; p->codesize = 0;
return p->tree;
@@ -206,35 +393,6 @@ static TTree *seqaux (TTree *tree, TTree *sib, int sibsize) {
}
/*
** Add element 'idx' to 'ktable' of pattern at the top of the stack;
** create new 'ktable' if necessary. Return index of new element.
** If new element is nil, does not add it to table (as it would be
** useless) and returns 0, as ktable[0] is always nil.
*/
static int addtoktable (lua_State *L, int idx) {
if (idx == 0) /* no actual value to insert? */
return 0;
else {
int n;
lua_getfenv(L, -1); /* get ktable from pattern */
n = lua_objlen(L, -1);
if (n == 0) { /* is it empty/non-existent? */
lua_pop(L, 1); /* remove it */
lua_createtable(L, 1, 0); /* create a fresh table */
lua_pushvalue(L, -1); /* make a copy */
lua_setfenv(L, -3); /* set it as 'ktable' for pattern */
}
if (!lua_isnil(L, idx)) { /* non-nil value? */
lua_pushvalue(L, idx); /* element to be added */
lua_rawseti(L, -2, ++n);
}
lua_pop(L, 1); /* remove 'ktable' */
return n;
}
}
/*
** Build a sequence of 'n' nodes, each with tag 'tag' and 'u.n' got
** from the array 's' (or 0 if array is NULL). (TSeq is binary, so it
@@ -310,7 +468,7 @@ static TTree *getpatt (lua_State *L, int idx, int *len) {
case LUA_TFUNCTION: {
tree = newtree(L, 2);
tree->tag = TRunTime;
tree->key = addtoktable(L, idx);
tree->key = addtonewktable(L, 0, idx);
sib1(tree)->tag = TTrue;
break;
}
@@ -325,123 +483,6 @@ static TTree *getpatt (lua_State *L, int idx, int *len) {
}
/*
** Return the number of elements in the ktable of pattern at 'idx'.
** In Lua 5.2, default "environment" for patterns is nil, not
** a table. Treat it as an empty table. In Lua 5.1, assumes that
** the environment has no numeric indices (len == 0)
*/
static int ktablelen (lua_State *L, int idx) {
if (!lua_istable(L, idx)) return 0;
else return lua_objlen(L, idx);
}
/*
** Concatentate the contents of table 'idx1' into table 'idx2'.
** (Assume that both indices are negative.)
** Return the original length of table 'idx2'
*/
static int concattable (lua_State *L, int idx1, int idx2) {
int i;
int n1 = ktablelen(L, idx1);
int n2 = ktablelen(L, idx2);
if (n1 == 0) return 0; /* nothing to correct */
for (i = 1; i <= n1; i++) {
lua_rawgeti(L, idx1, i);
lua_rawseti(L, idx2 - 1, n2 + i); /* correct 'idx2' */
}
return n2;
}
/*
** Make a merge of ktables from p1 and p2 the ktable for the new
** pattern at the top of the stack.
*/
static int joinktables (lua_State *L, int p1, int p2) {
int n1, n2;
lua_getfenv(L, p1); /* get ktables */
lua_getfenv(L, p2);
n1 = ktablelen(L, -2);
n2 = ktablelen(L, -1);
if (n1 == 0 && n2 == 0) { /* are both tables empty? */
lua_pop(L, 2); /* nothing to be done; pop tables */
return 0; /* nothing to correct */
}
if (n2 == 0 || lua_equal(L, -2, -1)) { /* second table is empty or equal? */
lua_pop(L, 1); /* pop 2nd table */
lua_setfenv(L, -2); /* set 1st ktable into new pattern */
return 0; /* nothing to correct */
}
if (n1 == 0) { /* first table is empty? */
lua_setfenv(L, -3); /* set 2nd table into new pattern */
lua_pop(L, 1); /* pop 1st table */
return 0; /* nothing to correct */
}
else {
lua_createtable(L, n1 + n2, 0); /* create ktable for new pattern */
/* stack: new p; ktable p1; ktable p2; new ktable */
concattable(L, -3, -1); /* from p1 into new ktable */
concattable(L, -2, -1); /* from p2 into new ktable */
lua_setfenv(L, -4); /* new ktable becomes p env */
lua_pop(L, 2); /* pop other ktables */
return n1; /* correction for indices from p2 */
}
}
static void correctkeys (TTree *tree, int n) {
if (n == 0) return; /* no correction? */
tailcall:
switch (tree->tag) {
case TOpenCall: case TCall: case TRunTime: case TRule: {
if (tree->key > 0)
tree->key += n;
break;
}
case TCapture: {
if (tree->key > 0 && tree->cap != Carg && tree->cap != Cnum)
tree->key += n;
break;
}
default: break;
}
switch (numsiblings[tree->tag]) {
case 1: /* correctkeys(sib1(tree), n); */
tree = sib1(tree); goto tailcall;
case 2:
correctkeys(sib1(tree), n);
tree = sib2(tree); goto tailcall; /* correctkeys(sib2(tree), n); */
default: assert(numsiblings[tree->tag] == 0); break;
}
}
/*
** copy 'ktable' of element 'idx' to new tree (on top of stack)
*/
static void copyktable (lua_State *L, int idx) {
lua_getfenv(L, idx);
lua_setfenv(L, -2);
}
/*
** merge 'ktable' from rule at stack index 'idx' into 'ktable'
** from tree at the top of the stack, and correct corresponding
** tree.
*/
static void mergektable (lua_State *L, int idx, TTree *rule) {
int n;
lua_getfenv(L, -1); /* get ktables */
lua_getfenv(L, idx);
n = concattable(L, -1, -2);
lua_pop(L, 2); /* remove both ktables */
correctkeys(rule, n);
}
/*
** create a new tree, whith a new root and one sibling.
** Sibling must be on the Lua stack, at index 1.
@@ -470,7 +511,7 @@ static TTree *newroot2sib (lua_State *L, int tag) {
tree->u.ps = 1 + s1;
memcpy(sib1(tree), tree1, s1 * sizeof(TTree));
memcpy(sib2(tree), tree2, s2 * sizeof(TTree));
correctkeys(sib2(tree), joinktables(L, 1, 2));
joinktables(L, 1, sib2(tree), 2);
return tree;
}
@@ -599,7 +640,7 @@ static int lp_sub (lua_State *L) {
sib1(tree)->tag = TNot; /* ...not... */
memcpy(sib1(sib1(tree)), t2, s2 * sizeof(TTree)); /* ...t2 */
memcpy(sib2(tree), t1, s1 * sizeof(TTree)); /* ... and t1 */
correctkeys(sib1(tree), joinktables(L, 1, 2));
joinktables(L, 1, sib1(tree), 2);
}
return 1;
}
@@ -640,7 +681,7 @@ static int lp_behind (lua_State *L) {
TTree *tree;
TTree *tree1 = getpatt(L, 1, NULL);
int n = fixedlen(tree1);
luaL_argcheck(L, n > 0, 1, "pattern may not have fixed length");
luaL_argcheck(L, n >= 0, 1, "pattern may not have fixed length");
luaL_argcheck(L, !hascaptures(tree1), 1, "pattern have captures");
luaL_argcheck(L, n <= MAXBEHIND, 1, "pattern too long to look behind");
tree = newroot1sib(L, TBehind);
@@ -655,7 +696,7 @@ static int lp_behind (lua_State *L) {
static int lp_V (lua_State *L) {
TTree *tree = newleaf(L, TOpenCall);
luaL_argcheck(L, !lua_isnoneornil(L, 1), 1, "non-nil value expected");
tree->key = addtoktable(L, 1);
tree->key = addtonewktable(L, 0, 1);
return 1;
}
@@ -668,7 +709,7 @@ static int lp_V (lua_State *L) {
static int capture_aux (lua_State *L, int cap, int labelidx) {
TTree *tree = newroot1sib(L, TCapture);
tree->cap = cap;
tree->key = addtoktable(L, labelidx);
tree->key = (labelidx == 0) ? 0 : addtonewktable(L, 1, labelidx);
return 1;
}
@@ -676,10 +717,9 @@ static int capture_aux (lua_State *L, int cap, int labelidx) {
/*
** Fill a tree with an empty capture, using an empty (TTrue) sibling.
*/
static TTree *auxemptycap (lua_State *L, TTree *tree, int cap, int idx) {
static TTree *auxemptycap (TTree *tree, int cap) {
tree->tag = TCapture;
tree->cap = cap;
tree->key = addtoktable(L, idx);
sib1(tree)->tag = TTrue;
return tree;
}
@@ -688,8 +728,18 @@ static TTree *auxemptycap (lua_State *L, TTree *tree, int cap, int idx) {
/*
** Create a tree for an empty capture
*/
static TTree *newemptycap (lua_State *L, int cap, int idx) {
return auxemptycap(L, newtree(L, 2), cap, idx);
static TTree *newemptycap (lua_State *L, int cap) {
return auxemptycap(newtree(L, 2), cap);
}
/*
** Create a tree for an empty capture with an associated Lua value
*/
static TTree *newemptycapkey (lua_State *L, int cap, int idx) {
TTree *tree = auxemptycap(newtree(L, 2), cap);
tree->key = addtonewktable(L, 0, idx);
return tree;
}
@@ -728,10 +778,8 @@ static int lp_tablecapture (lua_State *L) {
static int lp_groupcapture (lua_State *L) {
if (lua_isnoneornil(L, 2))
return capture_aux(L, Cgroup, 0);
else {
luaL_checkstring(L, 2);
else
return capture_aux(L, Cgroup, 2);
}
}
@@ -747,14 +795,14 @@ static int lp_simplecapture (lua_State *L) {
static int lp_poscapture (lua_State *L) {
newemptycap(L, Cposition, 0);
newemptycap(L, Cposition);
return 1;
}
static int lp_argcapture (lua_State *L) {
int n = (int)luaL_checkinteger(L, 1);
TTree *tree = newemptycap(L, Carg, 0);
TTree *tree = newemptycap(L, Carg);
tree->key = n;
luaL_argcheck(L, 0 < n && n <= SHRT_MAX, 1, "invalid argument index");
return 1;
@@ -762,8 +810,8 @@ static int lp_argcapture (lua_State *L) {
static int lp_backref (lua_State *L) {
luaL_checkstring(L, 1);
newemptycap(L, Cbackref, 1);
luaL_checkany(L, 1);
newemptycapkey(L, Cbackref, 1);
return 1;
}
@@ -777,9 +825,10 @@ static int lp_constcapture (lua_State *L) {
if (n == 0) /* no values? */
newleaf(L, TTrue); /* no capture */
else if (n == 1)
newemptycap(L, Cconst, 1); /* single constant capture */
newemptycapkey(L, Cconst, 1); /* single constant capture */
else { /* create a group capture with all values */
TTree *tree = newtree(L, 1 + 3 * (n - 1) + 2);
newktable(L, n); /* create a 'ktable' for new tree */
tree->tag = TCapture;
tree->cap = Cgroup;
tree->key = 0;
@@ -787,10 +836,12 @@ static int lp_constcapture (lua_State *L) {
for (i = 1; i <= n - 1; i++) {
tree->tag = TSeq;
tree->u.ps = 3; /* skip TCapture and its sibling */
auxemptycap(L, sib1(tree), Cconst, i);
auxemptycap(sib1(tree), Cconst);
sib1(tree)->key = addtoktable(L, i);
tree = sib2(tree);
}
auxemptycap(L, tree, Cconst, i);
auxemptycap(tree, Cconst);
tree->key = addtoktable(L, i);
}
return 1;
}
@@ -800,7 +851,7 @@ static int lp_matchtime (lua_State *L) {
TTree *tree;
luaL_checktype(L, 2, LUA_TFUNCTION);
tree = newroot1sib(L, TRunTime);
tree->key = addtoktable(L, 2);
tree->key = addtonewktable(L, 1, 2);
return 1;
}
@@ -857,7 +908,7 @@ static int collectrules (lua_State *L, int arg, int *totalsize) {
lua_pushnil(L); /* prepare to traverse grammar table */
while (lua_next(L, arg) != 0) {
if (lua_tonumber(L, -2) == 1 ||
lua_equal(L, -2, postab + 1)) { /* initial rule? */
lp_equal(L, -2, postab + 1)) { /* initial rule? */
lua_pop(L, 1); /* remove value (keep key for lua_next) */
continue;
}
@@ -934,36 +985,40 @@ static int verifyerror (lua_State *L, int *passed, int npassed) {
/*
** Check whether a rule can be left recursive; raise an error in that
** case; otherwise return 1 iff pattern is nullable. Assume ktable at
** the top of the stack.
** case; otherwise return 1 iff pattern is nullable.
** The return value is used to check sequences, where the second pattern
** is only relevant if the first is nullable.
** Parameter 'nb' works as an accumulator, to allow tail calls in
** choices. ('nb' true makes function returns true.)
** Assume ktable at the top of the stack.
*/
static int verifyrule (lua_State *L, TTree *tree, int *passed, int npassed,
int nullable) {
int nb) {
tailcall:
switch (tree->tag) {
case TChar: case TSet: case TAny:
case TFalse:
return nullable; /* cannot pass from here */
return nb; /* cannot pass from here */
case TTrue:
case TBehind: /* look-behind cannot have calls */
return 1;
case TNot: case TAnd: case TRep:
/* return verifyrule(L, sib1(tree), passed, npassed, 1); */
tree = sib1(tree); nullable = 1; goto tailcall;
tree = sib1(tree); nb = 1; goto tailcall;
case TCapture: case TRunTime:
/* return verifyrule(L, sib1(tree), passed, npassed); */
/* return verifyrule(L, sib1(tree), passed, npassed, nb); */
tree = sib1(tree); goto tailcall;
case TCall:
/* return verifyrule(L, sib2(tree), passed, npassed); */
/* return verifyrule(L, sib2(tree), passed, npassed, nb); */
tree = sib2(tree); goto tailcall;
case TSeq: /* only check 2nd child if first is nullable */
case TSeq: /* only check 2nd child if first is nb */
if (!verifyrule(L, sib1(tree), passed, npassed, 0))
return nullable;
/* else return verifyrule(L, sib2(tree), passed, npassed); */
return nb;
/* else return verifyrule(L, sib2(tree), passed, npassed, nb); */
tree = sib2(tree); goto tailcall;
case TChoice: /* must check both children */
nullable = verifyrule(L, sib1(tree), passed, npassed, nullable);
/* return verifyrule(L, sib2(tree), passed, npassed, nullable); */
nb = verifyrule(L, sib1(tree), passed, npassed, nb);
/* return verifyrule(L, sib2(tree), passed, npassed, nb); */
tree = sib2(tree); goto tailcall;
case TRule:
if (npassed >= MAXRULES)
@@ -1006,7 +1061,7 @@ static void verifygrammar (lua_State *L, TTree *grammar) {
*/
static void initialrulename (lua_State *L, TTree *grammar, int frule) {
if (sib1(grammar)->key == 0) { /* initial rule is not referenced? */
int n = lua_objlen(L, -1) + 1; /* index for name */
int n = lua_rawlen(L, -1) + 1; /* index for name */
lua_pushvalue(L, frule); /* rule's name */
lua_rawseti(L, -2, n); /* ktable was on the top of the stack */
sib1(grammar)->key = n;
@@ -1022,9 +1077,9 @@ static TTree *newgrammar (lua_State *L, int arg) {
luaL_argcheck(L, n <= MAXRULES, arg, "grammar has too many rules");
g->tag = TGrammar; g->u.n = n;
lua_newtable(L); /* create 'ktable' */
lua_setfenv(L, -2);
lua_setuservalue(L, -2);
buildgrammar(L, g, frule, n);
lua_getfenv(L, -1); /* get 'ktable' for new tree */
lua_getuservalue(L, -1); /* get 'ktable' for new tree */
finalfix(L, frule - 1, g, sib1(g));
initialrulename(L, g, frule);
verifygrammar(L, g);
@@ -1038,7 +1093,7 @@ static TTree *newgrammar (lua_State *L, int arg) {
static Instruction *prepcompile (lua_State *L, Pattern *p, int idx) {
lua_getfenv(L, idx); /* push 'ktable' (may be used by 'finalfix') */
lua_getuservalue(L, idx); /* push 'ktable' (may be used by 'finalfix') */
finalfix(L, 0, NULL, p->tree);
lua_pop(L, 1); /* remove 'ktable' */
return compile(L, p);
@@ -1049,7 +1104,7 @@ static int lp_printtree (lua_State *L) {
TTree *tree = getpatt(L, 1, NULL);
int c = lua_toboolean(L, 2);
if (c) {
lua_getfenv(L, 1); /* push 'ktable' (may be used by 'finalfix') */
lua_getuservalue(L, 1); /* push 'ktable' (may be used by 'finalfix') */
finalfix(L, 0, NULL, tree);
lua_pop(L, 1); /* remove 'ktable' */
}
@@ -1102,7 +1157,7 @@ static int lp_match (lua_State *L) {
int ptop = lua_gettop(L);
lua_pushnil(L); /* initialize subscache */
lua_pushlightuserdata(L, capture); /* initialize caplistidx */
lua_getfenv(L, 1); /* initialize penvidx */
lua_getuservalue(L, 1); /* initialize penvidx */
r = match(L, s, s + i, s + l, code, capture, ptop);
if (r == NULL) {
lua_pushnil(L);
@@ -1119,8 +1174,12 @@ static int lp_match (lua_State *L) {
** =======================================================
*/
/* maximum limit for stack size */
#define MAXLIM (INT_MAX / 100)
static int lp_setmax (lua_State *L) {
luaL_optinteger(L, 1, -1);
lua_Integer lim = luaL_checkinteger(L, 1);
luaL_argcheck(L, 0 < lim && lim <= MAXLIM, 1, "out of range");
lua_settop(L, 1);
lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX);
return 0;
@@ -1144,8 +1203,7 @@ static int lp_type (lua_State *L) {
int lp_gc (lua_State *L) {
Pattern *p = getpattern(L, 1);
if (p->codesize > 0)
realloccode(L, p, 0);
realloccode(L, p, 0); /* delete code block */
return 0;
}
@@ -1228,8 +1286,8 @@ int luaopen_lpeg (lua_State *L) {
luaL_newmetatable(L, PATTERN_T);
lua_pushnumber(L, MAXBACK); /* initialize maximum backtracking */
lua_setfield(L, LUA_REGISTRYINDEX, MAXSTACKIDX);
luaL_register(L, NULL, metareg);
luaL_register(L, "lpeg", pattreg);
luaL_setfuncs(L, metareg, 0);
luaL_newlib(L, pattreg);
lua_pushvalue(L, -1);
lua_setfield(L, -3, "__index");
return 1;

View File

@@ -1,7 +1,7 @@
/*
** $Id: lptypes.h,v 1.10 2014/12/12 17:11:35 roberto Exp $
** $Id: lptypes.h,v 1.14 2015/09/28 17:17:41 roberto Exp $
** LPeg - PEG pattern matching for Lua
** Copyright 2007-2014, Lua.org & PUC-Rio (see 'lpeg.html' for license)
** Copyright 2007-2015, Lua.org & PUC-Rio (see 'lpeg.html' for license)
** written by Roberto Ierusalimschy
*/
@@ -19,7 +19,7 @@
#include "lua.h"
#define VERSION "0.12.1"
#define VERSION "1.0.0"
#define PATTERN_T "lpeg-pattern"
@@ -27,31 +27,31 @@
/*
** compatibility with Lua 5.2
** compatibility with Lua 5.1
*/
#if (LUA_VERSION_NUM >= 502)
#if (LUA_VERSION_NUM == 501)
#undef lua_equal
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
#define lp_equal lua_equal
#undef lua_getfenv
#define lua_getfenv lua_getuservalue
#undef lua_setfenv
#define lua_setfenv lua_setuservalue
#define lua_getuservalue lua_getfenv
#define lua_setuservalue lua_setfenv
#undef lua_objlen
#define lua_objlen lua_rawlen
#define lua_rawlen lua_objlen
#undef luaL_register
#define luaL_register(L,n,f) \
{ if ((n) == NULL) luaL_setfuncs(L,f,0); else luaL_newlib(L,f); }
#define luaL_setfuncs(L,f,n) luaL_register(L,NULL,f)
#define luaL_newlib(L,f) luaL_register(L,"lpeg",f)
#endif
#if !defined(lp_equal)
#define lp_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
#endif
/* default maximum size for call/backtrack stack */
#if !defined(MAXBACK)
#define MAXBACK 100
#define MAXBACK 400
#endif

View File

@@ -1,5 +1,5 @@
/*
** $Id: lpvm.c,v 1.5 2013/04/12 16:29:49 roberto Exp $
** $Id: lpvm.c,v 1.6 2015/09/28 17:01:25 roberto Exp $
** Copyright 2007, Lua.org & PUC-Rio (see 'lpeg.html' for license)
*/
@@ -18,7 +18,7 @@
/* initial size for call/backtrack stack */
#if !defined(INITBACK)
#define INITBACK 100
#define INITBACK MAXBACK
#endif
@@ -70,7 +70,7 @@ static Stack *doublestack (lua_State *L, Stack **stacklimit, int ptop) {
max = lua_tointeger(L, -1); /* maximum allowed size */
lua_pop(L, 1);
if (n >= max) /* already at maximum size? */
luaL_error(L, "too many pending calls/choices");
luaL_error(L, "backtrack stack overflow (current limit is %d)", max);
newn = 2 * n; /* new size */
if (newn > max) newn = max;
newstack = (Stack *)lua_newuserdata(L, newn * sizeof(Stack));

View File

@@ -10,7 +10,7 @@
</head>
<body>
<!-- $Id: re.html,v 1.21 2013/03/28 20:43:30 roberto Exp $ -->
<!-- $Id: re.html,v 1.23 2015/09/28 17:17:41 roberto Exp $ -->
<div id="container">
@@ -296,7 +296,7 @@ it would be useful if each table had
a <code>tag</code> field telling what non terminal
that table represents.
We can add such a tag using
<a href="lpeg.html/#cap-g">named group captures</a>:
<a href="lpeg.html#cap-g">named group captures</a>:
</p>
<pre class="example">
x = re.compile[[
@@ -450,7 +450,7 @@ print(re.match(p, p)) -- a self description must match itself
<h2><a name="license">License</a></h2>
<p>
Copyright &copy; 2008-2010 Lua.org, PUC-Rio.
Copyright &copy; 2008-2015 Lua.org, PUC-Rio.
</p>
<p>
Permission is hereby granted, free of charge,
@@ -488,7 +488,7 @@ THE SOFTWARE.
<div id="about">
<p><small>
$Id: re.html,v 1.21 2013/03/28 20:43:30 roberto Exp $
$Id: re.html,v 1.23 2015/09/28 17:17:41 roberto Exp $
</small></p>
</div> <!-- id="about" -->

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env lua5.1
#!/usr/bin/env lua
-- $Id: test.lua,v 1.105 2014/12/12 17:00:39 roberto Exp $
-- $Id: test.lua,v 1.109 2015/09/28 17:01:25 roberto Exp $
-- require"strict" -- just to be pedantic
@@ -16,9 +16,6 @@ local unpack = rawget(table, "unpack") or unpack
local loadstring = rawget(_G, "loadstring") or load
-- most tests here do not need much stack space
m.setmaxstack(5)
local any = m.P(1)
local space = m.S" \t\n"^0
@@ -291,6 +288,13 @@ assert(m.match(m.P"ab"^-1 - "c", "abcd") == 3)
p = ('Aa' * ('Bb' * ('Cc' * m.P'Dd'^0)^0)^0)^-1
assert(p:match("AaBbCcDdBbCcDdDdDdBb") == 21)
-- bug in 0.12.2
-- p = { ('ab' ('c' 'ef'?)*)? }
p = m.C(('ab' * ('c' * m.P'ef'^-1)^0)^-1)
s = "abcefccefc"
assert(s == p:match(s))
pi = "3.14159 26535 89793 23846 26433 83279 50288 41971 69399 37510"
@@ -352,6 +356,11 @@ checkeq(t, {hi = 10, ho = 20})
t = p:match'abc'
checkeq(t, {hi = 10, ho = 20, 'a', 'b', 'c'})
-- non-string group names
p = m.Ct(m.Cg(1, print) * m.Cg(1, 23.5) * m.Cg(1, io))
t = p:match('abcdefghij')
assert(t[print] == 'a' and t[23.5] == 'b' and t[io] == 'c')
-- test for error messages
local function checkerr (msg, f, ...)
@@ -388,6 +397,25 @@ p = m.P { (m.P {m.P'abc'} + 'ayz') * m.V'y'; y = m.P'x' }
assert(p:match('abcx') == 5 and p:match('ayzx') == 5 and not p:match'abc')
do
-- large dynamic Cc
local lim = 2^16 - 1
local c = 0
local function seq (n)
if n == 1 then c = c + 1; return m.Cc(c)
else
local m = math.floor(n / 2)
return seq(m) * seq(n - m)
end
end
p = m.Ct(seq(lim))
t = p:match('')
assert(t[lim] == lim)
checkerr("too many", function () p = p / print end)
checkerr("too many", seq, lim + 1)
end
-- tests for non-pattern as arguments to pattern functions
p = { ('a' * m.V(1))^-1 } * m.P'b' * { 'a' * m.V(2); m.V(1)^-1 }
@@ -575,9 +603,9 @@ assert(not p:match(string.rep("011", 10001)))
-- this grammar does need backtracking info.
local lim = 10000
p = m.P{ '0' * m.V(1) + '0' }
checkerr("too many pending", m.match, p, string.rep("0", lim))
checkerr("stack overflow", m.match, p, string.rep("0", lim))
m.setmaxstack(2*lim)
checkerr("too many pending", m.match, p, string.rep("0", lim))
checkerr("stack overflow", m.match, p, string.rep("0", lim))
m.setmaxstack(2*lim + 4)
assert(m.match(p, string.rep("0", lim)) == lim + 1)
@@ -586,7 +614,7 @@ p = m.P{ ('a' * m.V(1))^0 * 'b' + 'c' }
m.setmaxstack(200)
assert(p:match(string.rep('a', 180) .. 'c' .. string.rep('b', 180)) == 362)
m.setmaxstack(5) -- restore original limit
m.setmaxstack(100) -- restore low limit
-- tests for optional start position
assert(m.match("a", "abc", 1))
@@ -718,6 +746,10 @@ t = {m.match(m.Cc(nil,nil,4) * m.Cc(nil,3) * m.Cc(nil, nil) / g / g, "")}
t1 = {1,1,nil,nil,4,nil,3,nil,nil}
for i=1,10 do assert(t[i] == t1[i]) end
-- bug in 0.12.2: ktable with only nil could be eliminated when joining
-- with a pattern without ktable
assert((m.P"aaa" * m.Cc(nil)):match"aaa" == nil)
t = {m.match((m.C(1) / function (x) return x, x.."x" end)^0, "abc")}
checkeq(t, {"a", "ax", "b", "bx", "c", "cx"})
@@ -925,6 +957,13 @@ p = m.Cg(m.C(1) * m.C(1), "k") * m.Ct(m.Cb("k"))
t = p:match("ab")
checkeq(t, {"a", "b"})
p = m.P(true)
for i = 1, 10 do p = p * m.Cg(1, i) end
for i = 1, 10 do
local p = p * m.Cb(i)
assert(p:match('abcdefghij') == string.sub('abcdefghij', i, i))
end
t = {}
function foo (p) t[#t + 1] = p; return p .. "x" end

View File

@@ -19,7 +19,7 @@ SYSCFLAGS=
SYSLDFLAGS=
SYSLIBS=
MYCFLAGS=
MYCFLAGS=-I../../skynet-src
MYLDFLAGS=
MYLIBS=
MYOBJS=

View File

@@ -1,5 +1,6 @@
This is 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
This is a modify version of lua 5.3.2 (http://www.lua.org/ftp/lua-5.3.2.tar.gz) .
For detail ,
Shared Proto : http://lua-users.org/lists/lua-l/2014-03/msg00489.html
Shared short string table : http://blog.codingnow.com/2015/08/lua_vm_share_string.html
Signal for debug use : http://blog.codingnow.com/2015/03/skynet_signal.html

View File

@@ -1,5 +1,5 @@
/*
** $Id: lapi.c,v 2.249 2015/04/06 12:23:48 roberto Exp $
** $Id: lapi.c,v 2.259 2016/02/29 14:27:14 roberto Exp $
** Lua API
** See Copyright Notice in lua.h
*/
@@ -122,11 +122,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to);
api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states");
api_check(from, to->ci->top - to->top >= n, "not enough elements to move");
api_check(from, to->ci->top - to->top >= n, "stack overflow");
from->top -= n;
for (i = 0; i < n; i++) {
setobj2s(to, to->top, from->top + i);
api_incr_top(to);
to->top++; /* stack already checked by previous 'api_check' */
}
lua_unlock(to);
}
@@ -379,9 +379,9 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
return NULL;
}
lua_lock(L); /* 'luaO_tostring' may create a new string */
luaO_tostring(L, o);
luaC_checkGC(L);
o = index2addr(L, idx); /* previous call may reallocate the stack */
luaO_tostring(L, o);
lua_unlock(L);
}
if (len != NULL)
@@ -472,13 +472,18 @@ LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
}
/*
** Pushes on the stack a string with given length. Avoid using 's' when
** 'len' == 0 (as 's' can be NULL in that case), due to later use of
** 'memcmp' and 'memcpy'.
*/
LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts;
lua_lock(L);
luaC_checkGC(L);
ts = luaS_newlstr(L, s, len);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
return getstr(ts);
}
@@ -490,12 +495,12 @@ LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
setnilvalue(L->top);
else {
TString *ts;
luaC_checkGC(L);
ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts);
s = getstr(ts); /* internal copy's address */
}
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
return s;
}
@@ -505,8 +510,8 @@ LUA_API const char *lua_pushvfstring (lua_State *L, const char *fmt,
va_list argp) {
const char *ret;
lua_lock(L);
luaC_checkGC(L);
ret = luaO_pushvfstring(L, fmt, argp);
luaC_checkGC(L);
lua_unlock(L);
return ret;
}
@@ -516,10 +521,10 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
const char *ret;
va_list argp;
lua_lock(L);
luaC_checkGC(L);
va_start(argp, fmt);
ret = luaO_pushvfstring(L, fmt, argp);
va_end(argp);
luaC_checkGC(L);
lua_unlock(L);
return ret;
}
@@ -534,7 +539,6 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
CClosure *cl;
api_checknelems(L, n);
api_check(L, n <= MAXUPVAL, "upvalue index too large");
luaC_checkGC(L);
cl = luaF_newCclosure(L, n);
cl->f = fn;
L->top -= n;
@@ -545,6 +549,7 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
setclCvalue(L, L->top, cl);
}
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
}
@@ -580,19 +585,30 @@ LUA_API int lua_pushthread (lua_State *L) {
*/
LUA_API int lua_getglobal (lua_State *L, const char *name) {
Table *reg = hvalue(&G(L)->l_registry);
const TValue *gt; /* global table */
lua_lock(L);
gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
setsvalue2s(L, L->top, luaS_new(L, name));
api_incr_top(L);
luaV_gettable(L, gt, L->top - 1, L->top - 1);
static int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, slot);
api_incr_top(L);
}
else {
setsvalue2s(L, L->top, str);
api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
}
lua_unlock(L);
return ttnov(L->top - 1);
}
LUA_API int lua_getglobal (lua_State *L, const char *name) {
Table *reg = hvalue(&G(L)->l_registry);
lua_lock(L);
return auxgetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
}
LUA_API int lua_gettable (lua_State *L, int idx) {
StkId t;
lua_lock(L);
@@ -604,24 +620,25 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
LUA_API int lua_getfield (lua_State *L, int idx, const char *k) {
StkId t;
lua_lock(L);
t = index2addr(L, idx);
setsvalue2s(L, L->top, luaS_new(L, k));
api_incr_top(L);
luaV_gettable(L, t, L->top - 1, L->top - 1);
lua_unlock(L);
return ttnov(L->top - 1);
return auxgetstr(L, index2addr(L, idx), k);
}
LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
StkId t;
const TValue *slot;
lua_lock(L);
t = index2addr(L, idx);
setivalue(L->top, n);
api_incr_top(L);
luaV_gettable(L, t, L->top - 1, L->top - 1);
if (luaV_fastget(L, t, n, slot, luaH_getint)) {
setobj2s(L, L->top, slot);
api_incr_top(L);
}
else {
setivalue(L->top, n);
api_incr_top(L);
luaV_finishget(L, t, L->top - 1, L->top - 1, slot);
}
lua_unlock(L);
return ttnov(L->top - 1);
}
@@ -667,12 +684,12 @@ LUA_API int lua_rawgetp (lua_State *L, int idx, const void *p) {
LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t;
lua_lock(L);
luaC_checkGC(L);
t = luaH_new(L);
sethvalue(L, L->top, t);
api_incr_top(L);
if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec);
luaC_checkGC(L);
lua_unlock(L);
}
@@ -720,18 +737,29 @@ LUA_API int lua_getuservalue (lua_State *L, int idx) {
** set functions (stack -> Lua)
*/
/*
** t[k] = value at the top of the stack (where 'k' is a string)
*/
static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot;
TString *str = luaS_new(L, k);
api_checknelems(L, 1);
if (luaV_fastset(L, t, str, slot, luaH_getstr, L->top - 1))
L->top--; /* pop value */
else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */
api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */
}
lua_unlock(L); /* lock done by caller */
}
LUA_API void lua_setglobal (lua_State *L, const char *name) {
Table *reg = hvalue(&G(L)->l_registry);
const TValue *gt; /* global table */
lua_lock(L);
api_checknelems(L, 1);
gt = luaH_getint(reg, LUA_RIDX_GLOBALS);
setsvalue2s(L, L->top, luaS_new(L, name));
api_incr_top(L);
luaV_settable(L, gt, L->top - 1, L->top - 2);
L->top -= 2; /* pop value and key */
lua_unlock(L);
lua_lock(L); /* unlock done in 'auxsetstr' */
auxsetstr(L, luaH_getint(reg, LUA_RIDX_GLOBALS), name);
}
@@ -747,42 +775,40 @@ LUA_API void lua_settable (lua_State *L, int idx) {
LUA_API void lua_setfield (lua_State *L, int idx, const char *k) {
StkId t;
lua_lock(L);
api_checknelems(L, 1);
t = index2addr(L, idx);
setsvalue2s(L, L->top, luaS_new(L, k));
api_incr_top(L);
luaV_settable(L, t, L->top - 1, L->top - 2);
L->top -= 2; /* pop value and key */
lua_unlock(L);
lua_lock(L); /* unlock done in 'auxsetstr' */
auxsetstr(L, index2addr(L, idx), k);
}
LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
StkId t;
const TValue *slot;
lua_lock(L);
api_checknelems(L, 1);
t = index2addr(L, idx);
setivalue(L->top, n);
api_incr_top(L);
luaV_settable(L, t, L->top - 1, L->top - 2);
L->top -= 2; /* pop value and key */
if (luaV_fastset(L, t, n, slot, luaH_getint, L->top - 1))
L->top--; /* pop value */
else {
setivalue(L->top, n);
api_incr_top(L);
luaV_finishset(L, t, L->top - 1, L->top - 2, slot);
L->top -= 2; /* pop value and key */
}
lua_unlock(L);
}
LUA_API void lua_rawset (lua_State *L, int idx) {
StkId o;
Table *t;
TValue *slot;
lua_lock(L);
api_checknelems(L, 2);
o = index2addr(L, idx);
api_check(L, ttistable(o), "table expected");
t = hvalue(o);
setobj2t(L, luaH_set(L, t, L->top-2), L->top-1);
invalidateTMcache(t);
luaC_barrierback(L, t, L->top-1);
slot = luaH_set(L, hvalue(o), L->top - 2);
setobj2t(L, slot, L->top - 1);
invalidateTMcache(hvalue(o));
luaC_barrierback(L, hvalue(o), L->top-1);
L->top -= 2;
lua_unlock(L);
}
@@ -790,14 +816,12 @@ LUA_API void lua_rawset (lua_State *L, int idx) {
LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
StkId o;
Table *t;
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
api_check(L, ttistable(o), "table expected");
t = hvalue(o);
luaH_setint(L, t, n, L->top - 1);
luaC_barrierback(L, t, L->top-1);
luaH_setint(L, hvalue(o), n, L->top - 1);
luaC_barrierback(L, hvalue(o), L->top-1);
L->top--;
lua_unlock(L);
}
@@ -805,16 +829,15 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
LUA_API void lua_rawsetp (lua_State *L, int idx, const void *p) {
StkId o;
Table *t;
TValue k;
TValue k, *slot;
lua_lock(L);
api_checknelems(L, 1);
o = index2addr(L, idx);
api_check(L, ttistable(o), "table expected");
t = hvalue(o);
setpvalue(&k, cast(void *, p));
setobj2t(L, luaH_set(L, t, &k), L->top - 1);
luaC_barrierback(L, t, L->top - 1);
slot = luaH_set(L, hvalue(o), &k);
setobj2t(L, slot, L->top - 1);
luaC_barrierback(L, hvalue(o), L->top - 1);
L->top--;
lua_unlock(L);
}
@@ -896,10 +919,10 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
if (k != NULL && L->nny == 0) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */
luaD_call(L, func, nresults, 1); /* do the call */
luaD_call(L, func, nresults); /* do the call */
}
else /* no continuation or no yieldable */
luaD_call(L, func, nresults, 0); /* just do the call */
luaD_callnoyield(L, func, nresults); /* just do the call */
adjustresults(L, nresults);
lua_unlock(L);
}
@@ -917,7 +940,7 @@ struct CallS { /* data to 'f_call' */
static void f_call (lua_State *L, void *ud) {
struct CallS *c = cast(struct CallS *, ud);
luaD_call(L, c->func, c->nresults, 0);
luaD_callnoyield(L, c->func, c->nresults);
}
@@ -955,7 +978,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
L->errfunc = func;
setoah(ci->callstatus, L->allowhook); /* save value of 'allowhook' */
ci->callstatus |= CIST_YPCALL; /* function can do error recovery */
luaD_call(L, c.func, nresults, 1); /* do the call */
luaD_call(L, c.func, nresults); /* do the call */
ci->callstatus &= ~CIST_YPCALL;
L->errfunc = ci->u.c.old_errfunc;
status = LUA_OK; /* if it is here, there were no errors */
@@ -989,10 +1012,9 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
return status;
}
static Proto * cloneproto (lua_State *L, const Proto *src) {
void cloneproto (lua_State *L, Proto *f, const Proto *src) {
/* copy constants and nested proto */
int i,n;
Proto *f = luaF_newproto(L, src->sp);
n = src->sp->sizek;
f->k=luaM_newvector(L,n,TValue);
for (i=0; i<n; i++) setnilvalue(&f->k[i]);
@@ -1000,7 +1022,7 @@ static Proto * cloneproto (lua_State *L, const Proto *src) {
const TValue *s=&src->k[i];
TValue *o=&f->k[i];
if (ttisstring(s)) {
TString * str = luaS_newlstr(L,svalue(s),vslen(s));
TString * str = luaS_clonestring(L,tsvalue(s));
setsvalue2n(L,o,str);
} else {
setobj(L,o,s);
@@ -1010,9 +1032,9 @@ static Proto * cloneproto (lua_State *L, const Proto *src) {
f->p=luaM_newvector(L,n,struct Proto *);
for (i=0; i<n; i++) f->p[i]=NULL;
for (i=0; i<n; i++) {
f->p[i]=cloneproto(L, src->p[i]);
f->p[i]= luaF_newproto(L, src->p[i]->sp);
cloneproto(L, f->p[i], src->p[i]);
}
return f;
}
LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
@@ -1026,9 +1048,10 @@ LUA_API void lua_clonefunction (lua_State *L, const void * fp) {
return;
}
cl = luaF_newLclosure(L,f->nupvalues);
cl->p = cloneproto(L, f->p);
setclLvalue(L,L->top,cl);
api_incr_top(L);
cl->p = luaF_newproto(L, f->p->sp);
cloneproto(L, cl->p, f->p);
luaF_initupvals(L, cl);
if (cl->nupvalues >= 1) { /* does it have an upvalue? */
@@ -1096,7 +1119,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
}
case LUA_GCSTEP: {
l_mem debt = 1; /* =1 to signal that it did an actual step */
int oldrunning = g->gcrunning;
lu_byte oldrunning = g->gcrunning;
g->gcrunning = 1; /* allow GC to run */
if (data == 0) {
luaE_setdebt(g, -GCSTEPSIZE); /* to do a "small" step */
@@ -1170,7 +1193,6 @@ LUA_API void lua_concat (lua_State *L, int n) {
lua_lock(L);
api_checknelems(L, n);
if (n >= 2) {
luaC_checkGC(L);
luaV_concat(L, n);
}
else if (n == 0) { /* push empty string */
@@ -1178,6 +1200,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
api_incr_top(L);
}
/* else n == 1; nothing to do */
luaC_checkGC(L);
lua_unlock(L);
}
@@ -1213,10 +1236,10 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud) {
LUA_API void *lua_newuserdata (lua_State *L, size_t size) {
Udata *u;
lua_lock(L);
luaC_checkGC(L);
u = luaS_newudata(L, size);
setuvalue(L, L->top, u);
api_incr_top(L);
luaC_checkGC(L);
lua_unlock(L);
return getudatamem(u);
}
@@ -1288,7 +1311,7 @@ static UpVal **getupvalref (lua_State *L, int fidx, int n, LClosure **pf) {
StkId fi = index2addr(L, fidx);
api_check(L, ttisLclosure(fi), "Lua function expected");
f = clLvalue(fi);
api_check(L, (1 <= n && n <= f->p->sizeupvalues), "invalid upvalue index");
api_check(L, (1 <= n && n <= f->p->sp->sizeupvalues), "invalid upvalue index");
if (pf) *pf = f;
return &f->upvals[n - 1]; /* get its upvalue pointer */
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lauxlib.c,v 1.280 2015/02/03 17:38:24 roberto Exp $
** $Id: lauxlib.c,v 1.286 2016/01/08 15:33:09 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -17,7 +17,8 @@
#include <string.h>
/* This file uses only the official API of Lua.
/*
** This file uses only the official API of Lua.
** Any function declared here could be written as an application function.
*/
@@ -33,8 +34,8 @@
*/
#define LEVELS1 12 /* size of the first part of the stack */
#define LEVELS2 10 /* size of the second part of the stack */
#define LEVELS1 10 /* size of the first part of the stack */
#define LEVELS2 11 /* size of the second part of the stack */
@@ -107,7 +108,7 @@ static void pushfuncname (lua_State *L, lua_Debug *ar) {
}
static int countlevels (lua_State *L) {
static int lastlevel (lua_State *L) {
lua_Debug ar;
int li = 1, le = 1;
/* find an upper bound */
@@ -126,14 +127,16 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
const char *msg, int level) {
lua_Debug ar;
int top = lua_gettop(L);
int numlevels = countlevels(L1);
int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
if (msg) lua_pushfstring(L, "%s\n", msg);
int last = lastlevel(L1);
int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1;
if (msg)
lua_pushfstring(L, "%s\n", msg);
luaL_checkstack(L, 10, NULL);
lua_pushliteral(L, "stack traceback:");
while (lua_getstack(L1, level++, &ar)) {
if (level == mark) { /* too many levels? */
if (n1-- == 0) { /* too many levels? */
lua_pushliteral(L, "\n\t..."); /* add a '...' */
level = numlevels - LEVELS2; /* and skip to last ones */
level = last - LEVELS2 + 1; /* and skip to last ones */
}
else {
lua_getinfo(L1, "Slnt", &ar);
@@ -196,6 +199,10 @@ static void tag_error (lua_State *L, int arg, int tag) {
}
/*
** The use of 'lua_pushfstring' ensures this function does not
** need reserved stack space when called.
*/
LUALIB_API void luaL_where (lua_State *L, int level) {
lua_Debug ar;
if (lua_getstack(L, level, &ar)) { /* check function at level */
@@ -205,10 +212,15 @@ LUALIB_API void luaL_where (lua_State *L, int level) {
return;
}
}
lua_pushliteral(L, ""); /* else, no information available... */
lua_pushfstring(L, ""); /* else, no information available... */
}
/*
** Again, the use of 'lua_pushvfstring' ensures this function does
** not need reserved stack space when called. (At worst, it generates
** an error with "stack overflow" instead of the given message.)
*/
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
@@ -289,7 +301,7 @@ LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */
return 0; /* leave previous value on top, but return 0 */
lua_pop(L, 1);
lua_newtable(L); /* create metatable */
lua_createtable(L, 0, 2); /* create metatable */
lua_pushstring(L, tname);
lua_setfield(L, -2, "__name"); /* metatable.__name = tname */
lua_pushvalue(L, -1);
@@ -347,10 +359,15 @@ LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
}
/*
** Ensures the stack has at least 'space' extra slots, raising an error
** if it cannot fulfill the request. (The error handling needs a few
** extra slots to format the error message. In case of an error without
** this extra space, Lua will generate the same 'stack overflow' error,
** but without 'msg'.)
*/
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
/* keep some extra space to run error routines, if needed */
const int extra = LUA_MINSTACK;
if (!lua_checkstack(L, space + extra)) {
if (!lua_checkstack(L, space)) {
if (msg)
luaL_error(L, "stack overflow (%s)", msg);
else
@@ -435,6 +452,47 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg,
** =======================================================
*/
/* userdata to box arbitrary data */
typedef struct UBox {
void *box;
size_t bsize;
} UBox;
static void *resizebox (lua_State *L, int idx, size_t newsize) {
void *ud;
lua_Alloc allocf = lua_getallocf(L, &ud);
UBox *box = (UBox *)lua_touserdata(L, idx);
void *temp = allocf(ud, box->box, box->bsize, newsize);
if (temp == NULL && newsize > 0) { /* allocation error? */
resizebox(L, idx, 0); /* free buffer */
luaL_error(L, "not enough memory for buffer allocation");
}
box->box = temp;
box->bsize = newsize;
return temp;
}
static int boxgc (lua_State *L) {
resizebox(L, 1, 0);
return 0;
}
static void *newbox (lua_State *L, size_t newsize) {
UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox));
box->box = NULL;
box->bsize = 0;
if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */
lua_pushcfunction(L, boxgc);
lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */
}
lua_setmetatable(L, -2);
return resizebox(L, -1, newsize);
}
/*
** check whether buffer is using a userdata on the stack as a temporary
** buffer
@@ -455,11 +513,12 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
if (newsize < B->n || newsize - B->n < sz)
luaL_error(L, "buffer too large");
/* create larger buffer */
newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));
/* move content to new buffer */
memcpy(newbuff, B->b, B->n * sizeof(char));
if (buffonstack(B))
lua_remove(L, -2); /* remove old buffer */
newbuff = (char *)resizebox(L, -1, newsize);
else { /* no buffer yet */
newbuff = (char *)newbox(L, newsize);
memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */
}
B->b = newbuff;
B->size = newsize;
}
@@ -468,9 +527,11 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
char *b = luaL_prepbuffsize(B, l);
memcpy(b, s, l * sizeof(char));
luaL_addsize(B, l);
if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */
char *b = luaL_prepbuffsize(B, l);
memcpy(b, s, l * sizeof(char));
luaL_addsize(B, l);
}
}
@@ -482,8 +543,10 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
lua_State *L = B->L;
lua_pushlstring(L, B->b, B->n);
if (buffonstack(B))
lua_remove(L, -2); /* remove old buffer */
if (buffonstack(B)) {
resizebox(L, -2, 0); /* delete old buffer */
lua_remove(L, -2); /* remove its header from the stack */
}
}
@@ -605,7 +668,7 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
static int skipBOM (LoadF *lf) {
const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
int c;
lf->n = 0;
do {
@@ -630,7 +693,7 @@ static int skipcomment (LoadF *lf, int *cp) {
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
c = getc(lf->f);
} while (c != EOF && c != '\n') ;
} while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */
return 1; /* there was a comment */
}
@@ -972,29 +1035,28 @@ LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
// use clonefunction
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
#include "spinlock.h"
struct codecache {
int lock;
struct spinlock lock;
lua_State *L;
};
static struct codecache CC = { 0 , NULL };
static struct codecache CC;
static void
clearcache() {
if (CC.L == NULL)
return;
LOCK(&CC)
SPIN_LOCK(&CC)
lua_close(CC.L);
CC.L = luaL_newstate();
UNLOCK(&CC)
SPIN_UNLOCK(&CC)
}
static void
init() {
CC.lock = 0;
SPIN_INIT(&CC);
CC.L = luaL_newstate();
}
@@ -1002,13 +1064,13 @@ static const void *
load(const char *key) {
if (CC.L == NULL)
return NULL;
LOCK(&CC)
SPIN_LOCK(&CC)
lua_State *L = CC.L;
lua_pushstring(L, key);
lua_rawget(L, LUA_REGISTRYINDEX);
const void * result = lua_touserdata(L, -1);
lua_pop(L, 1);
UNLOCK(&CC)
SPIN_UNLOCK(&CC)
return result;
}
@@ -1018,7 +1080,7 @@ save(const char *key, const void * proto) {
lua_State *L;
const void * result = NULL;
LOCK(&CC)
SPIN_LOCK(&CC)
if (CC.L == NULL) {
init();
L = CC.L;
@@ -1036,17 +1098,66 @@ save(const char *key, const void * proto) {
lua_pop(L,2);
}
}
UNLOCK(&CC)
SPIN_UNLOCK(&CC)
return result;
}
#define CACHE_OFF 0
#define CACHE_EXIST 1
#define CACHE_ON 2
static int cache_key = 0;
static int cache_level(lua_State *L) {
int t = lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key);
int r = lua_tointeger(L, -1);
lua_pop(L,1);
if (t == LUA_TNUMBER) {
return r;
}
return CACHE_ON;
}
static int cache_mode(lua_State *L) {
static const char * lst[] = {
"OFF",
"EXIST",
"ON",
NULL,
};
if (lua_isnoneornil(L,1)) {
int t = lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key);
int r = lua_tointeger(L, -1);
if (t == LUA_TNUMBER) {
if (r < 0 || r >= CACHE_ON) {
r = CACHE_ON;
}
} else {
r = CACHE_ON;
}
lua_pushstring(L, lst[r]);
return 1;
}
int t = luaL_checkoption(L, 1, "OFF" , lst);
lua_pushinteger(L, t);
lua_rawsetp(L, LUA_REGISTRYINDEX, &cache_key);
return 0;
}
LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
const char *mode) {
int level = cache_level(L);
if (level == CACHE_OFF) {
return luaL_loadfilex_(L, filename, mode);
}
const void * proto = load(filename);
if (proto) {
lua_clonefunction(L, proto);
return LUA_OK;
}
if (level == CACHE_EXIST) {
return luaL_loadfilex_(L, filename, mode);
}
lua_State * eL = luaL_newstate();
if (eL == NULL) {
lua_pushliteral(L, "New state failed");
@@ -1083,10 +1194,11 @@ cache_clear(lua_State *L) {
LUAMOD_API int luaopen_cache(lua_State *L) {
luaL_Reg l[] = {
{ "clear", cache_clear },
{ "mode", cache_mode },
{ NULL, NULL },
};
luaL_newlib(L,l);
lua_getglobal(L, "loadfile");
lua_setfield(L, -2, "loadfile");
return 1;
}
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lauxlib.h,v 1.128 2014/10/29 16:11:17 roberto Exp $
** $Id: lauxlib.h,v 1.129 2015/11/23 11:29:43 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@@ -65,7 +65,7 @@ LUALIB_API int (luaL_checkoption) (lua_State *L, int arg, const char *def,
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
/* pre-defined references */
/* predefined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)

View File

@@ -1,5 +1,5 @@
/*
** $Id: lbaselib.c,v 1.310 2015/03/28 19:14:47 roberto Exp $
** $Id: lbaselib.c,v 1.313 2016/04/11 19:18:40 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
@@ -86,8 +86,8 @@ static int luaB_tonumber (lua_State *L) {
const char *s;
lua_Integer n = 0; /* to avoid warnings */
lua_Integer base = luaL_checkinteger(L, 2);
luaL_checktype(L, 1, LUA_TSTRING); /* before 'luaL_checklstring'! */
s = luaL_checklstring(L, 1, &l);
luaL_checktype(L, 1, LUA_TSTRING); /* no numbers as strings */
s = lua_tolstring(L, 1, &l);
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
if (b_str2int(s, (int)base, &n) == s + l) {
lua_pushinteger(L, n);
@@ -102,8 +102,8 @@ static int luaB_tonumber (lua_State *L) {
static int luaB_error (lua_State *L) {
int level = (int)luaL_optinteger(L, 2, 1);
lua_settop(L, 1);
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
luaL_where(L, level);
if (lua_type(L, 1) == LUA_TSTRING && level > 0) {
luaL_where(L, level); /* add extra information */
lua_pushvalue(L, 1);
lua_concat(L, 2);
}
@@ -198,12 +198,10 @@ static int luaB_collectgarbage (lua_State *L) {
}
/*
** This function has all type names as upvalues, to maximize performance.
*/
static int luaB_type (lua_State *L) {
luaL_checkany(L, 1);
lua_pushvalue(L, lua_upvalueindex(lua_type(L, 1) + 1));
int t = lua_type(L, 1);
luaL_argcheck(L, t != LUA_TNONE, 1, "value expected");
lua_pushstring(L, lua_typename(L, t));
return 1;
}
@@ -243,18 +241,7 @@ static int luaB_pairs (lua_State *L) {
/*
** Traversal function for 'ipairs' for raw tables
*/
static int ipairsaux_raw (lua_State *L) {
lua_Integer i = luaL_checkinteger(L, 2) + 1;
luaL_checktype(L, 1, LUA_TTABLE);
lua_pushinteger(L, i);
return (lua_rawgeti(L, 1, i) == LUA_TNIL) ? 1 : 2;
}
/*
** Traversal function for 'ipairs' for tables with metamethods
** Traversal function for 'ipairs'
*/
static int ipairsaux (lua_State *L) {
lua_Integer i = luaL_checkinteger(L, 2) + 1;
@@ -264,18 +251,15 @@ static int ipairsaux (lua_State *L) {
/*
** This function will use either 'ipairsaux' or 'ipairsaux_raw' to
** traverse a table, depending on whether the table has metamethods
** that can affect the traversal.
** 'ipairs' function. Returns 'ipairsaux', given "table", 0.
** (The given "table" may not be a table.)
*/
static int luaB_ipairs (lua_State *L) {
lua_CFunction iter = (luaL_getmetafield(L, 1, "__index") != LUA_TNIL)
? ipairsaux : ipairsaux_raw;
#if defined(LUA_COMPAT_IPAIRS)
return pairsmeta(L, "__ipairs", 1, iter);
return pairsmeta(L, "__ipairs", 1, ipairsaux);
#else
luaL_checkany(L, 1);
lua_pushcfunction(L, iter); /* iteration function */
lua_pushcfunction(L, ipairsaux); /* iteration function */
lua_pushvalue(L, 1); /* state */
lua_pushinteger(L, 0); /* initial value */
return 3;
@@ -490,9 +474,9 @@ static const luaL_Reg base_funcs[] = {
{"setmetatable", luaB_setmetatable},
{"tonumber", luaB_tonumber},
{"tostring", luaB_tostring},
{"type", luaB_type},
{"xpcall", luaB_xpcall},
/* placeholders */
{"type", NULL},
{"_G", NULL},
{"_VERSION", NULL},
{NULL, NULL}
@@ -500,7 +484,6 @@ static const luaL_Reg base_funcs[] = {
LUAMOD_API int luaopen_base (lua_State *L) {
int i;
/* open lib into global table */
lua_pushglobaltable(L);
luaL_setfuncs(L, base_funcs, 0);
@@ -510,11 +493,6 @@ LUAMOD_API int luaopen_base (lua_State *L) {
/* set global _VERSION */
lua_pushliteral(L, LUA_VERSION);
lua_setfield(L, -2, "_VERSION");
/* set function 'type' with proper upvalues */
for (i = 0; i < LUA_NUMTAGS; i++) /* push all type names as upvalues */
lua_pushstring(L, lua_typename(L, i));
lua_pushcclosure(L, luaB_type, LUA_NUMTAGS);
lua_setfield(L, -2, "type");
return 1;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lbitlib.c,v 1.28 2014/11/02 19:19:04 roberto Exp $
** $Id: lbitlib.c,v 1.30 2015/11/11 19:08:09 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/
@@ -19,6 +19,10 @@
#if defined(LUA_COMPAT_BITLIB) /* { */
#define pushunsigned(L,n) lua_pushinteger(L, (lua_Integer)(n))
#define checkunsigned(L,i) ((lua_Unsigned)luaL_checkinteger(L,i))
/* number of bits to consider in a number */
#if !defined(LUA_NBITS)
#define LUA_NBITS 32
@@ -46,14 +50,14 @@ static lua_Unsigned andaux (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = ~(lua_Unsigned)0;
for (i = 1; i <= n; i++)
r &= luaL_checkunsigned(L, i);
r &= checkunsigned(L, i);
return trim(r);
}
static int b_and (lua_State *L) {
lua_Unsigned r = andaux(L);
lua_pushunsigned(L, r);
pushunsigned(L, r);
return 1;
}
@@ -69,8 +73,8 @@ static int b_or (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = 0;
for (i = 1; i <= n; i++)
r |= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
r |= checkunsigned(L, i);
pushunsigned(L, trim(r));
return 1;
}
@@ -79,15 +83,15 @@ static int b_xor (lua_State *L) {
int i, n = lua_gettop(L);
lua_Unsigned r = 0;
for (i = 1; i <= n; i++)
r ^= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
r ^= checkunsigned(L, i);
pushunsigned(L, trim(r));
return 1;
}
static int b_not (lua_State *L) {
lua_Unsigned r = ~luaL_checkunsigned(L, 1);
lua_pushunsigned(L, trim(r));
lua_Unsigned r = ~checkunsigned(L, 1);
pushunsigned(L, trim(r));
return 1;
}
@@ -104,23 +108,23 @@ static int b_shift (lua_State *L, lua_Unsigned r, lua_Integer i) {
else r <<= i;
r = trim(r);
}
lua_pushunsigned(L, r);
pushunsigned(L, r);
return 1;
}
static int b_lshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkinteger(L, 2));
return b_shift(L, checkunsigned(L, 1), luaL_checkinteger(L, 2));
}
static int b_rshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkinteger(L, 2));
return b_shift(L, checkunsigned(L, 1), -luaL_checkinteger(L, 2));
}
static int b_arshift (lua_State *L) {
lua_Unsigned r = luaL_checkunsigned(L, 1);
lua_Unsigned r = checkunsigned(L, 1);
lua_Integer i = luaL_checkinteger(L, 2);
if (i < 0 || !(r & ((lua_Unsigned)1 << (LUA_NBITS - 1))))
return b_shift(L, r, -i);
@@ -128,19 +132,19 @@ static int b_arshift (lua_State *L) {
if (i >= LUA_NBITS) r = ALLONES;
else
r = trim((r >> i) | ~(trim(~(lua_Unsigned)0) >> i)); /* add signal bit */
lua_pushunsigned(L, r);
pushunsigned(L, r);
return 1;
}
}
static int b_rot (lua_State *L, lua_Integer d) {
lua_Unsigned r = luaL_checkunsigned(L, 1);
lua_Unsigned r = checkunsigned(L, 1);
int i = d & (LUA_NBITS - 1); /* i = d % NBITS */
r = trim(r);
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
r = (r << i) | (r >> (LUA_NBITS - i));
lua_pushunsigned(L, trim(r));
pushunsigned(L, trim(r));
return 1;
}
@@ -175,23 +179,22 @@ static int fieldargs (lua_State *L, int farg, int *width) {
static int b_extract (lua_State *L) {
int w;
lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
lua_Unsigned r = trim(checkunsigned(L, 1));
int f = fieldargs(L, 2, &w);
r = (r >> f) & mask(w);
lua_pushunsigned(L, r);
pushunsigned(L, r);
return 1;
}
static int b_replace (lua_State *L) {
int w;
lua_Unsigned r = trim(luaL_checkunsigned(L, 1));
lua_Unsigned v = luaL_checkunsigned(L, 2);
lua_Unsigned r = trim(checkunsigned(L, 1));
lua_Unsigned v = trim(checkunsigned(L, 2));
int f = fieldargs(L, 3, &w);
int m = mask(w);
v &= m; /* erase bits outside given width */
r = (r & ~(m << f)) | (v << f);
lua_pushunsigned(L, r);
lua_Unsigned m = mask(w);
r = (r & ~(m << f)) | ((v & m) << f);
pushunsigned(L, r);
return 1;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*
** $Id: lcode.h,v 1.63 2013/12/30 20:47:58 roberto Exp $
** $Id: lcode.h,v 1.64 2016/01/05 16:22:37 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
@@ -40,7 +40,8 @@ typedef enum BinOpr {
typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
#define getcode(fs,e) ((fs)->f->sp->code[(e)->u.info])
/* get (pointer to) instruction of given 'expdesc' */
#define getinstruction(fs,e) ((fs)->f->sp->code[(e)->u.info])
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)

View File

@@ -1,5 +1,5 @@
/*
** $Id: lcorolib.c,v 1.9 2014/11/02 19:19:04 roberto Exp $
** $Id: lcorolib.c,v 1.10 2016/04/11 19:19:55 roberto Exp $
** Coroutine Library
** See Copyright Notice in lua.h
*/
@@ -75,7 +75,7 @@ static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L));
if (r < 0) {
if (lua_isstring(L, -1)) { /* error object is a string? */
if (lua_type(L, -1) == LUA_TSTRING) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */
lua_insert(L, -2);
lua_concat(L, 2);

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldblib.c,v 1.149 2015/02/19 17:06:21 roberto Exp $
** $Id: ldblib.c,v 1.151 2015/11/23 11:29:43 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
@@ -28,8 +28,8 @@ static const int HOOKKEY = 0;
/*
** If L1 != L, L1 can be in any state, and therefore there is no
** garanties about its stack space; any push in L1 must be
** If L1 != L, L1 can be in any state, and therefore there are no
** guarantees about its stack space; any push in L1 must be
** checked.
*/
static void checkstack (lua_State *L, lua_State *L1, int n) {

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldebug.c,v 2.115 2015/05/22 17:45:56 roberto Exp $
** $Id: ldebug.c,v 2.120 2016/03/31 19:01:21 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
@@ -69,7 +69,13 @@ static void swapextra (lua_State *L) {
/*
** this function can be called asynchronous (e.g. during a signal)
** This function can be called asynchronously (e.g. during a signal).
** Fields 'oldpc', 'basehookcount', and 'hookcount' (set by
** 'resethookcount') are for debug only, and it is no problem if they
** get arbitrary values (causes at most one wrong hook call). 'hookmask'
** is an atomic value. We assume that pointers are atomic too (e.g., gcc
** ensures that for all platforms where it runs). Moreover, 'hook' is
** always checked before being called (see 'luaD_hook').
*/
LUA_API void lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
if (func == NULL || mask == 0) { /* turn off hooks? */
@@ -118,7 +124,7 @@ LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
static const char *upvalname (Proto *p, int uv) {
TString *s = check_exp(uv < p->sizeupvalues, p->sp->upvalues[uv].name);
TString *s = check_exp(uv < p->sp->sizeupvalues, p->sp->upvalues[uv].name);
if (s == NULL) return "?";
else return getstr(s);
}
@@ -558,7 +564,7 @@ static const char *varinfo (lua_State *L, const TValue *o) {
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
const char *t = objtypename(o);
const char *t = luaT_objtypename(L, o);
luaG_runerror(L, "attempt to %s a %s value%s", op, t, varinfo(L, o));
}
@@ -590,9 +596,9 @@ l_noret luaG_tointerror (lua_State *L, const TValue *p1, const TValue *p2) {
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
const char *t1 = objtypename(p1);
const char *t2 = objtypename(p2);
if (t1 == t2)
const char *t1 = luaT_objtypename(L, p1);
const char *t2 = luaT_objtypename(L, p2);
if (strcmp(t1, t2) == 0)
luaG_runerror(L, "attempt to compare two %s values", t1);
else
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
@@ -618,7 +624,7 @@ l_noret luaG_errormsg (lua_State *L) {
setobjs2s(L, L->top, L->top - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */
L->top++; /* assume EXTRA_STACK */
luaD_call(L, L->top - 2, 1, 0); /* call it */
luaD_callnoyield(L, L->top - 2, 1); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
@@ -640,9 +646,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
void luaG_traceexec (lua_State *L) {
CallInfo *ci = L->ci;
lu_byte mask = L->hookmask;
int counthook = ((mask & LUA_MASKCOUNT) && L->hookcount == 0);
int counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT));
if (counthook)
resethookcount(L); /* reset count */
else if (!(mask & LUA_MASKLINE))
return; /* no line hook and count != 0; nothing to be done */
if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */
ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */
return; /* do not call hook again (VM yielded, so it did not move) */

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldo.c,v 2.138 2015/05/22 17:48:19 roberto Exp $
** $Id: ldo.c,v 2.151 2015/12/16 16:40:07 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -150,6 +150,11 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
/* }====================================================== */
/*
** {==================================================================
** Stack reallocation
** ===================================================================
*/
static void correctstack (lua_State *L, TValue *oldstack) {
CallInfo *ci;
UpVal *up;
@@ -221,17 +226,30 @@ void luaD_shrinkstack (lua_State *L) {
luaE_freeCI(L); /* free all CIs (list grew because of an error) */
else
luaE_shrinkCI(L); /* shrink list */
if (inuse > LUAI_MAXSTACK || /* still handling stack overflow? */
goodsize >= L->stacksize) /* would grow instead of shrink? */
condmovestack(L); /* don't change stack (change only for debugging) */
else
if (inuse <= LUAI_MAXSTACK && /* not handling stack overflow? */
goodsize < L->stacksize) /* trying to shrink? */
luaD_reallocstack(L, goodsize); /* shrink it */
else
condmovestack(L,,); /* don't change stack (change only for debugging) */
}
void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1);
L->top++;
}
/* }================================================================== */
/*
** Call a hook for the given event. Make sure there is a hook to be
** called. (Both 'L->hook' and 'L->hookmask', which triggers this
** function, can be changed asynchronously by signals.)
*/
void luaD_hook (lua_State *L, int event, int line) {
lua_Hook hook = L->hook;
if (hook && L->allowhook) {
if (hook && L->allowhook) { /* make sure there is a hook */
CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top);
ptrdiff_t ci_top = savestack(L, ci->top);
@@ -273,15 +291,15 @@ static StkId adjust_varargs (lua_State *L, SharedProto *p, int actual) {
int i;
int nfixargs = p->numparams;
StkId base, fixed;
lua_assert(actual >= nfixargs);
/* move fixed parameters to final position */
luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */
fixed = L->top - actual; /* first fixed argument */
base = L->top; /* final position of first argument */
for (i=0; i<nfixargs; i++) {
for (i = 0; i < nfixargs && i < actual; i++) {
setobjs2s(L, L->top++, fixed + i);
setnilvalue(fixed + i);
setnilvalue(fixed + i); /* erase original copy (for GC) */
}
for (; i < nfixargs; i++)
setnilvalue(L->top++); /* complete missing arguments */
return base;
}
@@ -308,26 +326,36 @@ static void tryfuncTM (lua_State *L, StkId func) {
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
/* macro to check stack size, preserving 'p' */
#define checkstackp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
luaC_checkGC(L), /* stack grow uses memory */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/*
** returns true if function has been executed (C function)
** Prepares a function call: checks the stack, creates a new CallInfo
** entry, fills in the relevant information, calls hook if needed.
** If function is a C function, does the call, too. (Otherwise, leave
** the execution ('luaV_execute') to the caller, to allow stackless
** calls.) Returns true iff function has been executed (C function).
*/
int luaD_precall (lua_State *L, StkId func, int nresults) {
lua_CFunction f;
CallInfo *ci;
int n; /* number of arguments (Lua) or returns (C) */
ptrdiff_t funcr = savestack(L, func);
switch (ttype(func)) {
case LUA_TCCL: /* C closure */
f = clCvalue(func)->f;
goto Cfunc;
case LUA_TLCF: /* light C function */
f = fvalue(func);
goto Cfunc;
case LUA_TCCL: { /* C closure */
f = clCvalue(func)->f;
Cfunc:
luaC_checkGC(L); /* stack grow uses memory */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
Cfunc: {
int n; /* number of returns */
checkstackp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = restorestack(L, funcr);
ci->func = func;
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
ci->callstatus = 0;
@@ -337,41 +365,36 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
luaD_poscall(L, L->top - n, n);
luaD_poscall(L, ci, L->top - n, n);
return 1;
}
case LUA_TLCL: { /* Lua function: prepare its call */
StkId base;
SharedProto *p = clLvalue(func)->p->sp;
n = cast_int(L->top - func) - 1; /* number of real arguments */
luaC_checkGC(L); /* stack grow uses memory */
luaD_checkstack(L, p->maxstacksize);
for (; n < p->numparams; n++)
setnilvalue(L->top++); /* complete missing arguments */
if (!p->is_vararg) {
func = restorestack(L, funcr);
int n = cast_int(L->top - func) - 1; /* number of real arguments */
int fsize = p->maxstacksize; /* frame size */
checkstackp(L, fsize, func);
if (p->is_vararg != 1) { /* do not use vararg? */
for (; n < p->numparams; n++)
setnilvalue(L->top++); /* complete missing arguments */
base = func + 1;
}
else {
else
base = adjust_varargs(L, p, n);
func = restorestack(L, funcr); /* previous call can change stack */
}
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = func;
ci->u.l.base = base;
ci->top = base + p->maxstacksize;
L->top = ci->top = base + fsize;
lua_assert(ci->top <= L->stack_last);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus = CIST_LUA;
L->top = ci->top;
if (L->hookmask & LUA_MASKCALL)
callhook(L, ci);
return 0;
}
default: { /* not a function */
luaD_checkstack(L, 1); /* ensure space for metamethod */
func = restorestack(L, funcr); /* previous call may change stack */
checkstackp(L, 1, func); /* ensure space for metamethod */
tryfuncTM(L, func); /* try to get '__call' metamethod */
return luaD_precall(L, func, nresults); /* now it must be a function */
}
@@ -379,10 +402,57 @@ int luaD_precall (lua_State *L, StkId func, int nresults) {
}
int luaD_poscall (lua_State *L, StkId firstResult, int nres) {
/*
** Given 'nres' results at 'firstResult', move 'wanted' of them to 'res'.
** Handle most typical cases (zero results for commands, one result for
** expressions, multiple results for tail calls/single parameters)
** separated.
*/
static int moveresults (lua_State *L, const TValue *firstResult, StkId res,
int nres, int wanted) {
switch (wanted) { /* handle typical cases separately */
case 0: break; /* nothing to move */
case 1: { /* one result needed */
if (nres == 0) /* no results? */
firstResult = luaO_nilobject; /* adjust with nil */
setobjs2s(L, res, firstResult); /* move it to proper place */
break;
}
case LUA_MULTRET: {
int i;
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstResult + i);
L->top = res + nres;
return 0; /* wanted == LUA_MULTRET */
}
default: {
int i;
if (wanted <= nres) { /* enough results? */
for (i = 0; i < wanted; i++) /* move wanted results to correct place */
setobjs2s(L, res + i, firstResult + i);
}
else { /* not enough results; use all of them plus nils */
for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstResult + i);
for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(res + i);
}
break;
}
}
L->top = res + wanted; /* top points after the last result */
return 1;
}
/*
** Finishes a function call: calls hook if necessary, removes CallInfo,
** moves current number of results to proper place; returns 0 iff call
** wanted multiple (variable number of) results.
*/
int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres) {
StkId res;
int wanted, i;
CallInfo *ci = L->ci;
int wanted = ci->nresults;
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
if (L->hookmask & LUA_MASKRET) {
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
@@ -392,15 +462,24 @@ int luaD_poscall (lua_State *L, StkId firstResult, int nres) {
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
}
res = ci->func; /* res == final position of 1st result */
wanted = ci->nresults;
L->ci = ci->previous; /* back to caller */
/* move results to correct place */
for (i = wanted; i != 0 && nres-- > 0; i--)
setobjs2s(L, res++, firstResult++);
while (i-- > 0)
setnilvalue(res++);
L->top = res;
return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */
/* move results to proper place */
return moveresults(L, firstResult, res, nres, wanted);
}
/*
** Check appropriate error for stack overflow ("regular" overflow or
** overflow while handling stack overflow). If 'nCalls' is larger than
** LUAI_MAXCCALLS (which means it is handling a "regular" overflow) but
** smaller than 9/8 of LUAI_MAXCCALLS, does not report an error (to
** allow overflow handling to work)
*/
static void stackerror (lua_State *L) {
if (L->nCcalls == LUAI_MAXCCALLS)
luaG_runerror(L, "C stack overflow");
else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
}
@@ -410,21 +489,25 @@ int luaD_poscall (lua_State *L, StkId firstResult, int nres) {
** When returns, all the results are on the stack, starting at the original
** function position.
*/
void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
if (++L->nCcalls >= LUAI_MAXCCALLS) {
if (L->nCcalls == LUAI_MAXCCALLS)
luaG_runerror(L, "C stack overflow");
else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
}
if (!allowyield) L->nny++;
void luaD_call (lua_State *L, StkId func, int nResults) {
if (++L->nCcalls >= LUAI_MAXCCALLS)
stackerror(L);
if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
luaV_execute(L); /* call it */
if (!allowyield) L->nny--;
L->nCcalls--;
}
/*
** Similar to 'luaD_call', but does not allow yields during the call
*/
void luaD_callnoyield (lua_State *L, StkId func, int nResults) {
L->nny++;
luaD_call(L, func, nResults);
L->nny--;
}
/*
** Completes the execution of an interrupted C function, calling its
** continuation function.
@@ -449,7 +532,7 @@ static void finishCcall (lua_State *L, int status) {
lua_lock(L);
api_checknelems(L, n);
/* finish 'luaD_precall' */
luaD_poscall(L, L->top - n, n);
luaD_poscall(L, ci, L->top - n, n);
}
@@ -560,7 +643,7 @@ static void resume (lua_State *L, void *ud) {
api_checknelems(L, n);
firstArg = L->top - n; /* yield results come from continuation */
}
luaD_poscall(L, firstArg, n); /* finish 'luaD_precall' */
luaD_poscall(L, ci, firstArg, n); /* finish 'luaD_precall' */
}
unroll(L, NULL); /* run continuation */
}
@@ -570,7 +653,7 @@ static void resume (lua_State *L, void *ud) {
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
int status;
int oldnny = L->nny; /* save "number of non-yieldable" calls */
unsigned short oldnny = L->nny; /* save "number of non-yieldable" calls */
lua_lock(L);
luai_userstateresume(L, nargs);
L->nCcalls = (from) ? from->nCcalls + 1 : 1;
@@ -684,13 +767,13 @@ static void f_parser (lua_State *L, void *ud) {
int c = zgetc(p->z); /* read first character */
if (c == LUA_SIGNATURE[0]) {
checkmode(L, p->mode, "binary");
cl = luaU_undump(L, p->z, &p->buff, p->name);
cl = luaU_undump(L, p->z, p->name);
}
else {
checkmode(L, p->mode, "text");
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
}
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
lua_assert(cl->nupvalues == cl->p->sp->sizeupvalues);
luaF_initupvals(L, cl);
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldo.h,v 2.22 2015/05/22 17:48:19 roberto Exp $
** $Id: ldo.h,v 2.29 2015/12/21 13:02:14 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -13,11 +13,21 @@
#include "lzio.h"
#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \
luaD_growstack(L, n); else condmovestack(L);
/*
** Macro to check stack size and grow stack if needed. Parameters
** 'pre'/'pos' allow the macro to preserve a pointer into the
** stack across reallocations, doing the work only when needed.
** 'condmovestack' is used in heavy tests to force a stack reallocation
** at every check.
*/
#define luaD_checkstackaux(L,n,pre,pos) \
if (L->stack_last - L->top <= (n)) \
{ pre; luaD_growstack(L, n); pos; } else { condmovestack(L,pre,pos); }
/* In general, 'pre'/'pos' are empty (nothing to save) */
#define luaD_checkstack(L,n) luaD_checkstackaux(L,n,(void)0,(void)0)
#define incr_top(L) {L->top++; luaD_checkstack(L,0);}
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
@@ -30,14 +40,16 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode);
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line);
LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults,
int allowyield);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef);
LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult, int nres);
LUAI_FUNC int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult,
int nres);
LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
LUAI_FUNC void luaD_inctop (lua_State *L);
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);

View File

@@ -1,5 +1,5 @@
/*
** $Id: ldump.c,v 2.36 2015/03/30 15:43:51 roberto Exp $
** $Id: ldump.c,v 2.37 2015/10/08 15:53:49 roberto Exp $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -38,7 +38,7 @@ typedef struct {
static void DumpBlock (const void *b, size_t size, DumpState *D) {
if (D->status == 0) {
if (D->status == 0 && size > 0) {
lua_unlock(D->L);
D->status = (*D->writer)(D->L, b, size, D->data);
lua_lock(D->L);

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->locvars, f->sizelocvars);
luaM_freearray(L, f->upvalues, f->sizeupvalues);
luaM_free(L, f);
}
void luaF_freeproto (lua_State *L, Proto *f) {

View File

@@ -1,5 +1,5 @@
/*
** $Id: lgc.c,v 2.205 2015/03/25 13:42:19 roberto Exp $
** $Id: lgc.c,v 2.212 2016/03/31 19:02:03 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -114,8 +114,13 @@ static void reallymarkobject (global_State *g, GCObject *o);
/*
** if key is not marked, mark its entry as dead (therefore removing it
** from the table)
** If key is not marked, mark its entry as dead. This allows key to be
** collected, but keeps its entry in the table. A dead node is needed
** when Lua looks up for a key (it may be part of a chain) and when
** traversing a weak table (key might be removed from the table during
** traversal). Other places never manipulate dead keys, because its
** associated nil value is enough to signal that the entry is logically
** empty.
*/
static void removeentry (Node *n) {
lua_assert(ttisnil(gval(n)));
@@ -188,7 +193,8 @@ void luaC_upvalbarrier_ (lua_State *L, UpVal *uv) {
void luaC_fix (lua_State *L, GCObject *o) {
global_State *g = G(L);
lua_assert(g->allgc == o); /* object must be 1st in 'allgc' list! */
if (g->allgc != o)
return; /* if object is not 1st in 'allgc' list, it is in global short string table */
white2gray(o); /* they will be gray forever */
g->allgc = o->next; /* remove object from 'allgc' list */
o->next = g->fixedgc; /* link it to 'fixedgc' list */
@@ -486,15 +492,19 @@ static int marksharedproto (global_State *g, SharedProto *f) {
** NULL, so the use of 'markobjectN')
*/
static int traverseproto (global_State *g, Proto *f) {
int i;
int i,nk,np;
if (f->cache && iswhite(f->cache))
f->cache = NULL; /* allow cache to be collected */
for (i = 0; i < f->sp->sizek; i++) /* mark literals */
if (f->sp == NULL)
return sizeof(Proto);
nk = (f->k == NULL) ? 0 : f->sp->sizek;
np = (f->p == NULL) ? 0 : f->sp->sizep;
for (i = 0; i < nk; i++) /* mark literals */
markvalue(g, &f->k[i]);
for (i = 0; i < f->sp->sizep; i++) /* mark nested protos */
for (i = 0; i < np; i++) /* mark nested protos */
markobjectN(g, f->p[i]);
return sizeof(Proto) + sizeof(Proto *) * f->sp->sizep +
sizeof(TValue) * f->sp->sizek +
return sizeof(Proto) + sizeof(Proto *) * np +
sizeof(TValue) * nk +
marksharedproto(g, f->sp);
}
@@ -548,7 +558,8 @@ static lu_mem traversethread (global_State *g, lua_State *th) {
}
else if (g->gckind != KGC_EMERGENCY)
luaD_shrinkstack(th); /* do not change stack in emergency cycle */
return (sizeof(lua_State) + sizeof(TValue) * th->stacksize);
return (sizeof(lua_State) + sizeof(TValue) * th->stacksize +
sizeof(CallInfo) * th->nci);
}
@@ -754,14 +765,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
/*
** sweep a list until a live object (or end of list)
*/
static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
static GCObject **sweeptolive (lua_State *L, GCObject **p) {
GCObject **old = p;
int i = 0;
do {
i++;
p = sweeplist(L, p, 1);
} while (p == old);
if (n) *n += i;
return p;
}
@@ -775,12 +783,11 @@ static GCObject **sweeptolive (lua_State *L, GCObject **p, int *n) {
*/
/*
** If possible, free concatenation buffer and shrink string table
** If possible, shrink string table
*/
static void checkSizes (lua_State *L, global_State *g) {
if (g->gckind != KGC_EMERGENCY) {
l_mem olddebt = g->GCdebt;
luaZ_freebuffer(L, &g->buff); /* free concatenation buffer */
if (g->strt.nuse < g->strt.size / 4) /* string table too big? */
luaS_resize(L, g->strt.size / 2); /* shrink it a little */
g->GCestimate += g->GCdebt - olddebt; /* update estimate */
@@ -803,7 +810,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) {
UNUSED(ud);
luaD_call(L, L->top - 2, 0, 0);
luaD_callnoyield(L, L->top - 2, 0);
}
@@ -857,10 +864,10 @@ static int runafewfinalizers (lua_State *L) {
/*
** call all pending finalizers
*/
static void callallpendingfinalizers (lua_State *L, int propagateerrors) {
static void callallpendingfinalizers (lua_State *L) {
global_State *g = G(L);
while (g->tobefnz)
GCTM(L, propagateerrors);
GCTM(L, 0);
}
@@ -910,7 +917,7 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
if (issweepphase(g)) {
makewhite(g, o); /* "sweep" object 'o' */
if (g->sweepgc == &o->next) /* should not remove 'sweepgc' object */
g->sweepgc = sweeptolive(L, g->sweepgc, NULL); /* change 'sweepgc' */
g->sweepgc = sweeptolive(L, g->sweepgc); /* change 'sweepgc' */
}
/* search for pointer pointing to 'o' */
for (p = &g->allgc; *p != o; p = &(*p)->next) { /* empty */ }
@@ -952,19 +959,16 @@ static void setpause (global_State *g) {
/*
** Enter first sweep phase.
** The call to 'sweeptolive' makes pointer point to an object inside
** the list (instead of to the header), so that the real sweep do not
** need to skip objects created between "now" and the start of the real
** sweep.
** Returns how many objects it swept.
** The call to 'sweeplist' tries to make pointer point to an object
** inside the list (instead of to the header), so that the real sweep do
** not need to skip objects created between "now" and the start of the
** real sweep.
*/
static int entersweep (lua_State *L) {
static void entersweep (lua_State *L) {
global_State *g = G(L);
int n = 0;
g->gcstate = GCSswpallgc;
lua_assert(g->sweepgc == NULL);
g->sweepgc = sweeptolive(L, &g->allgc, &n);
return n;
g->sweepgc = sweeplist(L, &g->allgc, 1);
}
@@ -972,7 +976,7 @@ void luaC_freeallobjects (lua_State *L) {
global_State *g = G(L);
separatetobefnz(g, 1); /* separate all objects with finalizers */
lua_assert(g->finobj == NULL);
callallpendingfinalizers(L, 0);
callallpendingfinalizers(L);
lua_assert(g->tobefnz == NULL);
g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
g->gckind = KGC_NORMAL;
@@ -1065,12 +1069,11 @@ static lu_mem singlestep (lua_State *L) {
}
case GCSatomic: {
lu_mem work;
int sw;
propagateall(g); /* make sure gray list is empty */
work = atomic(L); /* work is what was traversed by 'atomic' */
sw = entersweep(L);
entersweep(L);
g->GCestimate = gettotalbytes(g); /* first estimate */;
return work + sw * GCSWEEPCOST;
return work;
}
case GCSswpallgc: { /* sweep "regular" objects */
return sweepstep(L, g, GCSswpfinobj, &g->finobj);
@@ -1120,9 +1123,12 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
static l_mem getdebt (global_State *g) {
l_mem debt = g->GCdebt;
int stepmul = g->gcstepmul;
debt = (debt / STEPMULADJ) + 1;
debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
return debt;
if (debt <= 0) return 0; /* minimal debt */
else {
debt = (debt / STEPMULADJ) + 1;
debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
return debt;
}
}
/*

View File

@@ -1,5 +1,5 @@
/*
** $Id: lgc.h,v 2.86 2014/10/25 11:50:46 roberto Exp $
** $Id: lgc.h,v 2.91 2015/12/21 13:02:14 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@@ -101,26 +101,35 @@
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
#define luaC_condGC(L,c) \
{if (G(L)->GCdebt > 0) {c;}; condchangemem(L);}
#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);)
/*
** Does one step of collection when debt becomes positive. 'pre'/'pos'
** allows some adjustments to be done only when needed. macro
** 'condchangemem' is used only for heavy tests (forcing a full
** GC cycle on every opportunity)
*/
#define luaC_condGC(L,pre,pos) \
{ if (G(L)->GCdebt > 0) { pre; luaC_step(L); pos;}; \
condchangemem(L,pre,pos); }
/* more often than not, 'pre'/'pos' are empty */
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_barrier(L,p,v) { \
if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
#define luaC_barrier(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
#define luaC_barrierback(L,p,v) { \
if (iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) \
luaC_barrierback_(L,p); }
#define luaC_barrierback(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrierback_(L,p) : cast_void(0))
#define luaC_objbarrier(L,p,o) { \
if (isblack(p) && iswhite(o)) \
luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
#define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_upvalbarrier(L,uv) \
{ if (iscollectable((uv)->v) && !upisopen(uv)) \
luaC_upvalbarrier_(L,uv); }
#define luaC_upvalbarrier(L,uv) ( \
(iscollectable((uv)->v) && !upisopen(uv)) ? \
luaC_upvalbarrier_(L,uv) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L);

View File

@@ -1,5 +1,5 @@
/*
** $Id: liolib.c,v 2.144 2015/04/03 18:41:57 roberto Exp $
** $Id: liolib.c,v 2.149 2016/05/02 14:03:19 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
@@ -23,18 +23,24 @@
#include "lualib.h"
#if !defined(l_checkmode)
/*
** Check whether 'mode' matches '[rwa]%+?b?'.
** Change this macro to accept other modes for 'fopen' besides
** the standard ones.
*/
#if !defined(l_checkmode)
/* accepted extensions to 'mode' in 'fopen' */
#if !defined(L_MODEEXT)
#define L_MODEEXT "b"
#endif
/* Check whether 'mode' matches '[rwa]%+?[L_MODEEXT]*' */
#define l_checkmode(mode) \
(*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
(*mode != '+' || ++mode) && /* skip if char is '+' */ \
(*mode != 'b' || ++mode) && /* skip if char is 'b' */ \
(*mode == '\0'))
(*mode != '+' || (++mode, 1)) && /* skip if char is '+' */ \
(strspn(mode, L_MODEEXT) == strlen(mode)))
#endif
@@ -176,7 +182,7 @@ static FILE *tofile (lua_State *L) {
/*
** When creating file handles, always creates a 'closed' file handle
** before opening the actual file; so, if there is a memory error, the
** file is not left opened.
** handle is in a consistent state.
*/
static LStream *newprefile (lua_State *L) {
LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));
@@ -318,8 +324,15 @@ static int io_output (lua_State *L) {
static int io_readline (lua_State *L);
/*
** maximum number of arguments to 'f:lines'/'io.lines' (it + 3 must fit
** in the limit for upvalues of a closure)
*/
#define MAXARGLINE 250
static void aux_lines (lua_State *L, int toclose) {
int n = lua_gettop(L) - 1; /* number of arguments to read */
luaL_argcheck(L, n <= MAXARGLINE, MAXARGLINE + 2, "too many arguments");
lua_pushinteger(L, n); /* number of arguments to read */
lua_pushboolean(L, toclose); /* close/not close file when finished */
lua_rotate(L, 2, 2); /* move 'n' and 'toclose' to their positions */
@@ -362,14 +375,17 @@ static int io_lines (lua_State *L) {
/* maximum length of a numeral */
#define MAXRN 200
#if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
/* auxiliary structure used by 'read_number' */
typedef struct {
FILE *f; /* file being read */
int c; /* current character (look ahead) */
int n; /* number of elements in buffer 'buff' */
char buff[MAXRN + 1]; /* +1 for ending '\0' */
char buff[L_MAXLENNUM + 1]; /* +1 for ending '\0' */
} RN;
@@ -377,7 +393,7 @@ typedef struct {
** Add current char to buffer (if not out of space) and read next one
*/
static int nextc (RN *rn) {
if (rn->n >= MAXRN) { /* buffer overflow? */
if (rn->n >= L_MAXLENNUM) { /* buffer overflow? */
rn->buff[0] = '\0'; /* invalidate result */
return 0; /* fail */
}
@@ -390,10 +406,10 @@ static int nextc (RN *rn) {
/*
** Accept current char if it is in 'set' (of size 1 or 2)
** Accept current char if it is in 'set' (of size 2)
*/
static int test2 (RN *rn, const char *set) {
if (rn->c == set[0] || (rn->c == set[1] && rn->c != '\0'))
if (rn->c == set[0] || rn->c == set[1])
return nextc(rn);
else return 0;
}
@@ -422,11 +438,11 @@ static int read_number (lua_State *L, FILE *f) {
char decp[2];
rn.f = f; rn.n = 0;
decp[0] = lua_getlocaledecpoint(); /* get decimal point from locale */
decp[1] = '\0';
decp[1] = '.'; /* always accept a dot */
l_lockfile(rn.f);
do { rn.c = l_getc(rn.f); } while (isspace(rn.c)); /* skip spaces */
test2(&rn, "-+"); /* optional signal */
if (test2(&rn, "0")) {
if (test2(&rn, "00")) {
if (test2(&rn, "xX")) hex = 1; /* numeral is hexadecimal */
else count = 1; /* count initial '0' as a valid digit */
}
@@ -462,7 +478,7 @@ static int read_line (lua_State *L, FILE *f, int chop) {
int c = '\0';
luaL_buffinit(L, &b);
while (c != EOF && c != '\n') { /* repeat until end of line */
char *buff = luaL_prepbuffer(&b); /* pre-allocate buffer */
char *buff = luaL_prepbuffer(&b); /* preallocate buffer */
int i = 0;
l_lockfile(f); /* no memory errors can happen inside the lock */
while (i < LUAL_BUFFERSIZE && (c = l_getc(f)) != EOF && c != '\n')
@@ -483,7 +499,7 @@ static void read_all (lua_State *L, FILE *f) {
luaL_Buffer b;
luaL_buffinit(L, &b);
do { /* read file in chunks of LUAL_BUFFERSIZE bytes */
char *p = luaL_prepbuffsize(&b, LUAL_BUFFERSIZE);
char *p = luaL_prepbuffer(&b);
nr = fread(p, sizeof(char), LUAL_BUFFERSIZE, f);
luaL_addsize(&b, nr);
} while (nr == LUAL_BUFFERSIZE);

View File

@@ -1,5 +1,5 @@
/*
** $Id: llex.c,v 2.93 2015/05/22 17:45:56 roberto Exp $
** $Id: llex.c,v 2.96 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -162,7 +162,6 @@ static void inclinenumber (LexState *ls) {
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
int firstchar) {
ls->t.token = 0;
ls->decpoint = '.';
ls->L = L;
ls->current = firstchar;
ls->lookahead.token = TK_EOS; /* no look-ahead token */
@@ -207,37 +206,6 @@ static int check_next2 (LexState *ls, const char *set) {
}
/*
** change all characters 'from' in buffer to 'to'
*/
static void buffreplace (LexState *ls, char from, char to) {
if (from != to) {
size_t n = luaZ_bufflen(ls->buff);
char *p = luaZ_buffer(ls->buff);
while (n--)
if (p[n] == from) p[n] = to;
}
}
#define buff2num(b,o) (luaO_str2num(luaZ_buffer(b), o) != 0)
/*
** in case of format error, try to change decimal point separator to
** the one defined in the current locale and check again
*/
static void trydecpoint (LexState *ls, TValue *o) {
char old = ls->decpoint;
ls->decpoint = lua_getlocaledecpoint();
buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
if (!buff2num(ls->buff, o)) {
/* format error with correct decimal point: no more options */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
lexerror(ls, "malformed number", TK_FLT);
}
}
/* LUA_NUMBER */
/*
** this function is quite liberal in what it accepts, as 'luaO_str2num'
@@ -261,9 +229,8 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
else break;
}
save(ls, '\0');
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
if (!buff2num(ls->buff, &obj)) /* format error? */
trydecpoint(ls, &obj); /* try to update decimal point separator */
if (luaO_str2num(luaZ_buffer(ls->buff), &obj) == 0) /* format error? */
lexerror(ls, "malformed number", TK_FLT);
if (ttisinteger(&obj)) {
seminfo->i = ivalue(&obj);
return TK_INT;
@@ -277,7 +244,7 @@ static int read_numeral (LexState *ls, SemInfo *seminfo) {
/*
** skip a sequence '[=*[' or ']=*]'; if sequence is wellformed, return
** skip a sequence '[=*[' or ']=*]'; if sequence is well formed, return
** its number of '='s; otherwise, return a negative number (-1 iff there
** are no '='s after initial bracket)
*/

View File

@@ -1,5 +1,5 @@
/*
** $Id: llex.h,v 1.78 2014/10/29 15:38:24 roberto Exp $
** $Id: llex.h,v 1.79 2016/05/02 14:02:12 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
@@ -69,7 +69,6 @@ typedef struct LexState {
struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */
TString *envn; /* environment variable name */
char decpoint; /* locale decimal point */
} LexState;

View File

@@ -1,5 +1,5 @@
/*
** $Id: llimits.h,v 1.135 2015/06/09 14:21:00 roberto Exp $
** $Id: llimits.h,v 1.141 2015/11/19 19:16:22 roberto Exp $
** Limits, basic types, and some other 'installation-dependent' definitions
** See Copyright Notice in lua.h
*/
@@ -64,7 +64,13 @@ typedef unsigned char lu_byte;
#if defined(LUAI_USER_ALIGNMENT_T)
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
#else
typedef union { double u; void *s; lua_Integer i; long l; } L_Umaxalign;
typedef union {
lua_Number n;
double u;
void *s;
lua_Integer i;
long l;
} L_Umaxalign;
#endif
@@ -78,7 +84,7 @@ typedef LUAI_UACINT l_uacInt;
#if defined(lua_assert)
#define check_exp(c,e) (lua_assert(c), (e))
/* to avoid problems with conditions too long */
#define lua_longassert(c) { if (!(c)) lua_assert(0); }
#define lua_longassert(c) ((c) ? (void)0 : lua_assert(0))
#else
#define lua_assert(c) ((void)0)
#define check_exp(c,e) (e)
@@ -184,10 +190,13 @@ typedef unsigned long Instruction;
/*
** Size of cache for strings in the API (better be a prime)
** Size of cache for strings in the API. 'N' is the number of
** sets (better be a prime) and "M" is the size of each set (M == 1
** makes a direct cache.)
*/
#if !defined(STRCACHE_SIZE)
#define STRCACHE_SIZE 127
#if !defined(STRCACHE_N)
#define STRCACHE_N 53
#define STRCACHE_M 2
#endif
@@ -198,7 +207,7 @@ typedef unsigned long Instruction;
/*
** macros that are executed whenether program enters the Lua core
** macros that are executed whenever program enters the Lua core
** ('lua_lock') and leaves the core ('lua_unlock')
*/
#if !defined(lua_lock)
@@ -297,17 +306,18 @@ typedef unsigned long Instruction;
** macro to control inclusion of some hard tests on stack reallocation
*/
#if !defined(HARDSTACKTESTS)
#define condmovestack(L) ((void)0)
#define condmovestack(L,pre,pos) ((void)0)
#else
/* realloc stack keeping its size */
#define condmovestack(L) luaD_reallocstack((L), (L)->stacksize)
#define condmovestack(L,pre,pos) \
{ int sz_ = (L)->stacksize; pre; luaD_reallocstack((L), sz_); pos; }
#endif
#if !defined(HARDMEMTESTS)
#define condchangemem(L) condmovestack(L)
#define condchangemem(L,pre,pos) ((void)0)
#else
#define condchangemem(L) \
((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1)))
#define condchangemem(L,pre,pos) \
{ if (G(L)->gcrunning) { pre; luaC_fullgc(L, 0); pos; } }
#endif
#endif

View File

@@ -1,5 +1,5 @@
/*
** $Id: lmathlib.c,v 1.115 2015/03/12 14:04:04 roberto Exp $
** $Id: lmathlib.c,v 1.117 2015/10/02 15:39:23 roberto Exp $
** Standard mathematical library
** See Copyright Notice in lua.h
*/
@@ -39,7 +39,7 @@
static int math_abs (lua_State *L) {
if (lua_isinteger(L, 1)) {
lua_Integer n = lua_tointeger(L, 1);
if (n < 0) n = (lua_Integer)(0u - n);
if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n);
lua_pushinteger(L, n);
}
else
@@ -273,7 +273,7 @@ static int math_random (lua_State *L) {
static int math_randomseed (lua_State *L) {
l_srand((unsigned int)(lua_Integer)luaL_checknumber(L, 1));
(void)rand(); /* discard first value to avoid undesirable correlations */
(void)l_rand(); /* discard first value to avoid undesirable correlations */
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: loadlib.c,v 1.126 2015/02/16 13:14:33 roberto Exp $
** $Id: loadlib.c,v 1.127 2015/11/23 11:30:45 roberto Exp $
** Dynamic library loader for Lua
** See Copyright Notice in lua.h
**
@@ -732,7 +732,7 @@ static void createsearcherstable (lua_State *L) {
int i;
/* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);
/* fill it with pre-defined searchers */
/* fill it with predefined searchers */
for (i=0; searchers[i] != NULL; i++) {
lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */
lua_pushcclosure(L, searchers[i], 1);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lobject.c,v 2.104 2015/04/11 18:30:08 roberto Exp $
** $Id: lobject.c,v 2.111 2016/05/20 14:07:48 roberto Exp $
** Some generic functions over Lua objects
** See Copyright Notice in lua.h
*/
@@ -55,9 +55,7 @@ int luaO_int2fb (unsigned int x) {
/* converts back */
int luaO_fb2int (int x) {
int e = (x >> 3) & 0x1f;
if (e == 0) return x;
else return ((x & 7) + 8) << (e - 1);
return (x < 8) ? x : ((x & 7) + 8) << ((x >> 3) - 1);
}
@@ -245,20 +243,59 @@ static lua_Number lua_strx2number (const char *s, char **endptr) {
/* }====================================================== */
static const char *l_str2d (const char *s, lua_Number *result) {
/* maximum length of a numeral */
#if !defined (L_MAXLENNUM)
#define L_MAXLENNUM 200
#endif
static const char *l_str2dloc (const char *s, lua_Number *result, int mode) {
char *endptr;
if (strpbrk(s, "nN")) /* reject 'inf' and 'nan' */
return NULL;
else if (strpbrk(s, "xX")) /* hex? */
*result = lua_strx2number(s, &endptr);
else
*result = lua_str2number(s, &endptr);
if (endptr == s) return NULL; /* nothing recognized */
while (lisspace(cast_uchar(*endptr))) endptr++;
return (*endptr == '\0' ? endptr : NULL); /* OK if no trailing characters */
*result = (mode == 'x') ? lua_strx2number(s, &endptr) /* try to convert */
: lua_str2number(s, &endptr);
if (endptr == s) return NULL; /* nothing recognized? */
while (lisspace(cast_uchar(*endptr))) endptr++; /* skip trailing spaces */
return (*endptr == '\0') ? endptr : NULL; /* OK if no trailing characters */
}
/*
** Convert string 's' to a Lua number (put in 'result'). Return NULL
** on fail or the address of the ending '\0' on success.
** 'pmode' points to (and 'mode' contains) special things in the string:
** - 'x'/'X' means an hexadecimal numeral
** - 'n'/'N' means 'inf' or 'nan' (which should be rejected)
** - '.' just optimizes the search for the common case (nothing special)
** This function accepts both the current locale or a dot as the radix
** mark. If the convertion fails, it may mean number has a dot but
** locale accepts something else. In that case, the code copies 's'
** to a buffer (because 's' is read-only), changes the dot to the
** current locale radix mark, and tries to convert again.
*/
static const char *l_str2d (const char *s, lua_Number *result) {
const char *endptr;
const char *pmode = strpbrk(s, ".xXnN");
int mode = pmode ? ltolower(cast_uchar(*pmode)) : 0;
if (mode == 'n') /* reject 'inf' and 'nan' */
return NULL;
endptr = l_str2dloc(s, result, mode); /* try to convert */
if (endptr == NULL) { /* failed? may be a different locale */
char buff[L_MAXLENNUM + 1];
char *pdot = strchr(s, '.');
if (strlen(s) > L_MAXLENNUM || pdot == NULL)
return NULL; /* string too long or no dot; fail */
strcpy(buff, s); /* copy string to buffer */
buff[pdot - s] = lua_getlocaledecpoint(); /* correct decimal point */
endptr = l_str2dloc(buff, result, mode); /* try again */
if (endptr != NULL)
endptr = s + (endptr - buff); /* make relative to 's' */
}
return endptr;
}
#define MAXBY10 cast(lua_Unsigned, LUA_MAXINTEGER / 10)
#define MAXLASTD cast_int(LUA_MAXINTEGER % 10)
static const char *l_str2int (const char *s, lua_Integer *result) {
lua_Unsigned a = 0;
int empty = 1;
@@ -275,7 +312,10 @@ static const char *l_str2int (const char *s, lua_Integer *result) {
}
else { /* decimal */
for (; lisdigit(cast_uchar(*s)); s++) {
a = a * 10 + *s - '0';
int d = *s - '0';
if (a >= MAXBY10 && (a > MAXBY10 || d > MAXLASTD + neg)) /* overflow? */
return NULL; /* do not accept it (as integer) */
a = a * 10 + d;
empty = 0;
}
}
@@ -333,9 +373,9 @@ void luaO_tostring (lua_State *L, StkId obj) {
size_t len;
lua_assert(ttisnumber(obj));
if (ttisinteger(obj))
len = lua_integer2str(buff, ivalue(obj));
len = lua_integer2str(buff, sizeof(buff), ivalue(obj));
else {
len = lua_number2str(buff, fltvalue(obj));
len = lua_number2str(buff, sizeof(buff), fltvalue(obj));
#if !defined(LUA_COMPAT_FLOATSTRING)
if (buff[strspn(buff, "-0123456789")] == '\0') { /* looks like an int? */
buff[len++] = lua_getlocaledecpoint();
@@ -348,27 +388,29 @@ void luaO_tostring (lua_State *L, StkId obj) {
static void pushstr (lua_State *L, const char *str, size_t l) {
setsvalue2s(L, L->top++, luaS_newlstr(L, str, l));
setsvalue2s(L, L->top, luaS_newlstr(L, str, l));
luaD_inctop(L);
}
/* this function handles only '%d', '%c', '%f', '%p', and '%s'
conventional formats, plus Lua-specific '%I' and '%U' */
/*
** this function handles only '%d', '%c', '%f', '%p', and '%s'
conventional formats, plus Lua-specific '%I' and '%U'
*/
const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
int n = 0;
for (;;) {
const char *e = strchr(fmt, '%');
if (e == NULL) break;
luaD_checkstack(L, 2); /* fmt + item */
pushstr(L, fmt, e - fmt);
switch (*(e+1)) {
case 's': {
case 's': { /* zero-terminated string */
const char *s = va_arg(argp, char *);
if (s == NULL) s = "(null)";
pushstr(L, s, strlen(s));
break;
}
case 'c': {
case 'c': { /* an 'int' as a character */
char buff = cast(char, va_arg(argp, int));
if (lisprint(cast_uchar(buff)))
pushstr(L, &buff, 1);
@@ -376,28 +418,28 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
luaO_pushfstring(L, "<\\%d>", cast_uchar(buff));
break;
}
case 'd': {
setivalue(L->top++, va_arg(argp, int));
case 'd': { /* an 'int' */
setivalue(L->top, va_arg(argp, int));
goto top2str;
}
case 'I': { /* a 'lua_Integer' */
setivalue(L->top, cast(lua_Integer, va_arg(argp, l_uacInt)));
goto top2str;
}
case 'f': { /* a 'lua_Number' */
setfltvalue(L->top, cast_num(va_arg(argp, l_uacNumber)));
top2str: /* convert the top element to a string */
luaD_inctop(L);
luaO_tostring(L, L->top - 1);
break;
}
case 'I': {
setivalue(L->top++, cast(lua_Integer, va_arg(argp, l_uacInt)));
luaO_tostring(L, L->top - 1);
break;
}
case 'f': {
setfltvalue(L->top++, cast_num(va_arg(argp, l_uacNumber)));
luaO_tostring(L, L->top - 1);
break;
}
case 'p': {
case 'p': { /* a pointer */
char buff[4*sizeof(void *) + 8]; /* should be enough space for a '%p' */
int l = sprintf(buff, "%p", va_arg(argp, void *));
int l = l_sprintf(buff, sizeof(buff), "%p", va_arg(argp, void *));
pushstr(L, buff, l);
break;
}
case 'U': {
case 'U': { /* an 'int' as a UTF-8 sequence */
char buff[UTF8BUFFSZ];
int l = luaO_utf8esc(buff, cast(long, va_arg(argp, long)));
pushstr(L, buff + UTF8BUFFSZ - l, l);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lobject.h,v 2.111 2015/06/09 14:21:42 roberto Exp $
** $Id: lobject.h,v 2.116 2015/11/03 18:33:10 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
@@ -19,8 +19,8 @@
/*
** Extra tags for non-values
*/
#define LUA_TPROTO LUA_NUMTAGS
#define LUA_TDEADKEY (LUA_NUMTAGS+1)
#define LUA_TPROTO LUA_NUMTAGS /* function prototypes */
#define LUA_TDEADKEY (LUA_NUMTAGS+1) /* removed keys in tables */
/*
** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
@@ -88,22 +88,32 @@ struct GCObject {
/*
** Union of all Lua values
*/
typedef union Value Value;
/*
** Tagged Values. This is the basic representation of values in Lua,
** an actual value plus a tag with its type.
*/
/*
** Union of all Lua values
*/
typedef union Value {
GCObject *gc; /* collectable objects */
void *p; /* light userdata */
int b; /* booleans */
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
} Value;
#define TValuefields Value value_; int tt_
typedef struct lua_TValue TValue;
typedef struct lua_TValue {
TValuefields;
} TValue;
/* macro defining a nil value */
@@ -177,9 +187,9 @@ typedef struct lua_TValue TValue;
/* Macros for internal tests */
#define righttt(obj) (ttype(obj) == gcvalue(obj)->tt)
#define checkliveness(g,obj) \
#define checkliveness(L,obj) \
lua_longassert(!iscollectable(obj) || \
(righttt(obj) && !isdead(g,gcvalue(obj))))
(righttt(obj) && (L == NULL || !isdead(G(L),gcvalue(obj)))))
/* Macros to set values */
@@ -215,32 +225,32 @@ typedef struct lua_TValue TValue;
#define setsvalue(L,obj,x) \
{ TValue *io = (obj); TString *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define setuvalue(L,obj,x) \
{ TValue *io = (obj); Udata *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define setthvalue(L,obj,x) \
{ TValue *io = (obj); lua_State *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define setclLvalue(L,obj,x) \
{ TValue *io = (obj); LClosure *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define setclCvalue(L,obj,x) \
{ TValue *io = (obj); CClosure *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define sethvalue(L,obj,x) \
{ TValue *io = (obj); Table *x_ = (x); \
val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
@@ -248,7 +258,7 @@ typedef struct lua_TValue TValue;
#define setobj(L,obj1,obj2) \
{ TValue *io1=(obj1); *io1 = *(obj2); \
(void)L; checkliveness(G(L),io1); }
(void)L; checkliveness(L,io1); }
/*
@@ -264,12 +274,13 @@ typedef struct lua_TValue TValue;
#define setptvalue2s setptvalue
/* from table to same table */
#define setobjt2t setobj
/* to table */
#define setobj2t setobj
/* to new object */
#define setobj2n setobj
#define setsvalue2n setsvalue
/* to table (define it as an expression to be used in macros) */
#define setobj2t(L,o1,o2) ((void)L, *(o1)=*(o2), checkliveness(L,(o1)))
@@ -280,21 +291,6 @@ typedef struct lua_TValue TValue;
*/
union Value {
GCObject *gc; /* collectable objects */
void *p; /* light userdata */
int b; /* booleans */
lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */
};
struct lua_TValue {
TValuefields;
};
typedef TValue *StkId; /* index to stack elements */
@@ -329,9 +325,9 @@ typedef union UTString {
** Get the actual string (array of bytes) from a 'TString'.
** (Access to 'extra' ensures that value is really a 'TString'.)
*/
#define getaddrstr(ts) (cast(char *, (ts)) + sizeof(UTString))
#define getstr(ts) \
check_exp(sizeof((ts)->extra), cast(const char*, getaddrstr(ts)))
check_exp(sizeof((ts)->extra), cast(char *, (ts)) + sizeof(UTString))
/* get the actual string (array of bytes) from a Lua value */
#define svalue(o) getstr(tsvalue(o))
@@ -375,13 +371,13 @@ typedef union UUdata {
#define setuservalue(L,u,o) \
{ const TValue *io=(o); Udata *iu = (u); \
iu->user_ = io->value_; iu->ttuv_ = rttype(io); \
checkliveness(G(L),io); }
checkliveness(L,io); }
#define getuservalue(L,u,o) \
{ TValue *io=(o); const Udata *iu = (u); \
io->value_ = iu->user_; settt_(io, iu->ttuv_); \
checkliveness(G(L),io); }
checkliveness(L,io); }
/*
@@ -406,7 +402,7 @@ typedef struct LocVar {
typedef struct SharedProto {
lu_byte numparams; /* number of fixed parameters */
lu_byte is_vararg;
lu_byte is_vararg; /* 2: declared vararg; 1: uses vararg */
lu_byte maxstacksize; /* number of registers needed by this function */
int sizeupvalues; /* size of 'upvalues' */
int sizek; /* size of 'k' */
@@ -414,8 +410,8 @@ typedef struct SharedProto {
int sizelineinfo;
int sizep; /* size of 'p' */
int sizelocvars;
int linedefined;
int lastlinedefined;
int linedefined; /* debug information */
int lastlinedefined; /* debug information */
void *l_G; /* global state belongs to */
Instruction *code; /* opcodes */
int *lineinfo; /* map from opcodes to source lines (debug information) */
@@ -493,7 +489,7 @@ typedef union TKey {
#define setnodekey(L,key,obj) \
{ TKey *k_=(key); const TValue *io_=(obj); \
k_->nk.value_ = io_->value_; k_->nk.tt_ = io_->tt_; \
(void)L; checkliveness(G(L),io_); }
(void)L; checkliveness(L,io_); }
typedef struct Node {

View File

@@ -1,5 +1,5 @@
/*
** $Id: loslib.c,v 1.57 2015/04/10 17:41:04 roberto Exp $
** $Id: loslib.c,v 1.64 2016/04/18 13:06:55 roberto Exp $
** Standard Operating System library
** See Copyright Notice in lua.h
*/
@@ -24,18 +24,29 @@
/*
** {==================================================================
** list of valid conversion specifiers for the 'strftime' function
** List of valid conversion specifiers for the 'strftime' function;
** options are grouped by length; group of length 2 start with '||'.
** ===================================================================
*/
#if !defined(LUA_STRFTIMEOPTIONS) /* { */
#if defined(LUA_USE_C89)
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
/* options for ANSI C 89 */
#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
/* options for ISO C 99 and POSIX */
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy"
/* options for Windows */
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y"
#if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN
#elif defined(LUA_USE_C89)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89
#else /* C99 specification */
#define LUA_STRFTIMEOPTIONS \
{ "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "", \
"E", "cCxXyY", \
"O", "deHImMSuUVwWy" }
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99
#endif
#endif /* } */
@@ -54,7 +65,12 @@
*/
#define l_timet lua_Integer
#define l_pushtime(L,t) lua_pushinteger(L,(lua_Integer)(t))
#define l_checktime(L,a) ((time_t)luaL_checkinteger(L,a))
static time_t l_checktime (lua_State *L, int arg) {
lua_Integer t = luaL_checkinteger(L, arg);
luaL_argcheck(L, (time_t)t == t, arg, "time out-of-bounds");
return (time_t)t;
}
#endif /* } */
@@ -190,6 +206,23 @@ static void setboolfield (lua_State *L, const char *key, int value) {
lua_setfield(L, -2, key);
}
/*
** Set all fields from structure 'tm' in the table on top of the stack
*/
static void setallfields (lua_State *L, struct tm *stm) {
setfield(L, "sec", stm->tm_sec);
setfield(L, "min", stm->tm_min);
setfield(L, "hour", stm->tm_hour);
setfield(L, "day", stm->tm_mday);
setfield(L, "month", stm->tm_mon + 1);
setfield(L, "year", stm->tm_year + 1900);
setfield(L, "wday", stm->tm_wday + 1);
setfield(L, "yday", stm->tm_yday + 1);
setboolfield(L, "isdst", stm->tm_isdst);
}
static int getboolfield (lua_State *L, const char *key) {
int res;
res = (lua_getfield(L, -1, key) == LUA_TNIL) ? -1 : lua_toboolean(L, -1);
@@ -198,36 +231,42 @@ static int getboolfield (lua_State *L, const char *key) {
}
static int getfield (lua_State *L, const char *key, int d) {
int res, isnum;
lua_getfield(L, -1, key);
res = (int)lua_tointegerx(L, -1, &isnum);
if (!isnum) {
if (d < 0)
/* maximum value for date fields (to avoid arithmetic overflows with 'int') */
#if !defined(L_MAXDATEFIELD)
#define L_MAXDATEFIELD (INT_MAX / 2)
#endif
static int getfield (lua_State *L, const char *key, int d, int delta) {
int isnum;
int t = lua_getfield(L, -1, key); /* get field and its type */
lua_Integer res = lua_tointegerx(L, -1, &isnum);
if (!isnum) { /* field is not an integer? */
if (t != LUA_TNIL) /* some other value? */
return luaL_error(L, "field '%s' is not an integer", key);
else if (d < 0) /* absent field; no default? */
return luaL_error(L, "field '%s' missing in date table", key);
res = d;
}
else {
if (!(-L_MAXDATEFIELD <= res && res <= L_MAXDATEFIELD))
return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta;
}
lua_pop(L, 1);
return res;
return (int)res;
}
static const char *checkoption (lua_State *L, const char *conv, char *buff) {
static const char *const options[] = LUA_STRFTIMEOPTIONS;
unsigned int i;
for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2) {
if (*conv != '\0' && strchr(options[i], *conv) != NULL) {
buff[1] = *conv;
if (*options[i + 1] == '\0') { /* one-char conversion specifier? */
buff[2] = '\0'; /* end buffer */
return conv + 1;
}
else if (*(conv + 1) != '\0' &&
strchr(options[i + 1], *(conv + 1)) != NULL) {
buff[2] = *(conv + 1); /* valid two-char conversion specifier */
buff[3] = '\0'; /* end buffer */
return conv + 2;
}
const char *option;
int oplen = 1;
for (option = LUA_STRFTIMEOPTIONS; *option != '\0'; option += oplen) {
if (*option == '|') /* next block? */
oplen++; /* next length */
else if (memcmp(conv, option, oplen) == 0) { /* match? */
memcpy(buff, conv, oplen); /* copy valid option to buffer */
buff[oplen] = '\0';
return conv + oplen; /* return next item */
}
}
luaL_argerror(L, 1,
@@ -236,6 +275,10 @@ static const char *checkoption (lua_State *L, const char *conv, char *buff) {
}
/* maximum size for an individual 'strftime' item */
#define SIZETIMEFMT 250
static int os_date (lua_State *L) {
const char *s = luaL_optstring(L, 1, "%c");
time_t t = luaL_opt(L, l_checktime, 2, time(NULL));
@@ -247,33 +290,25 @@ static int os_date (lua_State *L) {
else
stm = l_localtime(&t, &tmr);
if (stm == NULL) /* invalid date? */
lua_pushnil(L);
else if (strcmp(s, "*t") == 0) {
luaL_error(L, "time result cannot be represented in this installation");
if (strcmp(s, "*t") == 0) {
lua_createtable(L, 0, 9); /* 9 = number of fields */
setfield(L, "sec", stm->tm_sec);
setfield(L, "min", stm->tm_min);
setfield(L, "hour", stm->tm_hour);
setfield(L, "day", stm->tm_mday);
setfield(L, "month", stm->tm_mon+1);
setfield(L, "year", stm->tm_year+1900);
setfield(L, "wday", stm->tm_wday+1);
setfield(L, "yday", stm->tm_yday+1);
setboolfield(L, "isdst", stm->tm_isdst);
setallfields(L, stm);
}
else {
char cc[4];
char cc[4]; /* buffer for individual conversion specifiers */
luaL_Buffer b;
cc[0] = '%';
luaL_buffinit(L, &b);
while (*s) {
if (*s != '%') /* no conversion specifier? */
if (*s != '%') /* not a conversion specifier? */
luaL_addchar(&b, *s++);
else {
size_t reslen;
char buff[200]; /* should be big enough for any conversion result */
s = checkoption(L, s + 1, cc);
reslen = strftime(buff, sizeof(buff), cc, stm);
luaL_addlstring(&b, buff, reslen);
char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT);
s = checkoption(L, s + 1, cc + 1); /* copy specifier to 'cc' */
reslen = strftime(buff, SIZETIMEFMT, cc, stm);
luaL_addsize(&b, reslen);
}
}
luaL_pushresult(&b);
@@ -290,21 +325,19 @@ static int os_time (lua_State *L) {
struct tm ts;
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 1); /* make sure table is at the top */
ts.tm_sec = getfield(L, "sec", 0);
ts.tm_min = getfield(L, "min", 0);
ts.tm_hour = getfield(L, "hour", 12);
ts.tm_mday = getfield(L, "day", -1);
ts.tm_mon = getfield(L, "month", -1) - 1;
ts.tm_year = getfield(L, "year", -1) - 1900;
ts.tm_sec = getfield(L, "sec", 0, 0);
ts.tm_min = getfield(L, "min", 0, 0);
ts.tm_hour = getfield(L, "hour", 12, 0);
ts.tm_mday = getfield(L, "day", -1, 0);
ts.tm_mon = getfield(L, "month", -1, 1);
ts.tm_year = getfield(L, "year", -1, 1900);
ts.tm_isdst = getboolfield(L, "isdst");
t = mktime(&ts);
setallfields(L, &ts); /* update fields with normalized values */
}
if (t != (time_t)(l_timet)t)
luaL_error(L, "time result cannot be represented in this Lua installation");
else if (t == (time_t)(-1))
lua_pushnil(L);
else
l_pushtime(L, t);
if (t != (time_t)(l_timet)t || t == (time_t)(-1))
luaL_error(L, "time result cannot be represented in this installation");
l_pushtime(L, t);
return 1;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lparser.c,v 2.147 2014/12/27 20:31:43 roberto Exp $
** $Id: lparser.c,v 2.153 2016/05/13 19:10:16 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -165,7 +165,8 @@ static int registerlocalvar (LexState *ls, TString *varname) {
int oldsize = f->sizelocvars;
luaM_growvector(ls->L, f->locvars, fs->nlocvars, f->sizelocvars,
LocVar, SHRT_MAX, "local variables");
while (oldsize < f->sizelocvars) f->locvars[oldsize++].varname = NULL;
while (oldsize < f->sizelocvars)
f->locvars[oldsize++].varname = NULL;
f->locvars[fs->nlocvars].varname = varname;
luaC_objbarrier(ls->L, fp, varname);
return fs->nlocvars++;
@@ -232,7 +233,8 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) {
checklimit(fs, fs->nups + 1, MAXUPVAL, "upvalues");
luaM_growvector(fs->ls->L, f->upvalues, fs->nups, f->sizeupvalues,
Upvaldesc, MAXUPVAL, "upvalues");
while (oldsize < f->sizeupvalues) f->upvalues[oldsize++].name = NULL;
while (oldsize < f->sizeupvalues)
f->upvalues[oldsize++].name = NULL;
f->upvalues[fs->nups].instack = (v->k == VLOCAL);
f->upvalues[fs->nups].idx = cast_byte(v->u.info);
f->upvalues[fs->nups].name = name;
@@ -257,7 +259,8 @@ static int searchvar (FuncState *fs, TString *n) {
*/
static void markupval (FuncState *fs, int level) {
BlockCnt *bl = fs->bl;
while (bl->nactvar > level) bl = bl->previous;
while (bl->nactvar > level)
bl = bl->previous;
bl->upval = 1;
}
@@ -266,27 +269,26 @@ static void markupval (FuncState *fs, int level) {
Find variable with given name 'n'. If it is an upvalue, add this
upvalue into all intermediate functions.
*/
static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
if (fs == NULL) /* no more levels? */
return VVOID; /* default is global */
init_exp(var, VVOID, 0); /* default is global */
else {
int v = searchvar(fs, n); /* look up locals at current level */
if (v >= 0) { /* found? */
init_exp(var, VLOCAL, v); /* variable is local */
if (!base)
markupval(fs, v); /* local will be used as an upval */
return VLOCAL;
}
else { /* not found as local at current level; try upvalues */
int idx = searchupvalue(fs, n); /* try existing upvalues */
if (idx < 0) { /* not found? */
if (singlevaraux(fs->prev, n, var, 0) == VVOID) /* try upper levels */
return VVOID; /* not found; is a global */
singlevaraux(fs->prev, n, var, 0); /* try upper levels */
if (var->k == VVOID) /* not found? */
return; /* it is a global */
/* else was LOCAL or UPVAL */
idx = newupvalue(fs, n, var); /* will be a new upvalue */
}
init_exp(var, VUPVAL, idx);
return VUPVAL;
init_exp(var, VUPVAL, idx); /* new or old upvalue */
}
}
}
@@ -295,10 +297,11 @@ static int singlevaraux (FuncState *fs, TString *n, expdesc *var, int base) {
static void singlevar (LexState *ls, expdesc *var) {
TString *varname = str_checkname(ls);
FuncState *fs = ls->fs;
if (singlevaraux(fs, varname, var, 1) == VVOID) { /* global name? */
singlevaraux(fs, varname, var, 1);
if (var->k == VVOID) { /* global name? */
expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k == VLOCAL || var->k == VUPVAL);
lua_assert(var->k != VVOID); /* this one must exist */
codestring(ls, &key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */
}
@@ -501,7 +504,8 @@ static Proto *addprototype (LexState *ls) {
if (fs->np >= f->sp->sizep) {
int oldsize = f->sp->sizep;
luaM_growvector(L, f->p, fs->np, f->sp->sizep, Proto *, MAXARG_Bx, "functions");
while (oldsize < f->sp->sizep) f->p[oldsize++] = NULL;
while (oldsize < f->sp->sizep)
f->p[oldsize++] = NULL;
}
f->p[fs->np++] = clp = luaF_newproto(L, NULL);
luaC_objbarrier(L, f, clp);
@@ -763,7 +767,7 @@ static void parlist (LexState *ls) {
}
case TK_DOTS: { /* param -> '...' */
luaX_next(ls);
f->is_vararg = 1;
f->is_vararg = 2; /* declared vararg */
break;
}
default: luaX_syntaxerror(ls, "<name> or '...' expected");
@@ -959,6 +963,7 @@ static void simpleexp (LexState *ls, expdesc *v) {
FuncState *fs = ls->fs;
check_condition(ls, fs->f->sp->is_vararg,
"cannot use '...' outside a vararg function");
fs->f->sp->is_vararg = 1; /* function actually uses vararg */
init_exp(v, VVARARG, luaK_codeABC(fs, OP_VARARG, 0, 1, 0));
break;
}
@@ -1228,7 +1233,7 @@ static void labelstat (LexState *ls, TString *label, int line) {
checkrepeated(fs, ll, label); /* check for repeated labels */
checknext(ls, TK_DBCOLON); /* skip double colon */
/* create new entry for this label */
l = newlabelentry(ls, ll, label, line, fs->pc);
l = newlabelentry(ls, ll, label, line, luaK_getlabel(fs));
skipnoopstat(ls); /* skip other no-op statements */
if (block_follow(ls, 0)) { /* label is last no-op statement in the block? */
/* assume that locals are already out of scope */
@@ -1496,7 +1501,7 @@ static void exprstat (LexState *ls) {
}
else { /* stat -> func */
check_condition(ls, v.v.k == VCALL, "syntax error");
SETARG_C(getcode(fs, &v.v), 1); /* call statement uses no results */
SETARG_C(getinstruction(fs, &v.v), 1); /* call statement uses no results */
}
}
@@ -1513,8 +1518,8 @@ static void retstat (LexState *ls) {
if (hasmultret(e.k)) {
luaK_setmultret(fs, &e);
if (e.k == VCALL && nret == 1) { /* tail call? */
SET_OPCODE(getcode(fs,&e), OP_TAILCALL);
lua_assert(GETARG_A(getcode(fs,&e)) == fs->nactvar);
SET_OPCODE(getinstruction(fs,&e), OP_TAILCALL);
lua_assert(GETARG_A(getinstruction(fs,&e)) == fs->nactvar);
}
first = fs->nactvar;
nret = LUA_MULTRET; /* return all values */
@@ -1596,7 +1601,7 @@ static void statement (LexState *ls) {
break;
}
}
lua_assert(ls->fs->f->maxstacksize >= ls->fs->freereg &&
lua_assert(ls->fs->f->sp->maxstacksize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar);
ls->fs->freereg = ls->fs->nactvar; /* free registers */
leavelevel(ls);
@@ -1613,7 +1618,7 @@ static void mainfunc (LexState *ls, FuncState *fs) {
BlockCnt bl;
expdesc v;
open_func(ls, fs, &bl);
fs->f->sp->is_vararg = 1; /* main function is always vararg */
fs->f->sp->is_vararg = 2; /* main function is always declared vararg */
init_exp(&v, VLOCAL, 0); /* create and... */
newupvalue(fs, ls->envn, &v); /* ...set environment upvalue */
luaX_next(ls); /* read first token */
@@ -1629,10 +1634,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue(L, L->top, cl); /* anchor it (to avoid being collected) */
incr_top(L);
luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue(L, L->top, lexstate.h); /* anchor it */
incr_top(L);
luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L, NULL);
funcstate.f->sp->source = luaS_new(L, name); /* create and anchor TString */
lua_assert(iswhite(funcstate.f)); /* do not need barrier here */

View File

@@ -1,5 +1,5 @@
/*
** $Id: lparser.h,v 1.74 2014/10/25 11:50:46 roberto Exp $
** $Id: lparser.h,v 1.76 2015/12/30 18:16:13 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
@@ -13,25 +13,38 @@
/*
** Expression descriptor
** Expression and variable descriptor.
** Code generation for variables and expressions can be delayed to allow
** optimizations; An 'expdesc' structure describes a potentially-delayed
** variable/expression. It has a description of its "main" value plus a
** list of conditional jumps that can also produce its value (generated
** by short-circuit operators 'and'/'or').
*/
/* kinds of variables/expressions */
typedef enum {
VVOID, /* no value */
VNIL,
VTRUE,
VFALSE,
VK, /* info = index of constant in 'k' */
VKFLT, /* nval = numerical float value */
VKINT, /* nval = numerical integer value */
VNONRELOC, /* info = result register */
VLOCAL, /* info = local register */
VUPVAL, /* info = index of upvalue in 'upvalues' */
VINDEXED, /* t = table register/upvalue; idx = index R/K */
VJMP, /* info = instruction pc */
VRELOCABLE, /* info = instruction pc */
VCALL, /* info = instruction pc */
VVARARG /* info = instruction pc */
VVOID, /* when 'expdesc' describes the last expression a list,
this kind means an empty list (so, no expression) */
VNIL, /* constant nil */
VTRUE, /* constant true */
VFALSE, /* constant false */
VK, /* constant in 'k'; info = index of constant in 'k' */
VKFLT, /* floating constant; nval = numerical float value */
VKINT, /* integer constant; nval = numerical integer value */
VNONRELOC, /* expression has its value in a fixed register;
info = result register */
VLOCAL, /* local variable; info = local register */
VUPVAL, /* upvalue variable; info = index of upvalue in 'upvalues' */
VINDEXED, /* indexed variable;
ind.vt = whether 't' is register or upvalue;
ind.t = table register or upvalue;
ind.idx = key's R/K index */
VJMP, /* expression is a test/comparison;
info = pc of corresponding jump instruction */
VRELOCABLE, /* expression can put result in any register;
info = instruction pc */
VCALL, /* expression is a function call; info = instruction pc */
VVARARG /* vararg expression; info = instruction pc */
} expkind;
@@ -41,14 +54,14 @@ typedef enum {
typedef struct expdesc {
expkind k;
union {
lua_Integer ival; /* for VKINT */
lua_Number nval; /* for VKFLT */
int info; /* for generic use */
struct { /* for indexed variables (VINDEXED) */
short idx; /* index (R/K) */
lu_byte t; /* table (register or upvalue) */
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
} ind;
int info; /* for generic use */
lua_Number nval; /* for VKFLT */
lua_Integer ival; /* for VKINT */
} u;
int t; /* patch list of 'exit when true' */
int f; /* patch list of 'exit when false' */

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstate.c,v 2.128 2015/03/04 13:31:21 roberto Exp $
** $Id: lstate.c,v 2.133 2015/11/13 12:16:51 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -76,7 +76,7 @@ typedef struct LG {
*/
#define addbuff(b,p,e) \
{ size_t t = cast(size_t, e); \
memcpy(buff + p, &t, sizeof(t)); p += sizeof(t); }
memcpy(b + p, &t, sizeof(t)); p += sizeof(t); }
static unsigned int makeseed (lua_State *L) {
char buff[4 * sizeof(size_t)];
@@ -93,10 +93,14 @@ static unsigned int makeseed (lua_State *L) {
/*
** set GCdebt to a new value keeping the value (totalbytes + GCdebt)
** invariant
** invariant (and avoiding underflows in 'totalbytes')
*/
void luaE_setdebt (global_State *g, l_mem debt) {
g->totalbytes -= (debt - g->GCdebt);
l_mem tb = gettotalbytes(g);
lua_assert(tb > 0);
if (debt < tb - MAX_LMEM)
debt = tb - MAX_LMEM; /* will make 'totalbytes == MAX_LMEM' */
g->totalbytes = tb - debt;
g->GCdebt = debt;
}
@@ -107,6 +111,7 @@ CallInfo *luaE_extendCI (lua_State *L) {
L->ci->next = ci;
ci->previous = L->ci;
ci->next = NULL;
L->nci++;
return ci;
}
@@ -121,6 +126,7 @@ void luaE_freeCI (lua_State *L) {
while ((ci = next) != NULL) {
next = ci->next;
luaM_free(L, ci);
L->nci--;
}
}
@@ -130,13 +136,14 @@ void luaE_freeCI (lua_State *L) {
*/
void luaE_shrinkCI (lua_State *L) {
CallInfo *ci = L->ci;
while (ci->next != NULL) { /* while there is 'next' */
CallInfo *next2 = ci->next->next; /* next's next */
if (next2 == NULL) break;
luaM_free(L, ci->next); /* remove next */
CallInfo *next2; /* next's next */
/* while there are two nexts */
while (ci->next != NULL && (next2 = ci->next->next) != NULL) {
luaM_free(L, ci->next); /* free next */
L->nci--;
ci->next = next2; /* remove 'next' from the list */
next2->previous = ci;
ci = next2;
ci = next2; /* keep next's next */
}
}
@@ -166,6 +173,7 @@ static void freestack (lua_State *L) {
return; /* stack not completely built yet */
L->ci = &L->base_ci; /* free the entire 'ci' list */
luaE_freeCI(L);
lua_assert(L->nci == 0);
luaM_freearray(L, L->stack, L->stacksize); /* free stack array */
}
@@ -214,6 +222,7 @@ static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g;
L->stack = NULL;
L->ci = NULL;
L->nci = 0;
L->stacksize = 0;
L->twups = L; /* thread has no upvalues */
L->errorJmp = NULL;
@@ -237,7 +246,6 @@ static void close_state (lua_State *L) {
if (g->version) /* closing a fully built state? */
luai_userstateclose(L);
luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size);
luaZ_freebuffer(L, &g->buff);
freestack(L);
lua_assert(gettotalbytes(g) == sizeof(LG));
(*g->frealloc)(g->ud, fromstate(L), sizeof(LG), 0); /* free main block */
@@ -306,7 +314,6 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->strt.size = g->strt.nuse = 0;
g->strt.hash = NULL;
setnilvalue(&g->l_registry);
luaZ_initbuffer(L, &g->buff);
g->panic = NULL;
g->version = NULL;
g->gcstate = GCSpause;

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstate.h,v 2.122 2015/06/01 16:34:37 roberto Exp $
** $Id: lstate.h,v 2.130 2015/12/16 16:39:38 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
@@ -33,6 +33,15 @@
struct lua_longjmp; /* defined in ldo.c */
/*
** Atomic type (relative to signals) to better ensure that 'lua_sethook'
** is thread safe
*/
#if !defined(l_signalT)
#include <signal.h>
#define l_signalT sig_atomic_t
#endif
/* extra stack space to handle TM calls and some other extras */
#define EXTRA_STACK 5
@@ -89,8 +98,8 @@ typedef struct CallInfo {
#define CIST_OAH (1<<0) /* original value of 'allowhook' */
#define CIST_LUA (1<<1) /* call is running a Lua function */
#define CIST_HOOKED (1<<2) /* call is running a debug hook */
#define CIST_REENTRY (1<<3) /* call is running on same invocation of
luaV_execute of previous call */
#define CIST_FRESH (1<<3) /* call is running on a fresh invocation
of luaV_execute */
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
#define CIST_TAIL (1<<5) /* call was tail called */
#define CIST_HOOKYIELD (1<<6) /* last hook called yielded */
@@ -109,7 +118,7 @@ typedef struct CallInfo {
typedef struct global_State {
lua_Alloc frealloc; /* function to reallocate memory */
void *ud; /* auxiliary data to 'frealloc' */
lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
lu_mem GCmemtrav; /* memory traversed by the GC */
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
@@ -131,7 +140,6 @@ typedef struct global_State {
GCObject *tobefnz; /* list of userdata to be GC */
GCObject *fixedgc; /* list of objects not to be collected */
struct lua_State *twups; /* list of threads with open upvalues */
Mbuffer buff; /* temporary buffer for string concatenation */
unsigned int gcfinnum; /* number of finalizers to call in each GC step */
int gcpause; /* size of pause between successive GCs */
int gcstepmul; /* GC 'granularity' */
@@ -141,7 +149,7 @@ typedef struct global_State {
TString *memerrmsg; /* memory-error message */
TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
TString *strcache[STRCACHE_SIZE][1]; /* cache for strings in API */
TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */
} global_State;
@@ -150,6 +158,7 @@ typedef struct global_State {
*/
struct lua_State {
CommonHeader;
unsigned short nci; /* number of items in 'ci' list */
lu_byte status;
StkId top; /* first free slot in the stack */
global_State *l_G;
@@ -162,14 +171,14 @@ struct lua_State {
struct lua_State *twups; /* list of threads with open upvalues */
struct lua_longjmp *errorJmp; /* current error recover point */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
lua_Hook hook;
volatile lua_Hook hook;
ptrdiff_t errfunc; /* current error handling function (stack index) */
int stacksize;
int basehookcount;
int hookcount;
unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */
lu_byte hookmask;
l_signalT hookmask;
lu_byte allowhook;
};
@@ -212,7 +221,7 @@ union GCUnion {
/* actual number of total bytes allocated */
#define gettotalbytes(g) ((g)->totalbytes + (g)->GCdebt)
#define gettotalbytes(g) cast(lu_mem, (g)->totalbytes + (g)->GCdebt)
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstring.c,v 2.49 2015/06/01 16:34:37 roberto Exp $
** $Id: lstring.c,v 2.56 2015/11/23 11:32:51 roberto Exp $
** String table (keeps all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -48,14 +48,23 @@ int luaS_eqlngstr (TString *a, TString *b) {
unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
unsigned int h = seed ^ cast(unsigned int, l);
size_t l1;
size_t step = (l >> LUAI_HASHLIMIT) + 1;
for (l1 = l; l1 >= step; l1 -= step)
h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1]));
for (; l >= step; l -= step)
h ^= ((h<<5) + (h>>2) + cast_byte(str[l - 1]));
return h;
}
unsigned int luaS_hashlongstr (TString *ts) {
lua_assert(ts->tt == LUA_TLNGSTR);
if (ts->extra == 0) { /* no hash? */
ts->hash = luaS_hash(getstr(ts), ts->u.lnglen, ts->hash);
ts->extra = 1; /* now it has its hash */
}
return ts->hash;
}
/*
** resizes the string table
*/
@@ -92,11 +101,12 @@ void luaS_resize (lua_State *L, int newsize) {
** a non-collectable string.)
*/
void luaS_clearcache (global_State *g) {
int i;
for (i = 0; i < STRCACHE_SIZE; i++) {
if (iswhite(g->strcache[i][0])) /* will entry be collected? */
g->strcache[i][0] = g->memerrmsg; /* replace it with something fixed */
}
int i, j;
for (i = 0; i < STRCACHE_N; i++)
for (j = 0; j < STRCACHE_M; j++) {
if (iswhite(g->strcache[i][j])) /* will entry be collected? */
g->strcache[i][j] = g->memerrmsg; /* replace it with something fixed */
}
}
@@ -105,13 +115,14 @@ void luaS_clearcache (global_State *g) {
*/
void luaS_init (lua_State *L) {
global_State *g = G(L);
int i;
int i, j;
luaS_resize(L, MINSTRTABSIZE); /* initial size of string table */
/* pre-create memory-error message */
g->memerrmsg = luaS_newliteral(L, MEMERRMSG);
luaC_fix(L, obj2gco(g->memerrmsg)); /* it should never be collected */
for (i = 0; i < STRCACHE_SIZE; i++) /* fill cache with valid strings */
g->strcache[i][0] = g->memerrmsg;
for (i = 0; i < STRCACHE_N; i++) /* fill cache with valid strings */
for (j = 0; j < STRCACHE_M; j++)
g->strcache[i][j] = g->memerrmsg;
}
@@ -119,8 +130,7 @@ void luaS_init (lua_State *L) {
/*
** creates a new string object
*/
static TString *createstrobj (lua_State *L, const char *str, size_t l,
int tag, unsigned int h) {
static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) {
TString *ts;
GCObject *o;
size_t totalsize; /* total size of TString object */
@@ -129,8 +139,14 @@ static TString *createstrobj (lua_State *L, const char *str, size_t l,
ts = gco2ts(o);
ts->hash = h;
ts->extra = 0;
memcpy(getaddrstr(ts), str, l * sizeof(char));
getaddrstr(ts)[l] = '\0'; /* ending 0 */
getstr(ts)[l] = '\0'; /* ending 0 */
return ts;
}
TString *luaS_createlngstrobj (lua_State *L, size_t l) {
TString *ts = createstrobj(L, l, LUA_TLNGSTR, G(L)->seed);
ts->u.lnglen = l;
return ts;
}
@@ -148,11 +164,11 @@ void luaS_remove (lua_State *L, TString *ts) {
/*
** checks whether short string exists and reuses it or creates a new one
*/
static TString *internshrstr (lua_State *L, const char *str, size_t l) {
static TString *queryshrstr (lua_State *L, const char *str, size_t l, unsigned int h) {
TString *ts;
global_State *g = G(L);
unsigned int h = luaS_hash(str, l, g->seed);
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */
for (ts = *list; ts != NULL; ts = ts->u.hnext) {
if (l == ts->shrlen &&
(memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
@@ -162,11 +178,19 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
return ts;
}
}
return NULL;
}
static TString *addshrstr (lua_State *L, const char *str, size_t l, unsigned int h) {
TString *ts;
global_State *g = G(L);
TString **list = &g->strt.hash[lmod(h, g->strt.size)];
if (g->strt.nuse >= g->strt.size && g->strt.size <= MAX_INT/2) {
luaS_resize(L, g->strt.size * 2);
list = &g->strt.hash[lmod(h, g->strt.size)]; /* recompute with new size */
}
ts = createstrobj(L, str, l, LUA_TSHRSTR, h);
ts = createstrobj(L, l, LUA_TSHRSTR, h);
memcpy(getstr(ts), str, l * sizeof(char));
ts->shrlen = cast_byte(l);
ts->u.hnext = *list;
*list = ts;
@@ -174,6 +198,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) {
return ts;
}
static TString *internshrstr (lua_State *L, const char *str, size_t l);
/*
** new string (with explicit length)
@@ -183,10 +208,10 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
return internshrstr(L, str, l);
else {
TString *ts;
if (l + 1 > (MAX_SIZE - sizeof(TString))/sizeof(char))
if (l >= (MAX_SIZE - sizeof(TString))/sizeof(char))
luaM_toobig(L);
ts = createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed);
ts->u.lnglen = l;
ts = luaS_createlngstrobj(L, l);
memcpy(getstr(ts), str, l * sizeof(char));
return ts;
}
}
@@ -199,15 +224,19 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
** check hits.
*/
TString *luaS_new (lua_State *L, const char *str) {
unsigned int i = point2uint(str) % STRCACHE_SIZE; /* hash */
unsigned int i = point2uint(str) % STRCACHE_N; /* hash */
int j;
TString **p = G(L)->strcache[i];
if (strcmp(str, getstr(p[0])) == 0) /* hit? */
return p[0]; /* that it is */
else { /* normal route */
TString *s = luaS_newlstr(L, str, strlen(str));
p[0] = s;
return s;
for (j = 0; j < STRCACHE_M; j++) {
if (strcmp(str, getstr(p[j])) == 0) /* hit? */
return p[j]; /* that is it */
}
/* normal route */
for (j = STRCACHE_M - 1; j > 0; j--)
p[j] = p[j - 1]; /* move out last element */
/* new element is first in the list */
p[0] = luaS_newlstr(L, str, strlen(str));
return p[0];
}
@@ -224,3 +253,217 @@ Udata *luaS_newudata (lua_State *L, size_t s) {
return u;
}
/*
* global shared table
*/
#include "rwlock.h"
#include "atomic.h"
#include <stdlib.h>
#define SHRSTR_SLOT 0x10000
#define HASH_NODE(h) ((h) % SHRSTR_SLOT)
#define getaddrstr(ts) (cast(char *, (ts)) + sizeof(UTString))
struct shrmap_slot {
struct rwlock lock;
TString *str;
};
struct shrmap {
struct shrmap_slot h[SHRSTR_SLOT];
int n;
};
static struct shrmap SSM;
LUA_API void
luaS_initshr() {
struct shrmap * s = &SSM;
int i;
for (i=0;i<SHRSTR_SLOT;i++) {
rwlock_init(&s->h[i].lock);
}
}
LUA_API void
luaS_exitshr() {
int i;
for (i=0;i<SHRSTR_SLOT;i++) {
TString *str = SSM.h[i].str;
while (str) {
TString * next = str->u.hnext;
free(str);
str = next;
}
}
}
static TString *
query_string(unsigned int h, const char *str, lu_byte l) {
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
rwlock_rlock(&s->lock);
TString *ts = s->str;
while (ts) {
if (ts->hash == h &&
ts->shrlen == l &&
memcmp(str, ts+1, l) == 0) {
break;
}
ts = ts->u.hnext;
}
rwlock_runlock(&s->lock);
return ts;
}
static TString *
query_ptr(TString *t) {
unsigned int h = t->hash;
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
rwlock_rlock(&s->lock);
TString *ts = s->str;
while (ts) {
if (ts == t)
break;
ts = ts->u.hnext;
}
rwlock_runlock(&s->lock);
return ts;
}
static TString *
new_string(unsigned int h, const char *str, lu_byte l) {
size_t sz = sizelstring(l);
TString *ts = malloc(sz);
memset(ts, 0, sz);
ts->tt = LUA_TSHRSTR;
ts->hash = h;
ts->shrlen = l;
memcpy(ts+1, str, l);
return ts;
}
static TString *
add_string(unsigned int h, const char *str, lu_byte l) {
TString * tmp = new_string(h, str, l);
struct shrmap_slot *s = &SSM.h[HASH_NODE(h)];
rwlock_wlock(&s->lock);
TString *ts = s->str;
while (ts) {
if (ts->hash == h &&
ts->shrlen == l &&
memcmp(str, ts+1, l) == 0) {
break;
}
ts = ts->u.hnext;
}
if (ts == NULL) {
ts = tmp;
ts->u.hnext = s->str;
s->str = ts;
tmp = NULL;
}
rwlock_wunlock(&s->lock);
if (tmp) {
// string is create by other thread, so free tmp
free(tmp);
}
return ts;
}
static TString *
internshrstr (lua_State *L, const char *str, size_t l) {
TString *ts;
global_State *g = G(L);
unsigned int h = luaS_hash(str, l, g->seed);
unsigned int h0;
// lookup global state of this L first
ts = queryshrstr (L, str, l, h);
if (ts)
return ts;
// lookup SSM again
h0 = luaS_hash(str, l, 0);
ts = query_string(h0, str, l);
if (ts)
return ts;
// If SSM.n greate than 0, add it to SSM
if (SSM.n > 0) {
ATOM_DEC(&SSM.n);
return add_string(h0, str, l);
}
// Else add it to global state (local)
return addshrstr (L, str, l, h);
}
LUA_API void
luaS_expandshr(int n) {
ATOM_ADD(&SSM.n, n);
}
LUAI_FUNC TString *
luaS_clonestring(lua_State *L, TString *ts) {
unsigned int h;
int l;
const char * str = getaddrstr(ts);
global_State *g = G(L);
TString *result;
if (ts->tt == LUA_TLNGSTR)
return luaS_newlstr(L, str, ts->u.lnglen);
// look up global state of this L first
l = ts->shrlen;
h = luaS_hash(str, l, g->seed);
result = queryshrstr (L, str, l, h);
if (result)
return result;
// look up SSM by ptr
result = query_ptr(ts);
if (result)
return result;
h = luaS_hash(str, l, 0);
result = query_string(h, str, l);
if (result)
return result;
// ts is not in SSM, so recalc hash, and add it to SSM
return add_string(h, str, l);
}
struct slotinfo {
int len;
int size;
};
static void
getslot(struct shrmap_slot *s, struct slotinfo *info) {
memset(info, 0, sizeof(*info));
rwlock_rlock(&s->lock);
TString *ts = s->str;
while (ts) {
++info->len;
info->size += sizelstring(ts->shrlen);
ts = ts->u.hnext;
}
rwlock_runlock(&s->lock);
}
LUA_API int
luaS_shrinfo(lua_State *L) {
struct slotinfo total;
struct slotinfo tmp;
memset(&total, 0, sizeof(total));
int i;
int len = 0;
for (i=0;i<SHRSTR_SLOT;i++) {
struct shrmap_slot *s = &SSM.h[i];
getslot(s, &tmp);
len += tmp.len;
if (tmp.len > total.len) {
total.len = tmp.len;
}
total.size += tmp.size;
}
lua_pushinteger(L, len);
lua_pushinteger(L, total.size);
lua_pushinteger(L, total.len);
lua_pushinteger(L, SSM.n);
return 4;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstring.h,v 1.59 2015/03/25 13:42:19 roberto Exp $
** $Id: lstring.h,v 1.61 2015/11/03 15:36:01 roberto Exp $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
@@ -34,6 +34,7 @@
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
LUAI_FUNC unsigned int luaS_hashlongstr (TString *ts);
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
LUAI_FUNC void luaS_clearcache (global_State *g);
@@ -42,6 +43,14 @@ LUAI_FUNC void luaS_remove (lua_State *L, TString *ts);
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s);
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
LUAI_FUNC TString *luaS_createlngstrobj (lua_State *L, size_t l);
#define ENABLE_SHORT_STRING_TABLE
LUA_API void luaS_initshr();
LUA_API void luaS_exitshr();
LUA_API void luaS_expandshr(int n);
LUAI_FUNC TString *luaS_clonestring(lua_State *L, TString *);
LUA_API int luaS_shrinfo(lua_State *L);
#endif

View File

@@ -1,5 +1,5 @@
/*
** $Id: lstrlib.c,v 1.229 2015/05/20 17:39:23 roberto Exp $
** $Id: lstrlib.c,v 1.251 2016/05/20 14:13:21 roberto Exp $
** Standard library for string operations and pattern-matching
** See Copyright Notice in lua.h
*/
@@ -13,6 +13,7 @@
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <locale.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -26,7 +27,8 @@
/*
** maximum number of captures that a pattern can do during
** pattern-matching. This limit is arbitrary.
** pattern-matching. This limit is arbitrary, but must fit in
** an unsigned char.
*/
#if !defined(LUA_MAXCAPTURES)
#define LUA_MAXCAPTURES 32
@@ -41,8 +43,10 @@
** Some sizes are better limited to fit in 'int', but must also fit in
** 'size_t'. (We assume that 'lua_Integer' cannot be smaller than 'int'.)
*/
#define MAX_SIZET ((size_t)(~(size_t)0))
#define MAXSIZE \
(sizeof(size_t) < sizeof(int) ? (~(size_t)0) : (size_t)(INT_MAX))
(sizeof(size_t) < sizeof(int) ? MAX_SIZET : (size_t)(INT_MAX))
@@ -208,12 +212,12 @@ static int str_dump (lua_State *L) {
typedef struct MatchState {
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
const char *src_init; /* init of source string */
const char *src_end; /* end ('\0') of source string */
const char *p_end; /* end ('\0') of pattern */
lua_State *L;
int level; /* total number of captures (finished or unfinished) */
int matchdepth; /* control for recursive depth (to avoid C stack overflow) */
unsigned char level; /* total number of captures (finished or unfinished) */
struct {
const char *init;
ptrdiff_t len;
@@ -584,6 +588,22 @@ static int nospecials (const char *p, size_t l) {
}
static void prepstate (MatchState *ms, lua_State *L,
const char *s, size_t ls, const char *p, size_t lp) {
ms->L = L;
ms->matchdepth = MAXCCALLS;
ms->src_init = s;
ms->src_end = s + ls;
ms->p_end = p + lp;
}
static void reprepstate (MatchState *ms) {
ms->level = 0;
lua_assert(ms->matchdepth == MAXCCALLS);
}
static int str_find_aux (lua_State *L, int find) {
size_t ls, lp;
const char *s = luaL_checklstring(L, 1, &ls);
@@ -611,15 +631,10 @@ static int str_find_aux (lua_State *L, int find) {
if (anchor) {
p++; lp--; /* skip anchor character */
}
ms.L = L;
ms.matchdepth = MAXCCALLS;
ms.src_init = s;
ms.src_end = s + ls;
ms.p_end = p + lp;
prepstate(&ms, L, s, ls, p, lp);
do {
const char *res;
ms.level = 0;
lua_assert(ms.matchdepth == MAXCCALLS);
reprepstate(&ms);
if ((res=match(&ms, s1, p)) != NULL) {
if (find) {
lua_pushinteger(L, (s1 - s) + 1); /* start */
@@ -646,29 +661,25 @@ static int str_match (lua_State *L) {
}
/* state for 'gmatch' */
typedef struct GMatchState {
const char *src; /* current position */
const char *p; /* pattern */
const char *lastmatch; /* end of last match */
MatchState ms; /* match state */
} GMatchState;
static int gmatch_aux (lua_State *L) {
MatchState ms;
size_t ls, lp;
const char *s = lua_tolstring(L, lua_upvalueindex(1), &ls);
const char *p = lua_tolstring(L, lua_upvalueindex(2), &lp);
GMatchState *gm = (GMatchState *)lua_touserdata(L, lua_upvalueindex(3));
const char *src;
ms.L = L;
ms.matchdepth = MAXCCALLS;
ms.src_init = s;
ms.src_end = s+ls;
ms.p_end = p + lp;
for (src = s + (size_t)lua_tointeger(L, lua_upvalueindex(3));
src <= ms.src_end;
src++) {
gm->ms.L = L;
for (src = gm->src; src <= gm->ms.src_end; src++) {
const char *e;
ms.level = 0;
lua_assert(ms.matchdepth == MAXCCALLS);
if ((e = match(&ms, src, p)) != NULL) {
lua_Integer newstart = e-s;
if (e == src) newstart++; /* empty match? go at least one position */
lua_pushinteger(L, newstart);
lua_replace(L, lua_upvalueindex(3));
return push_captures(&ms, src, e);
reprepstate(&gm->ms);
if ((e = match(&gm->ms, src, gm->p)) != NULL && e != gm->lastmatch) {
gm->src = gm->lastmatch = e;
return push_captures(&gm->ms, src, e);
}
}
return 0; /* not found */
@@ -676,10 +687,14 @@ static int gmatch_aux (lua_State *L) {
static int gmatch (lua_State *L) {
luaL_checkstring(L, 1);
luaL_checkstring(L, 2);
lua_settop(L, 2);
lua_pushinteger(L, 0);
size_t ls, lp;
const char *s = luaL_checklstring(L, 1, &ls);
const char *p = luaL_checklstring(L, 2, &lp);
GMatchState *gm;
lua_settop(L, 2); /* keep them on closure to avoid being collected */
gm = (GMatchState *)lua_newuserdata(L, sizeof(GMatchState));
prepstate(&gm->ms, L, s, ls, p, lp);
gm->src = s; gm->p = p; gm->lastmatch = NULL;
lua_pushcclosure(L, gmatch_aux, 3);
return 1;
}
@@ -746,12 +761,13 @@ static void add_value (MatchState *ms, luaL_Buffer *b, const char *s,
static int str_gsub (lua_State *L) {
size_t srcl, lp;
const char *src = luaL_checklstring(L, 1, &srcl);
const char *p = luaL_checklstring(L, 2, &lp);
int tr = lua_type(L, 3);
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1);
const char *src = luaL_checklstring(L, 1, &srcl); /* subject */
const char *p = luaL_checklstring(L, 2, &lp); /* pattern */
const char *lastmatch = NULL; /* end of last match */
int tr = lua_type(L, 3); /* replacement type */
lua_Integer max_s = luaL_optinteger(L, 4, srcl + 1); /* max replacements */
int anchor = (*p == '^');
lua_Integer n = 0;
lua_Integer n = 0; /* replacement count */
MatchState ms;
luaL_Buffer b;
luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
@@ -761,25 +777,18 @@ static int str_gsub (lua_State *L) {
if (anchor) {
p++; lp--; /* skip anchor character */
}
ms.L = L;
ms.matchdepth = MAXCCALLS;
ms.src_init = src;
ms.src_end = src+srcl;
ms.p_end = p + lp;
prepstate(&ms, L, src, srcl, p, lp);
while (n < max_s) {
const char *e;
ms.level = 0;
lua_assert(ms.matchdepth == MAXCCALLS);
e = match(&ms, src, p);
if (e) {
reprepstate(&ms); /* (re)prepare state for new match */
if ((e = match(&ms, src, p)) != NULL && e != lastmatch) { /* match? */
n++;
add_value(&ms, &b, src, e, tr);
add_value(&ms, &b, src, e, tr); /* add replacement to buffer */
src = lastmatch = e;
}
if (e && e>src) /* non empty match? */
src = e; /* skip it */
else if (src < ms.src_end)
else if (src < ms.src_end) /* otherwise, skip one character */
luaL_addchar(&b, *src++);
else break;
else break; /* end of subject */
if (anchor) break;
}
luaL_addlstring(&b, src, ms.src_end-src);
@@ -804,7 +813,6 @@ static int str_gsub (lua_State *L) {
** Hexadecimal floating-point formatter
*/
#include <locale.h>
#include <math.h>
#define SIZELENMOD (sizeof(LUA_NUMBER_FRMLEN)/sizeof(char))
@@ -830,13 +838,12 @@ static lua_Number adddigit (char *buff, int n, lua_Number x) {
}
static int num2straux (char *buff, lua_Number x) {
static int num2straux (char *buff, int sz, lua_Number x) {
if (x != x || x == HUGE_VAL || x == -HUGE_VAL) /* inf or NaN? */
return sprintf(buff, LUA_NUMBER_FMT, x); /* equal to '%g' */
return l_sprintf(buff, sz, LUA_NUMBER_FMT, x); /* equal to '%g' */
else if (x == 0) { /* can be -0... */
sprintf(buff, LUA_NUMBER_FMT, x);
strcat(buff, "x0p+0"); /* reuses '0/-0' from 'sprintf'... */
return strlen(buff);
/* create "0" or "-0" followed by exponent */
return l_sprintf(buff, sz, LUA_NUMBER_FMT "x0p+0", x);
}
else {
int e;
@@ -855,15 +862,16 @@ static int num2straux (char *buff, lua_Number x) {
m = adddigit(buff, n++, m * 16);
} while (m > 0);
}
n += sprintf(buff + n, "p%+d", e); /* add exponent */
n += l_sprintf(buff + n, sz - n, "p%+d", e); /* add exponent */
lua_assert(n < sz);
return n;
}
}
static int lua_number2strx (lua_State *L, char *buff, const char *fmt,
lua_Number x) {
int n = num2straux(buff, x);
static int lua_number2strx (lua_State *L, char *buff, int sz,
const char *fmt, lua_Number x) {
int n = num2straux(buff, sz, x);
if (fmt[SIZELENMOD] == 'A') {
int i;
for (i = 0; i < n; i++)
@@ -879,10 +887,12 @@ static int lua_number2strx (lua_State *L, char *buff, const char *fmt,
/*
** Maximum size of each formatted item. This maximum size is produced
** by format('%.99f', minfloat), and is equal to 99 + 2 ('-' and '.') +
** number of decimal digits to represent minfloat.
** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.',
** and '\0') + number of decimal digits to represent maxfloat (which
** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra
** expenses", such as locale-dependent stuff)
*/
#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP))
#define MAX_ITEM (120 + l_mathlim(MAX_10_EXP))
/* valid flags in a format specification */
@@ -894,21 +904,19 @@ static int lua_number2strx (lua_State *L, char *buff, const char *fmt,
#define MAX_FORMAT 32
static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
static void addquoted (luaL_Buffer *b, const char *s, size_t len) {
luaL_addchar(b, '"');
while (l--) {
while (len--) {
if (*s == '"' || *s == '\\' || *s == '\n') {
luaL_addchar(b, '\\');
luaL_addchar(b, *s);
}
else if (*s == '\0' || iscntrl(uchar(*s))) {
else if (iscntrl(uchar(*s))) {
char buff[10];
if (!isdigit(uchar(*(s+1))))
sprintf(buff, "\\%d", (int)uchar(*s));
l_sprintf(buff, sizeof(buff), "\\%d", (int)uchar(*s));
else
sprintf(buff, "\\%03d", (int)uchar(*s));
l_sprintf(buff, sizeof(buff), "\\%03d", (int)uchar(*s));
luaL_addstring(b, buff);
}
else
@@ -918,6 +926,57 @@ static void addquoted (lua_State *L, luaL_Buffer *b, int arg) {
luaL_addchar(b, '"');
}
/*
** Ensures the 'buff' string uses a dot as the radix character.
*/
static void checkdp (char *buff, int nb) {
if (memchr(buff, '.', nb) == NULL) { /* no dot? */
char point = lua_getlocaledecpoint(); /* try locale point */
char *ppoint = memchr(buff, point, nb);
if (ppoint) *ppoint = '.'; /* change it to a dot */
}
}
static void addliteral (lua_State *L, luaL_Buffer *b, int arg) {
switch (lua_type(L, arg)) {
case LUA_TSTRING: {
size_t len;
const char *s = lua_tolstring(L, arg, &len);
addquoted(b, s, len);
break;
}
case LUA_TNUMBER: {
char *buff = luaL_prepbuffsize(b, MAX_ITEM);
int nb;
if (!lua_isinteger(L, arg)) { /* float? */
lua_Number n = lua_tonumber(L, arg); /* write as hexa ('%a') */
nb = lua_number2strx(L, buff, MAX_ITEM, "%" LUA_NUMBER_FRMLEN "a", n);
checkdp(buff, nb); /* ensure it uses a dot */
}
else { /* integers */
lua_Integer n = lua_tointeger(L, arg);
const char *format = (n == LUA_MININTEGER) /* corner case? */
? "0x%" LUA_INTEGER_FRMLEN "x" /* use hexa */
: LUA_INTEGER_FMT; /* else use default format */
nb = l_sprintf(buff, MAX_ITEM, format, n);
}
luaL_addsize(b, nb);
break;
}
case LUA_TNIL: case LUA_TBOOLEAN: {
luaL_tolstring(L, arg, NULL);
luaL_addvalue(b);
break;
}
default: {
luaL_argerror(L, arg, "value has no literal form");
}
}
}
static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {
const char *p = strfrmt;
while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++; /* skip flags */
@@ -975,41 +1034,46 @@ static int str_format (lua_State *L) {
strfrmt = scanformat(L, strfrmt, form);
switch (*strfrmt++) {
case 'c': {
nb = sprintf(buff, form, (int)luaL_checkinteger(L, arg));
nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg));
break;
}
case 'd': case 'i':
case 'o': case 'u': case 'x': case 'X': {
lua_Integer n = luaL_checkinteger(L, arg);
addlenmod(form, LUA_INTEGER_FRMLEN);
nb = sprintf(buff, form, n);
nb = l_sprintf(buff, MAX_ITEM, form, n);
break;
}
case 'a': case 'A':
addlenmod(form, LUA_NUMBER_FRMLEN);
nb = lua_number2strx(L, buff, form, luaL_checknumber(L, arg));
nb = lua_number2strx(L, buff, MAX_ITEM, form,
luaL_checknumber(L, arg));
break;
case 'e': case 'E': case 'f':
case 'g': case 'G': {
addlenmod(form, LUA_NUMBER_FRMLEN);
nb = sprintf(buff, form, luaL_checknumber(L, arg));
nb = l_sprintf(buff, MAX_ITEM, form, luaL_checknumber(L, arg));
break;
}
case 'q': {
addquoted(L, &b, arg);
addliteral(L, &b, arg);
break;
}
case 's': {
size_t l;
const char *s = luaL_tolstring(L, arg, &l);
if (!strchr(form, '.') && l >= 100) {
/* no precision and string is too long to be formatted;
keep original string */
luaL_addvalue(&b);
}
if (form[2] == '\0') /* no modifiers? */
luaL_addvalue(&b); /* keep entire string */
else {
nb = sprintf(buff, form, s);
lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
luaL_argcheck(L, l == strlen(s), arg, "string contains zeros");
if (!strchr(form, '.') && l >= 100) {
/* no precision and string is too long to be formatted */
luaL_addvalue(&b); /* keep entire string */
}
else { /* format the string into 'buff' */
nb = l_sprintf(buff, MAX_ITEM, form, s);
lua_pop(L, 1); /* remove result from 'luaL_tolstring' */
}
}
break;
}
@@ -1018,6 +1082,7 @@ static int str_format (lua_State *L) {
*(strfrmt - 1));
}
}
lua_assert(nb < MAX_ITEM);
luaL_addsize(&b, nb);
}
}
@@ -1036,8 +1101,8 @@ static int str_format (lua_State *L) {
/* value used for padding */
#if !defined(LUA_PACKPADBYTE)
#define LUA_PACKPADBYTE 0x00
#if !defined(LUAL_PACKPADBYTE)
#define LUAL_PACKPADBYTE 0x00
#endif
/* maximum size for the binary representation of an integer */
@@ -1274,7 +1339,7 @@ static int str_pack (lua_State *L) {
KOption opt = getdetails(&h, totalsize, &fmt, &size, &ntoalign);
totalsize += ntoalign + size;
while (ntoalign-- > 0)
luaL_addchar(&b, LUA_PACKPADBYTE); /* fill alignment */
luaL_addchar(&b, LUAL_PACKPADBYTE); /* fill alignment */
arg++;
switch (opt) {
case Kint: { /* signed integers */
@@ -1309,8 +1374,11 @@ static int str_pack (lua_State *L) {
case Kchar: { /* fixed-size string */
size_t len;
const char *s = luaL_checklstring(L, arg, &len);
luaL_argcheck(L, len == (size_t)size, arg, "wrong length");
luaL_addlstring(&b, s, size);
luaL_argcheck(L, len <= (size_t)size, arg,
"string longer than given size");
luaL_addlstring(&b, s, len); /* add string */
while (len++ < (size_t)size) /* pad extra space */
luaL_addchar(&b, LUAL_PACKPADBYTE);
break;
}
case Kstring: { /* strings with length count */
@@ -1333,7 +1401,7 @@ static int str_pack (lua_State *L) {
totalsize += len + 1;
break;
}
case Kpadding: luaL_addchar(&b, LUA_PACKPADBYTE); /* FALLTHROUGH */
case Kpadding: luaL_addchar(&b, LUAL_PACKPADBYTE); /* FALLTHROUGH */
case Kpaddalign: case Knop:
arg--; /* undo increment */
break;
@@ -1360,7 +1428,7 @@ static int str_packsize (lua_State *L) {
case Kstring: /* strings with length count */
case Kzstr: /* zero-terminated string */
luaL_argerror(L, 1, "variable-length format");
break;
/* call never return, but to avoid warnings: *//* FALLTHROUGH */
default: break;
}
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltable.c,v 2.111 2015/06/09 14:21:13 roberto Exp $
** $Id: ltable.c,v 2.117 2015/11/19 19:16:22 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -85,7 +85,7 @@ static const Node dummynode_ = {
/*
** Hash for floating-point numbers.
** The main computation should be just
** n = frepx(n, &i); return (n * INT_MAX) + i
** n = frexp(n, &i); return (n * INT_MAX) + i
** but there are some numerical subtleties.
** In a two-complement representation, INT_MAX does not has an exact
** representation as a float, but INT_MIN does; because the absolute
@@ -101,7 +101,7 @@ static int l_hashfloat (lua_Number n) {
lua_Integer ni;
n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN);
if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */
lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == HUGE_VAL);
lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == cast_num(HUGE_VAL));
return 0;
}
else { /* normal case */
@@ -124,14 +124,8 @@ static Node *mainposition (const Table *t, const TValue *key) {
return hashmod(t, l_hashfloat(fltvalue(key)));
case LUA_TSHRSTR:
return hashstr(t, tsvalue(key));
case LUA_TLNGSTR: {
TString *s = tsvalue(key);
if (s->extra == 0) { /* no hash? */
s->hash = luaS_hash(getstr(s), s->u.lnglen, s->hash);
s->extra = 1; /* now it has its hash */
}
return hashstr(t, tsvalue(key));
}
case LUA_TLNGSTR:
return hashpow2(t, luaS_hashlongstr(tsvalue(key)));
case LUA_TBOOLEAN:
return hashboolean(t, bvalue(key));
case LUA_TLIGHTUSERDATA:
@@ -139,6 +133,7 @@ static Node *mainposition (const Table *t, const TValue *key) {
case LUA_TLCF:
return hashpointer(t, fvalue(key));
default:
lua_assert(!ttisdeadkey(key));
return hashpointer(t, gcvalue(key));
}
}
@@ -463,7 +458,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
Node *f = getfreepos(t); /* get a free place */
if (f == NULL) { /* cannot find a free place? */
rehash(L, t, key); /* grow table */
/* whatever called 'newkey' takes care of TM cache and GC barrier */
/* whatever called 'newkey' takes care of TM cache */
return luaH_set(L, t, key); /* insert key into grown table */
}
lua_assert(!isdummy(f));
@@ -501,7 +496,7 @@ TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key) {
*/
const TValue *luaH_getint (Table *t, lua_Integer key) {
/* (1 <= key && key <= t->sizearray) */
if (l_castS2U(key - 1) < t->sizearray)
if (l_castS2U(key) - 1 < t->sizearray)
return &t->array[key - 1];
else {
Node *n = hashint(t, key);
@@ -513,7 +508,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
if (nx == 0) break;
n += nx;
}
};
}
return luaO_nilobject;
}
}
@@ -522,7 +517,7 @@ const TValue *luaH_getint (Table *t, lua_Integer key) {
/*
** search function for short strings
*/
const TValue *luaH_getstr (Table *t, TString *key) {
const TValue *luaH_getshortstr (Table *t, TString *key) {
Node *n = hashstr(t, key);
lua_assert(key->tt == LUA_TSHRSTR);
for (;;) { /* check whether 'key' is somewhere in the chain */
@@ -531,11 +526,41 @@ const TValue *luaH_getstr (Table *t, TString *key) {
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0) break;
if (nx == 0)
return luaO_nilobject; /* not found */
n += nx;
}
};
return luaO_nilobject;
}
}
/*
** "Generic" get version. (Not that generic: not valid for integers,
** which may be in array part, nor for floats with integral values.)
*/
static const TValue *getgeneric (Table *t, const TValue *key) {
Node *n = mainposition(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */
if (luaV_rawequalobj(gkey(n), key))
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0)
return luaO_nilobject; /* not found */
n += nx;
}
}
}
const TValue *luaH_getstr (Table *t, TString *key) {
if (key->tt == LUA_TSHRSTR)
return luaH_getshortstr(t, key);
else { /* for long strings, use generic case */
TValue ko;
setsvalue(cast(lua_State *, NULL), &ko, key);
return getgeneric(t, &ko);
}
}
@@ -544,7 +569,7 @@ const TValue *luaH_getstr (Table *t, TString *key) {
*/
const TValue *luaH_get (Table *t, const TValue *key) {
switch (ttype(key)) {
case LUA_TSHRSTR: return luaH_getstr(t, tsvalue(key));
case LUA_TSHRSTR: return luaH_getshortstr(t, tsvalue(key));
case LUA_TNUMINT: return luaH_getint(t, ivalue(key));
case LUA_TNIL: return luaO_nilobject;
case LUA_TNUMFLT: {
@@ -553,19 +578,8 @@ const TValue *luaH_get (Table *t, const TValue *key) {
return luaH_getint(t, k); /* use specialized version */
/* else... */
} /* FALLTHROUGH */
default: {
Node *n = mainposition(t, key);
for (;;) { /* check whether 'key' is somewhere in the chain */
if (luaV_rawequalobj(gkey(n), key))
return gval(n); /* that's it */
else {
int nx = gnext(n);
if (nx == 0) break;
n += nx;
}
};
return luaO_nilobject;
}
default:
return getgeneric(t, key);
}
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltable.h,v 2.20 2014/09/04 18:15:29 roberto Exp $
** $Id: ltable.h,v 2.21 2015/11/03 15:47:30 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
@@ -18,6 +18,10 @@
/* 'const' to avoid wrong writings that can mess up field 'next' */
#define gkey(n) cast(const TValue*, (&(n)->i_key.tvk))
/*
** writable version of 'gkey'; allows updates to individual fields,
** but not to the whole (which has incompatible type)
*/
#define wgkey(n) (&(n)->i_key.nk)
#define invalidateTMcache(t) ((t)->flags = 0)
@@ -31,6 +35,7 @@
LUAI_FUNC const TValue *luaH_getint (Table *t, lua_Integer key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key,
TValue *value);
LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltablib.c,v 1.80 2015/01/13 16:27:29 roberto Exp $
** $Id: ltablib.c,v 1.93 2016/02/25 19:41:54 roberto Exp $
** Library for Table Manipulation
** See Copyright Notice in lua.h
*/
@@ -12,6 +12,7 @@
#include <limits.h>
#include <stddef.h>
#include <string.h>
#include "lua.h"
@@ -19,40 +20,42 @@
#include "lualib.h"
/*
** Structure with table-access functions
** Operations that an object must define to mimic a table
** (some functions only need some of them)
*/
typedef struct {
int (*geti) (lua_State *L, int idx, lua_Integer n);
void (*seti) (lua_State *L, int idx, lua_Integer n);
} TabA;
#define TAB_R 1 /* read */
#define TAB_W 2 /* write */
#define TAB_L 4 /* length */
#define TAB_RW (TAB_R | TAB_W) /* read/write */
/*
** Check that 'arg' has a table and set access functions in 'ta' to raw
** or non-raw according to the presence of corresponding metamethods.
*/
static void checktab (lua_State *L, int arg, TabA *ta) {
ta->geti = NULL; ta->seti = NULL;
if (lua_getmetatable(L, arg)) {
lua_pushliteral(L, "__index"); /* 'index' metamethod */
if (lua_rawget(L, -2) != LUA_TNIL)
ta->geti = lua_geti;
lua_pushliteral(L, "__newindex"); /* 'newindex' metamethod */
if (lua_rawget(L, -3) != LUA_TNIL)
ta->seti = lua_seti;
lua_pop(L, 3); /* pop metatable plus both metamethods */
}
if (ta->geti == NULL || ta->seti == NULL) {
luaL_checktype(L, arg, LUA_TTABLE); /* must be table for raw methods */
if (ta->geti == NULL) ta->geti = lua_rawgeti;
if (ta->seti == NULL) ta->seti = lua_rawseti;
}
#define aux_getn(L,n,w) (checktab(L, n, (w) | TAB_L), luaL_len(L, n))
static int checkfield (lua_State *L, const char *key, int n) {
lua_pushstring(L, key);
return (lua_rawget(L, -n) != LUA_TNIL);
}
#define aux_getn(L,n,ta) (checktab(L, n, ta), luaL_len(L, n))
/*
** Check that 'arg' either is a table or can behave like one (that is,
** has a metatable with the required metamethods)
*/
static void checktab (lua_State *L, int arg, int what) {
if (lua_type(L, arg) != LUA_TTABLE) { /* is it not a table? */
int n = 1; /* number of elements to pop */
if (lua_getmetatable(L, arg) && /* must have metatable */
(!(what & TAB_R) || checkfield(L, "__index", ++n)) &&
(!(what & TAB_W) || checkfield(L, "__newindex", ++n)) &&
(!(what & TAB_L) || checkfield(L, "__len", ++n))) {
lua_pop(L, n); /* pop metatable and tested metamethods */
}
else
luaL_checktype(L, arg, LUA_TTABLE); /* force an error */
}
}
#if defined(LUA_COMPAT_MAXN)
@@ -74,8 +77,7 @@ static int maxn (lua_State *L) {
static int tinsert (lua_State *L) {
TabA ta;
lua_Integer e = aux_getn(L, 1, &ta) + 1; /* first empty element */
lua_Integer e = aux_getn(L, 1, TAB_RW) + 1; /* first empty element */
lua_Integer pos; /* where to insert new element */
switch (lua_gettop(L)) {
case 2: { /* called with only 2 arguments */
@@ -87,8 +89,8 @@ static int tinsert (lua_State *L) {
pos = luaL_checkinteger(L, 2); /* 2nd argument is the position */
luaL_argcheck(L, 1 <= pos && pos <= e, 2, "position out of bounds");
for (i = e; i > pos; i--) { /* move up elements */
(*ta.geti)(L, 1, i - 1);
(*ta.seti)(L, 1, i); /* t[i] = t[i - 1] */
lua_geti(L, 1, i - 1);
lua_seti(L, 1, i); /* t[i] = t[i - 1] */
}
break;
}
@@ -96,67 +98,67 @@ static int tinsert (lua_State *L) {
return luaL_error(L, "wrong number of arguments to 'insert'");
}
}
(*ta.seti)(L, 1, pos); /* t[pos] = v */
lua_seti(L, 1, pos); /* t[pos] = v */
return 0;
}
static int tremove (lua_State *L) {
TabA ta;
lua_Integer size = aux_getn(L, 1, &ta);
lua_Integer size = aux_getn(L, 1, TAB_RW);
lua_Integer pos = luaL_optinteger(L, 2, size);
if (pos != size) /* validate 'pos' if given */
luaL_argcheck(L, 1 <= pos && pos <= size + 1, 1, "position out of bounds");
(*ta.geti)(L, 1, pos); /* result = t[pos] */
lua_geti(L, 1, pos); /* result = t[pos] */
for ( ; pos < size; pos++) {
(*ta.geti)(L, 1, pos + 1);
(*ta.seti)(L, 1, pos); /* t[pos] = t[pos + 1] */
lua_geti(L, 1, pos + 1);
lua_seti(L, 1, pos); /* t[pos] = t[pos + 1] */
}
lua_pushnil(L);
(*ta.seti)(L, 1, pos); /* t[pos] = nil */
lua_seti(L, 1, pos); /* t[pos] = nil */
return 1;
}
/*
** Copy elements (1[f], ..., 1[e]) into (tt[t], tt[t+1], ...). Whenever
** possible, copy in increasing order, which is better for rehashing.
** "possible" means destination after original range, or smaller
** than origin, or copying to another table.
*/
static int tmove (lua_State *L) {
TabA ta;
lua_Integer f = luaL_checkinteger(L, 2);
lua_Integer e = luaL_checkinteger(L, 3);
lua_Integer t = luaL_checkinteger(L, 4);
int tt = !lua_isnoneornil(L, 5) ? 5 : 1; /* destination table */
checktab(L, 1, TAB_R);
checktab(L, tt, TAB_W);
if (e >= f) { /* otherwise, nothing to move */
lua_Integer n, i;
ta.geti = (luaL_getmetafield(L, 1, "__index") == LUA_TNIL)
? (luaL_checktype(L, 1, LUA_TTABLE), lua_rawgeti)
: lua_geti;
ta.seti = (luaL_getmetafield(L, tt, "__newindex") == LUA_TNIL)
? (luaL_checktype(L, tt, LUA_TTABLE), lua_rawseti)
: lua_seti;
luaL_argcheck(L, f > 0 || e < LUA_MAXINTEGER + f, 3,
"too many elements to move");
n = e - f + 1; /* number of elements to move */
luaL_argcheck(L, t <= LUA_MAXINTEGER - n + 1, 4,
"destination wrap around");
if (t > f) {
for (i = n - 1; i >= 0; i--) {
(*ta.geti)(L, 1, f + i);
(*ta.seti)(L, tt, t + i);
if (t > e || t <= f || (tt != 1 && !lua_compare(L, 1, tt, LUA_OPEQ))) {
for (i = 0; i < n; i++) {
lua_geti(L, 1, f + i);
lua_seti(L, tt, t + i);
}
}
else {
for (i = 0; i < n; i++) {
(*ta.geti)(L, 1, f + i);
(*ta.seti)(L, tt, t + i);
for (i = n - 1; i >= 0; i--) {
lua_geti(L, 1, f + i);
lua_seti(L, tt, t + i);
}
}
}
lua_pushvalue(L, tt); /* return "to table" */
lua_pushvalue(L, tt); /* return destination table */
return 1;
}
static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) {
(*ta->geti)(L, 1, i);
static void addfield (lua_State *L, luaL_Buffer *b, lua_Integer i) {
lua_geti(L, 1, i);
if (!lua_isstring(L, -1))
luaL_error(L, "invalid value (%s) at index %d in table for 'concat'",
luaL_typename(L, -1), i);
@@ -165,21 +167,19 @@ static void addfield (lua_State *L, luaL_Buffer *b, TabA *ta, lua_Integer i) {
static int tconcat (lua_State *L) {
TabA ta;
luaL_Buffer b;
lua_Integer last = aux_getn(L, 1, TAB_R);
size_t lsep;
lua_Integer i, last;
const char *sep = luaL_optlstring(L, 2, "", &lsep);
checktab(L, 1, &ta);
i = luaL_optinteger(L, 3, 1);
last = luaL_opt(L, luaL_checkinteger, 4, luaL_len(L, 1));
lua_Integer i = luaL_optinteger(L, 3, 1);
last = luaL_optinteger(L, 4, last);
luaL_buffinit(L, &b);
for (; i < last; i++) {
addfield(L, &b, &ta, i);
addfield(L, &b, i);
luaL_addlstring(&b, sep, lsep);
}
if (i == last) /* add last value (if interval was not empty) */
addfield(L, &b, &ta, i);
addfield(L, &b, i);
luaL_pushresult(&b);
return 1;
}
@@ -197,7 +197,7 @@ static int pack (lua_State *L) {
lua_createtable(L, n, 1); /* create result table */
lua_insert(L, 1); /* put it at index 1 */
for (i = n; i >= 1; i--) /* assign elements */
lua_rawseti(L, 1, i);
lua_seti(L, 1, i);
lua_pushinteger(L, n);
lua_setfield(L, 1, "n"); /* t.n = number of elements */
return 1; /* return table */
@@ -205,20 +205,17 @@ static int pack (lua_State *L) {
static int unpack (lua_State *L) {
TabA ta;
lua_Integer i, e;
lua_Unsigned n;
checktab(L, 1, &ta);
i = luaL_optinteger(L, 2, 1);
e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
lua_Integer i = luaL_optinteger(L, 2, 1);
lua_Integer e = luaL_opt(L, luaL_checkinteger, 3, luaL_len(L, 1));
if (i > e) return 0; /* empty range */
n = (lua_Unsigned)e - i; /* number of elements minus 1 (avoid overflows) */
if (n >= (unsigned int)INT_MAX || !lua_checkstack(L, (int)(++n)))
return luaL_error(L, "too many results to unpack");
do { /* must have at least one element */
(*ta.geti)(L, 1, i); /* push arg[i..e] */
} while (i++ < e);
for (; i < e; i++) { /* push arg[i..e - 1] (to avoid overflows) */
lua_geti(L, 1, i);
}
lua_geti(L, 1, e); /* push last element */
return (int)n;
}
@@ -235,97 +232,191 @@ static int unpack (lua_State *L) {
*/
static void set2 (lua_State *L, TabA *ta, int i, int j) {
(*ta->seti)(L, 1, i);
(*ta->seti)(L, 1, j);
/* type for array indices */
typedef unsigned int IdxT;
/*
** Produce a "random" 'unsigned int' to randomize pivot choice. This
** macro is used only when 'sort' detects a big imbalance in the result
** of a partition. (If you don't want/need this "randomness", ~0 is a
** good choice.)
*/
#if !defined(l_randomizePivot) /* { */
#include <time.h>
/* size of 'e' measured in number of 'unsigned int's */
#define sof(e) (sizeof(e) / sizeof(unsigned int))
/*
** Use 'time' and 'clock' as sources of "randomness". Because we don't
** know the types 'clock_t' and 'time_t', we cannot cast them to
** anything without risking overflows. A safe way to use their values
** is to copy them to an array of a known type and use the array values.
*/
static unsigned int l_randomizePivot (void) {
clock_t c = clock();
time_t t = time(NULL);
unsigned int buff[sof(c) + sof(t)];
unsigned int i, rnd = 0;
memcpy(buff, &c, sof(c) * sizeof(unsigned int));
memcpy(buff + sof(c), &t, sof(t) * sizeof(unsigned int));
for (i = 0; i < sof(buff); i++)
rnd += buff[i];
return rnd;
}
#endif /* } */
/* arrays larger than 'RANLIMIT' may use randomized pivots */
#define RANLIMIT 100u
static void set2 (lua_State *L, IdxT i, IdxT j) {
lua_seti(L, 1, i);
lua_seti(L, 1, j);
}
/*
** Return true iff value at stack index 'a' is less than the value at
** index 'b' (according to the order of the sort).
*/
static int sort_comp (lua_State *L, int a, int b) {
if (!lua_isnil(L, 2)) { /* function? */
if (lua_isnil(L, 2)) /* no function? */
return lua_compare(L, a, b, LUA_OPLT); /* a < b */
else { /* function */
int res;
lua_pushvalue(L, 2);
lua_pushvalue(L, 2); /* push function */
lua_pushvalue(L, a-1); /* -1 to compensate function */
lua_pushvalue(L, b-2); /* -2 to compensate function and 'a' */
lua_call(L, 2, 1);
res = lua_toboolean(L, -1);
lua_pop(L, 1);
lua_call(L, 2, 1); /* call function */
res = lua_toboolean(L, -1); /* get result */
lua_pop(L, 1); /* pop result */
return res;
}
else /* a < b? */
return lua_compare(L, a, b, LUA_OPLT);
}
static void auxsort (lua_State *L, TabA *ta, int l, int u) {
while (l < u) { /* for tail recursion */
int i, j;
/* sort elements a[l], a[(l+u)/2] and a[u] */
(*ta->geti)(L, 1, l);
(*ta->geti)(L, 1, u);
if (sort_comp(L, -1, -2)) /* a[u] < a[l]? */
set2(L, ta, l, u); /* swap a[l] - a[u] */
/*
** Does the partition: Pivot P is at the top of the stack.
** precondition: a[lo] <= P == a[up-1] <= a[up],
** so it only needs to do the partition from lo + 1 to up - 2.
** Pos-condition: a[lo .. i - 1] <= a[i] == P <= a[i + 1 .. up]
** returns 'i'.
*/
static IdxT partition (lua_State *L, IdxT lo, IdxT up) {
IdxT i = lo; /* will be incremented before first use */
IdxT j = up - 1; /* will be decremented before first use */
/* loop invariant: a[lo .. i] <= P <= a[j .. up] */
for (;;) {
/* next loop: repeat ++i while a[i] < P */
while (lua_geti(L, 1, ++i), sort_comp(L, -1, -2)) {
if (i == up - 1) /* a[i] < P but a[up - 1] == P ?? */
luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[i] */
}
/* after the loop, a[i] >= P and a[lo .. i - 1] < P */
/* next loop: repeat --j while P < a[j] */
while (lua_geti(L, 1, --j), sort_comp(L, -3, -1)) {
if (j < i) /* j < i but a[j] > P ?? */
luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[j] */
}
/* after the loop, a[j] <= P and a[j + 1 .. up] >= P */
if (j < i) { /* no elements out of place? */
/* a[lo .. i - 1] <= P <= a[j + 1 .. i .. up] */
lua_pop(L, 1); /* pop a[j] */
/* swap pivot (a[up - 1]) with a[i] to satisfy pos-condition */
set2(L, up - 1, i);
return i;
}
/* otherwise, swap a[i] - a[j] to restore invariant and repeat */
set2(L, i, j);
}
}
/*
** Choose an element in the middle (2nd-3th quarters) of [lo,up]
** "randomized" by 'rnd'
*/
static IdxT choosePivot (IdxT lo, IdxT up, unsigned int rnd) {
IdxT r4 = (up - lo) / 4; /* range/4 */
IdxT p = rnd % (r4 * 2) + (lo + r4);
lua_assert(lo + r4 <= p && p <= up - r4);
return p;
}
/*
** QuickSort algorithm (recursive function)
*/
static void auxsort (lua_State *L, IdxT lo, IdxT up,
unsigned int rnd) {
while (lo < up) { /* loop for tail recursion */
IdxT p; /* Pivot index */
IdxT n; /* to be used later */
/* sort elements 'lo', 'p', and 'up' */
lua_geti(L, 1, lo);
lua_geti(L, 1, up);
if (sort_comp(L, -1, -2)) /* a[up] < a[lo]? */
set2(L, lo, up); /* swap a[lo] - a[up] */
else
lua_pop(L, 2);
if (u-l == 1) break; /* only 2 elements */
i = (l+u)/2;
(*ta->geti)(L, 1, i);
(*ta->geti)(L, 1, l);
if (sort_comp(L, -2, -1)) /* a[i]<a[l]? */
set2(L, ta, i, l);
lua_pop(L, 2); /* remove both values */
if (up - lo == 1) /* only 2 elements? */
return; /* already sorted */
if (up - lo < RANLIMIT || rnd == 0) /* small interval or no randomize? */
p = (lo + up)/2; /* middle element is a good pivot */
else /* for larger intervals, it is worth a random pivot */
p = choosePivot(lo, up, rnd);
lua_geti(L, 1, p);
lua_geti(L, 1, lo);
if (sort_comp(L, -2, -1)) /* a[p] < a[lo]? */
set2(L, p, lo); /* swap a[p] - a[lo] */
else {
lua_pop(L, 1); /* remove a[l] */
(*ta->geti)(L, 1, u);
if (sort_comp(L, -1, -2)) /* a[u]<a[i]? */
set2(L, ta, i, u);
lua_pop(L, 1); /* remove a[lo] */
lua_geti(L, 1, up);
if (sort_comp(L, -1, -2)) /* a[up] < a[p]? */
set2(L, p, up); /* swap a[up] - a[p] */
else
lua_pop(L, 2);
}
if (u-l == 2) break; /* only 3 elements */
(*ta->geti)(L, 1, i); /* Pivot */
lua_pushvalue(L, -1);
(*ta->geti)(L, 1, u-1);
set2(L, ta, i, u-1);
/* a[l] <= P == a[u-1] <= a[u], only need to sort from l+1 to u-2 */
i = l; j = u-1;
for (;;) { /* invariant: a[l..i] <= P <= a[j..u] */
/* repeat ++i until a[i] >= P */
while ((*ta->geti)(L, 1, ++i), sort_comp(L, -1, -2)) {
if (i>=u) luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[i] */
}
/* repeat --j until a[j] <= P */
while ((*ta->geti)(L, 1, --j), sort_comp(L, -3, -1)) {
if (j<=l) luaL_error(L, "invalid order function for sorting");
lua_pop(L, 1); /* remove a[j] */
}
if (j<i) {
lua_pop(L, 3); /* pop pivot, a[i], a[j] */
break;
}
set2(L, ta, i, j);
}
(*ta->geti)(L, 1, u-1);
(*ta->geti)(L, 1, i);
set2(L, ta, u-1, i); /* swap pivot (a[u-1]) with a[i] */
/* a[l..i-1] <= a[i] == P <= a[i+1..u] */
/* adjust so that smaller half is in [j..i] and larger one in [l..u] */
if (i-l < u-i) {
j=l; i=i-1; l=i+2;
if (up - lo == 2) /* only 3 elements? */
return; /* already sorted */
lua_geti(L, 1, p); /* get middle element (Pivot) */
lua_pushvalue(L, -1); /* push Pivot */
lua_geti(L, 1, up - 1); /* push a[up - 1] */
set2(L, p, up - 1); /* swap Pivot (a[p]) with a[up - 1] */
p = partition(L, lo, up);
/* a[lo .. p - 1] <= a[p] == P <= a[p + 1 .. up] */
if (p - lo < up - p) { /* lower interval is smaller? */
auxsort(L, lo, p - 1, rnd); /* call recursively for lower interval */
n = p - lo; /* size of smaller interval */
lo = p + 1; /* tail call for [p + 1 .. up] (upper interval) */
}
else {
j=i+1; i=u; u=j-2;
auxsort(L, p + 1, up, rnd); /* call recursively for upper interval */
n = up - p; /* size of smaller interval */
up = p - 1; /* tail call for [lo .. p - 1] (lower interval) */
}
auxsort(L, ta, j, i); /* call recursively the smaller one */
} /* repeat the routine for the larger one */
if ((up - lo) / 128 > n) /* partition too imbalanced? */
rnd = l_randomizePivot(); /* try a new randomization */
} /* tail call auxsort(L, lo, up, rnd) */
}
static int sort (lua_State *L) {
TabA ta;
int n = (int)aux_getn(L, 1, &ta);
luaL_checkstack(L, 50, ""); /* assume array is smaller than 2^50 */
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
luaL_checktype(L, 2, LUA_TFUNCTION);
lua_settop(L, 2); /* make sure there are two arguments */
auxsort(L, &ta, 1, n);
lua_Integer n = aux_getn(L, 1, TAB_RW);
if (n > 1) { /* non-trivial interval? */
luaL_argcheck(L, n < INT_MAX, 1, "array too big");
if (!lua_isnoneornil(L, 2)) /* is there a 2nd argument? */
luaL_checktype(L, 2, LUA_TFUNCTION); /* must be a function */
lua_settop(L, 2); /* make sure there are two arguments */
auxsort(L, 1, (IdxT)n, 0);
}
return 0;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltm.c,v 2.34 2015/03/30 15:42:27 roberto Exp $
** $Id: ltm.c,v 2.37 2016/02/26 19:20:15 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -57,7 +57,7 @@ void luaT_init (lua_State *L) {
** tag methods
*/
const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
const TValue *tm = luaH_getstr(events, ename);
const TValue *tm = luaH_getshortstr(events, ename);
lua_assert(event <= TM_EQ);
if (ttisnil(tm)) { /* no tag method? */
events->flags |= cast_byte(1u<<event); /* cache this fact */
@@ -79,20 +79,41 @@ const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
default:
mt = G(L)->mt[ttnov(o)];
}
return (mt ? luaH_getstr(mt, G(L)->tmname[event]) : luaO_nilobject);
return (mt ? luaH_getshortstr(mt, G(L)->tmname[event]) : luaO_nilobject);
}
/*
** Return the name of the type of an object. For tables and userdata
** with metatable, use their '__name' metafield, if present.
*/
const char *luaT_objtypename (lua_State *L, const TValue *o) {
Table *mt;
if ((ttistable(o) && (mt = hvalue(o)->metatable) != NULL) ||
(ttisfulluserdata(o) && (mt = uvalue(o)->metatable) != NULL)) {
const TValue *name = luaH_getshortstr(mt, luaS_new(L, "__name"));
if (ttisstring(name)) /* is '__name' a string? */
return getstr(tsvalue(name)); /* use it as type name */
}
return ttypename(ttnov(o)); /* else use standard type name */
}
void luaT_callTM (lua_State *L, const TValue *f, const TValue *p1,
const TValue *p2, TValue *p3, int hasres) {
ptrdiff_t result = savestack(L, p3);
setobj2s(L, L->top++, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, L->top++, p1); /* 1st argument */
setobj2s(L, L->top++, p2); /* 2nd argument */
StkId func = L->top;
setobj2s(L, func, f); /* push function (assume EXTRA_STACK) */
setobj2s(L, func + 1, p1); /* 1st argument */
setobj2s(L, func + 2, p2); /* 2nd argument */
L->top += 3;
if (!hasres) /* no result? 'p3' is third argument */
setobj2s(L, L->top++, p3); /* 3rd argument */
/* metamethod may yield only when called from Lua code */
luaD_call(L, L->top - (4 - hasres), hasres, isLua(L->ci));
if (isLua(L->ci))
luaD_call(L, func, hasres);
else
luaD_callnoyield(L, func, hasres);
if (hasres) { /* if has result, move it to its place */
p3 = restorestack(L, result);
setobjs2s(L, p3, --L->top);

View File

@@ -1,5 +1,5 @@
/*
** $Id: ltm.h,v 2.21 2014/10/25 11:50:46 roberto Exp $
** $Id: ltm.h,v 2.22 2016/02/26 19:20:15 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
@@ -51,11 +51,12 @@ typedef enum {
#define fasttm(l,et,e) gfasttm(G(l), et, e)
#define ttypename(x) luaT_typenames_[(x) + 1]
#define objtypename(x) ttypename(ttnov(x))
LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
LUAI_FUNC const char *luaT_objtypename (lua_State *L, const TValue *o);
LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
TMS event);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lua.c,v 1.225 2015/03/30 15:42:59 roberto Exp $
** $Id: lua.c,v 1.226 2015/08/14 19:11:20 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/
@@ -18,6 +18,7 @@
#include "lauxlib.h"
#include "lualib.h"
#include "lstring.h"
#if !defined(LUA_PROMPT)
@@ -324,24 +325,20 @@ static int pushline (lua_State *L, int firstline) {
/*
** Try to compile line on the stack as 'return <line>'; on return, stack
** Try to compile line on the stack as 'return <line>;'; on return, stack
** has either compiled chunk or original line (if compilation failed).
*/
static int addreturn (lua_State *L) {
int status;
size_t len; const char *line;
lua_pushliteral(L, "return ");
lua_pushvalue(L, -2); /* duplicate line */
lua_concat(L, 2); /* new line is "return ..." */
line = lua_tolstring(L, -1, &len);
if ((status = luaL_loadbuffer(L, line, len, "=stdin")) == LUA_OK) {
lua_remove(L, -3); /* remove original line */
line += sizeof("return")/sizeof(char); /* remove 'return' for history */
const char *line = lua_tostring(L, -1); /* original line */
const char *retline = lua_pushfstring(L, "return %s;", line);
int status = luaL_loadbuffer(L, retline, strlen(retline), "=stdin");
if (status == LUA_OK) {
lua_remove(L, -2); /* remove modified line */
if (line[0] != '\0') /* non empty? */
lua_saveline(L, line); /* keep history */
}
else
lua_pop(L, 2); /* remove result from 'luaL_loadbuffer' and new line */
lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */
return status;
}
@@ -596,7 +593,9 @@ static int pmain (lua_State *L) {
int main (int argc, char **argv) {
int status, result;
lua_State *L = luaL_newstate(); /* create state */
lua_State *L;
luaS_initshr(); /* init global short string table */
L = luaL_newstate(); /* create state */
if (L == NULL) {
l_message(argv[0], "cannot create state: not enough memory");
return EXIT_FAILURE;
@@ -608,6 +607,7 @@ int main (int argc, char **argv) {
result = lua_toboolean(L, -1); /* get result */
report(L, status);
lua_close(L);
luaS_exitshr();
return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lua.h,v 1.328 2015/06/03 13:03:38 roberto Exp $
** $Id: lua.h,v 1.331 2016/05/30 15:53:28 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
@@ -19,11 +19,11 @@
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "3"
#define LUA_VERSION_NUM 503
#define LUA_VERSION_RELEASE "1"
#define LUA_VERSION_RELEASE "3"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2015 Lua.org, PUC-Rio"
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2016 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@@ -363,7 +363,7 @@ LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
#define lua_pushliteral(L, s) lua_pushstring(L, "" s)
#define lua_pushglobaltable(L) \
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
((void)lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
@@ -467,7 +467,7 @@ LUA_API void (lua_checksig_)(lua_State *L);
#define lua_checksig(L) if (skynet_sig_L) { lua_checksig_(L); }
/******************************************************************************
* Copyright (C) 1994-2015 Lua.org, PUC-Rio.
* Copyright (C) 1994-2016 Lua.org, PUC-Rio.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the

View File

@@ -21,6 +21,7 @@
#include "lobject.h"
#include "lstate.h"
#include "lundump.h"
#include "lstring.h"
static void PrintFunction(const Proto* f, int full);
#define luaU_print PrintFunction
@@ -195,6 +196,7 @@ int main(int argc, char* argv[])
int i=doargs(argc,argv);
argc-=i; argv+=i;
if (argc<=0) usage("no input files given");
luaS_initshr();
L=luaL_newstate();
if (L==NULL) fatal("cannot create state: not enough memory");
lua_pushcfunction(L,&pmain);

View File

@@ -1,5 +1,5 @@
/*
** $Id: luaconf.h,v 1.251 2015/05/20 17:39:23 roberto Exp $
** $Id: luaconf.h,v 1.255 2016/05/01 20:06:09 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
@@ -145,7 +145,7 @@
#if !defined(LUA_FLOAT_TYPE)
#define LUA_FLOAT_TYPE LUA_FLOAT_DOUBLE
#endif /* } */
#endif
/* }================================================================== */
@@ -412,9 +412,33 @@
@@ LUA_NUMBER_FMT is the format for writing floats.
@@ lua_number2str converts a float to a string.
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations.
@@ l_floor takes the floor of a float.
@@ lua_str2number converts a decimal numeric string to a number.
*/
/* The following definitions are good for most cases here */
#define l_floor(x) (l_mathop(floor)(x))
#define lua_number2str(s,sz,n) l_sprintf((s), sz, LUA_NUMBER_FMT, (n))
/*
@@ lua_numbertointeger converts a float number to an integer, or
** returns 0 if float is not within the range of a lua_Integer.
** (The range comparisons are tricky because of rounding. The tests
** here assume a two-complement representation, where MININTEGER always
** has an exact representation as a float; MAXINTEGER may not have one,
** and therefore its conversion to float may have an ill-defined value.)
*/
#define lua_numbertointeger(n,p) \
((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
(n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
(*(p) = (LUA_INTEGER)(n), 1))
/* now the variable definitions */
#if LUA_FLOAT_TYPE == LUA_FLOAT_FLOAT /* { single float */
#define LUA_NUMBER float
@@ -468,25 +492,6 @@
#endif /* } */
#define l_floor(x) (l_mathop(floor)(x))
#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
/*
@@ lua_numbertointeger converts a float number to an integer, or
** returns 0 if float is not within the range of a lua_Integer.
** (The range comparisons are tricky because of rounding. The tests
** here assume a two-complement representation, where MININTEGER always
** has an exact representation as a float; MAXINTEGER may not have one,
** and therefore its conversion to float may have an ill-defined value.)
*/
#define lua_numbertointeger(n,p) \
((n) >= (LUA_NUMBER)(LUA_MININTEGER) && \
(n) < -(LUA_NUMBER)(LUA_MININTEGER) && \
(*(p) = (LUA_INTEGER)(n), 1))
/*
@@ LUA_INTEGER is the integer type used by Lua.
@@ -506,7 +511,7 @@
/* The following definitions are good for most cases here */
#define LUA_INTEGER_FMT "%" LUA_INTEGER_FRMLEN "d"
#define lua_integer2str(s,n) sprintf((s), LUA_INTEGER_FMT, (n))
#define lua_integer2str(s,sz,n) l_sprintf((s), sz, LUA_INTEGER_FMT, (n))
#define LUAI_UACINT LUA_INTEGER
@@ -537,6 +542,7 @@
#elif LUA_INT_TYPE == LUA_INT_LONGLONG /* }{ long long */
/* use presence of macro LLONG_MAX as proxy for C99 compliance */
#if defined(LLONG_MAX) /* { */
/* use ISO C99 stuff */
@@ -577,6 +583,17 @@
** ===================================================================
*/
/*
@@ l_sprintf is equivalent to 'snprintf' or 'sprintf' in C89.
** (All uses in Lua have only one format item.)
*/
#if !defined(LUA_USE_C89)
#define l_sprintf(s,sz,f,i) snprintf(s,sz,f,i)
#else
#define l_sprintf(s,sz,f,i) ((void)(sz), sprintf(s,f,i))
#endif
/*
@@ lua_strx2number converts an hexadecimal numeric string to a number.
** In C99, 'strtod' does that conversion. Otherwise, you can
@@ -584,7 +601,7 @@
** implementation.
*/
#if !defined(LUA_USE_C89)
#define lua_strx2number(s,p) lua_str2number(s,p)
#define lua_strx2number(s,p) lua_str2number(s,p)
#endif
@@ -595,7 +612,7 @@
** provide its own implementation.
*/
#if !defined(LUA_USE_C89)
#define lua_number2strx(L,b,f,n) sprintf(b,f,n)
#define lua_number2strx(L,b,sz,f,n) ((void)L, l_sprintf(b,sz,f,n))
#endif

View File

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

View File

@@ -1,5 +1,5 @@
/*
** $Id: lundump.c,v 2.41 2014/11/02 19:19:04 roberto Exp $
** $Id: lundump.c,v 2.44 2015/11/02 16:09:30 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -32,7 +32,6 @@
typedef struct {
lua_State *L;
ZIO *Z;
Mbuffer *b;
const char *name;
} LoadState;
@@ -92,10 +91,15 @@ static TString *LoadString (LoadState *S) {
LoadVar(S, size);
if (size == 0)
return NULL;
else {
char *s = luaZ_openspace(S->L, S->b, --size);
LoadVector(S, s, size);
return luaS_newlstr(S->L, s, size);
else if (--size <= LUAI_MAXSHORTLEN) { /* short string? */
char buff[LUAI_MAXSHORTLEN];
LoadVector(S, buff, size);
return luaS_newlstr(S->L, buff, size);
}
else { /* long string */
TString *ts = luaS_createlngstrobj(S->L, size);
LoadVector(S, getstr(ts), size); /* load directly in final place */
return ts;
}
}
@@ -252,8 +256,7 @@ static void checkHeader (LoadState *S) {
/*
** load precompiled chunk
*/
LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
const char *name) {
LClosure *luaU_undump(lua_State *L, ZIO *Z, const char *name) {
LoadState S;
LClosure *cl;
if (*name == '@' || *name == '=')
@@ -264,14 +267,13 @@ LClosure *luaU_undump(lua_State *L, ZIO *Z, Mbuffer *buff,
S.name = name;
S.L = L;
S.Z = Z;
S.b = buff;
checkHeader(&S);
cl = luaF_newLclosure(L, LoadByte(&S));
setclLvalue(L, L->top, cl);
incr_top(L);
luaD_inctop(L);
cl->p = luaF_newproto(L, NULL);
LoadFunction(&S, cl->p, NULL);
lua_assert(cl->nupvalues == cl->p->sizeupvalues);
lua_assert(cl->nupvalues == cl->p->sp->sizeupvalues);
luai_verifycode(L, buff, cl->p);
return cl;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lundump.h,v 1.44 2014/06/19 18:27:20 roberto Exp $
** $Id: lundump.h,v 1.45 2015/09/08 15:41:05 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
@@ -23,8 +23,7 @@
#define LUAC_FORMAT 0 /* this is the official format */
/* load one chunk; from lundump.c */
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff,
const char* name);
LUAI_FUNC LClosure* luaU_undump (lua_State* L, ZIO* Z, const char* name);
/* dump one chunk; from ldump.c */
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w,

View File

@@ -1,5 +1,5 @@
/*
** $Id: lvm.c,v 2.245 2015/06/09 15:53:35 roberto Exp $
** $Id: lvm.c,v 2.268 2016/02/05 19:59:14 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -66,7 +66,7 @@
/* Add by skynet */
lua_State * skynet_sig_L = NULL;
LUA_API void
LUA_API void
lua_checksig_(lua_State *L) {
if (skynet_sig_L == G(L)->mainthread) {
skynet_sig_L = NULL;
@@ -163,75 +163,88 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
/*
** Main function for table access (invoking metamethods if needed).
** Compute 'val = t[key]'
** Finish the table access 'val = t[key]'.
** if 'slot' is NULL, 't' is not a table; otherwise, 'slot' points to
** t[k] entry (which must be nil).
*/
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) {
void luaV_finishget (lua_State *L, const TValue *t, TValue *key, StkId val,
const TValue *slot) {
int loop; /* counter to avoid infinite loops */
const TValue *tm; /* metamethod */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (ttistable(t)) { /* 't' is a table? */
Table *h = hvalue(t);
const TValue *res = luaH_get(h, key); /* do a primitive get */
if (!ttisnil(res) || /* result is not nil? */
(tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */
setobj2s(L, val, res); /* result is the raw get */
if (slot == NULL) { /* 't' is not a table? */
lua_assert(!ttistable(t));
tm = luaT_gettmbyobj(L, t, TM_INDEX);
if (ttisnil(tm))
luaG_typeerror(L, t, "index"); /* no metamethod */
/* else will try the metamethod */
}
else { /* 't' is a table */
lua_assert(ttisnil(slot));
tm = fasttm(L, hvalue(t)->metatable, TM_INDEX); /* table's metamethod */
if (tm == NULL) { /* no metamethod? */
setnilvalue(val); /* result is nil */
return;
}
/* else will try metamethod */
/* else will try the metamethod */
}
else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX)))
luaG_typeerror(L, t, "index"); /* no metamethod */
if (ttisfunction(tm)) { /* metamethod is a function */
luaT_callTM(L, tm, t, key, val, 1);
if (ttisfunction(tm)) { /* is metamethod a function? */
luaT_callTM(L, tm, t, key, val, 1); /* call it */
return;
}
t = tm; /* else repeat access over 'tm' */
t = tm; /* else try to access 'tm[key]' */
if (luaV_fastget(L,t,key,slot,luaH_get)) { /* fast track? */
setobj2s(L, val, slot); /* done */
return;
}
/* else repeat (tail call 'luaV_finishget') */
}
luaG_runerror(L, "gettable chain too long; possible loop");
luaG_runerror(L, "'__index' chain too long; possible loop");
}
/*
** Main function for table assignment (invoking metamethods if needed).
** Compute 't[key] = val'
** Finish a table assignment 't[key] = val'.
** If 'slot' is NULL, 't' is not a table. Otherwise, 'slot' points
** to the entry 't[key]', or to 'luaO_nilobject' if there is no such
** entry. (The value at 'slot' must be nil, otherwise 'luaV_fastset'
** would have done the job.)
*/
void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot) {
int loop; /* counter to avoid infinite loops */
for (loop = 0; loop < MAXTAGLOOP; loop++) {
const TValue *tm;
if (ttistable(t)) { /* 't' is a table? */
Table *h = hvalue(t);
TValue *oldval = cast(TValue *, luaH_get(h, key));
/* if previous value is not nil, there must be a previous entry
in the table; a metamethod has no relevance */
if (!ttisnil(oldval) ||
/* previous value is nil; must check the metamethod */
((tm = fasttm(L, h->metatable, TM_NEWINDEX)) == NULL &&
/* no metamethod; is there a previous entry in the table? */
(oldval != luaO_nilobject ||
/* no previous entry; must create one. (The next test is
always true; we only need the assignment.) */
(oldval = luaH_newkey(L, h, key), 1)))) {
const TValue *tm; /* '__newindex' metamethod */
if (slot != NULL) { /* is 't' a table? */
Table *h = hvalue(t); /* save 't' table */
lua_assert(ttisnil(slot)); /* old value must be nil */
tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */
if (tm == NULL) { /* no metamethod? */
if (slot == luaO_nilobject) /* no previous entry? */
slot = luaH_newkey(L, h, key); /* create one */
/* no metamethod and (now) there is an entry with given key */
setobj2t(L, oldval, val); /* assign new value to that entry */
setobj2t(L, cast(TValue *, slot), val); /* set its new value */
invalidateTMcache(h);
luaC_barrierback(L, h, val);
return;
}
/* else will try the metamethod */
}
else /* not a table; check metamethod */
else { /* not a table; check metamethod */
if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_NEWINDEX)))
luaG_typeerror(L, t, "index");
}
/* try the metamethod */
if (ttisfunction(tm)) {
luaT_callTM(L, tm, t, key, val, 0);
return;
}
t = tm; /* else repeat assignment over 'tm' */
if (luaV_fastset(L, t, key, slot, luaH_get, val))
return; /* done */
/* else loop */
}
luaG_runerror(L, "settable chain too long; possible loop");
luaG_runerror(L, "'__newindex' chain too long; possible loop");
}
@@ -453,6 +466,17 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) {
#define isemptystr(o) (ttisshrstring(o) && tsvalue(o)->shrlen == 0)
/* copy strings in stack from top - n up to top - 1 to buffer */
static void copy2buff (StkId top, int n, char *buff) {
size_t tl = 0; /* size already copied */
do {
size_t l = vslen(top - n); /* length of string being copied */
memcpy(buff + tl, svalue(top - n), l * sizeof(char));
tl += l;
} while (--n > 0);
}
/*
** Main operation for concatenation: concat 'total' values in the stack,
** from 'L->top - total' up to 'L->top - 1'.
@@ -472,24 +496,24 @@ void luaV_concat (lua_State *L, int total) {
else {
/* at least two non-empty string values; get as many as possible */
size_t tl = vslen(top - 1);
char *buffer;
int i;
/* collect total length */
for (i = 1; i < total && tostring(L, top-i-1); i++) {
size_t l = vslen(top - i - 1);
TString *ts;
/* collect total length and number of strings */
for (n = 1; n < total && tostring(L, top - n - 1); n++) {
size_t l = vslen(top - n - 1);
if (l >= (MAX_SIZE/sizeof(char)) - tl)
luaG_runerror(L, "string length overflow");
tl += l;
}
buffer = luaZ_openspace(L, &G(L)->buff, tl);
tl = 0;
n = i;
do { /* copy all strings to buffer */
size_t l = vslen(top - i);
memcpy(buffer+tl, svalue(top-i), l * sizeof(char));
tl += l;
} while (--i > 0);
setsvalue2s(L, top-n, luaS_newlstr(L, buffer, tl)); /* create result */
if (tl <= LUAI_MAXSHORTLEN) { /* is result a short string? */
char buff[LUAI_MAXSHORTLEN];
copy2buff(top, n, buff); /* copy strings to buffer */
ts = luaS_newlstr(L, buff, tl);
}
else { /* long string; copy strings directly to final result */
ts = luaS_createlngstrobj(L, tl);
copy2buff(top, n, getstr(ts));
}
setsvalue2s(L, top - n, ts); /* create result */
}
total -= n-1; /* got 'n' strings to create 1 new */
L->top -= n-1; /* popped 'n' strings and pushed one */
@@ -710,27 +734,20 @@ void luaV_finishOp (lua_State *L) {
** some macros for common tasks in 'luaV_execute'
*/
#if !defined(luai_runtimecheck)
#define luai_runtimecheck(L, c) /* void */
#endif
#define RA(i) (base+GETARG_A(i))
/* to be used after possible stack reallocation */
#define RB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgR, base+GETARG_B(i))
#define RC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgR, base+GETARG_C(i))
#define RKB(i) check_exp(getBMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_B(i)) ? k+INDEXK(GETARG_B(i)) : base+GETARG_B(i))
#define RKC(i) check_exp(getCMode(GET_OPCODE(i)) == OpArgK, \
ISK(GETARG_C(i)) ? k+INDEXK(GETARG_C(i)) : base+GETARG_C(i))
#define KBx(i) \
(k + (GETARG_Bx(i) != 0 ? GETARG_Bx(i) - 1 : GETARG_Ax(*ci->u.l.savedpc++)))
/* execute a jump instruction */
#define dojump(ci,i,e) \
{ int a = GETARG_A(i); \
if (a > 0) luaF_close(L, ci->u.l.base + a - 1); \
if (a != 0) luaF_close(L, ci->u.l.base + a - 1); \
ci->u.l.savedpc += GETARG_sBx(i) + e; }
/* for test instructions, execute the jump instruction that follows it */
@@ -740,38 +757,58 @@ void luaV_finishOp (lua_State *L) {
#define Protect(x) { {x;}; base = ci->u.l.base; }
#define checkGC(L,c) \
Protect( luaC_condGC(L,{L->top = (c); /* limit of live values */ \
luaC_step(L); \
L->top = ci->top;}) /* restore top */ \
luai_threadyield(L); )
{ luaC_condGC(L, L->top = (c), /* limit of live values */ \
Protect(L->top = ci->top)); /* restore top */ \
luai_threadyield(L); }
/* fetch an instruction and prepare its execution */
#define vmfetch() { \
i = *(ci->u.l.savedpc++); \
if (L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) \
Protect(luaG_traceexec(L)); \
ra = RA(i); /* WARNING: any stack reallocation invalidates 'ra' */ \
lua_assert(base == ci->u.l.base); \
lua_assert(base <= L->top && L->top < L->stack + L->stacksize); \
}
#define vmdispatch(o) switch(o)
#define vmcase(l) case l:
#define vmbreak break
/*
** copy of 'luaV_gettable', but protecting the call to potential
** metamethod (which can reallocate the stack)
*/
#define gettableProtected(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else Protect(luaV_finishget(L,t,k,v,slot)); }
/* same for 'luaV_settable' */
#define settableProtected(L,t,k,v) { const TValue *slot; \
if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
Protect(luaV_finishset(L,t,k,v,slot)); }
void luaV_execute (lua_State *L) {
CallInfo *ci = L->ci;
LClosure *cl;
TValue *k;
StkId base;
ci->callstatus |= CIST_FRESH; /* fresh invocation of 'luaV_execute" */
newframe: /* reentry point when frame changes (call/return) */
lua_assert(ci == L->ci);
cl = clLvalue(ci->func);
k = cl->p->k;
base = ci->u.l.base;
cl = clLvalue(ci->func); /* local reference to function's closure */
k = cl->p->k; /* local reference to function's constant table */
base = ci->u.l.base; /* local copy of function's base */
/* main loop of interpreter */
for (;;) {
Instruction i = *(ci->u.l.savedpc++);
Instruction i;
StkId ra;
if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) &&
(--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) {
Protect(luaG_traceexec(L));
}
/* WARNING: several calls may realloc the stack and invalidate 'ra' */
ra = RA(i);
lua_assert(base == ci->u.l.base);
lua_assert(base <= L->top && L->top < L->stack + L->stacksize);
vmfetch();
vmdispatch (GET_OPCODE(i)) {
vmcase(OP_MOVE) {
setobjs2s(L, ra, RB(i));
@@ -807,17 +844,22 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_GETTABUP) {
int b = GETARG_B(i);
Protect(luaV_gettable(L, cl->upvals[b]->v, RKC(i), ra));
TValue *upval = cl->upvals[GETARG_B(i)]->v;
TValue *rc = RKC(i);
gettableProtected(L, upval, rc, ra);
vmbreak;
}
vmcase(OP_GETTABLE) {
Protect(luaV_gettable(L, RB(i), RKC(i), ra));
StkId rb = RB(i);
TValue *rc = RKC(i);
gettableProtected(L, rb, rc, ra);
vmbreak;
}
vmcase(OP_SETTABUP) {
int a = GETARG_A(i);
Protect(luaV_settable(L, cl->upvals[a]->v, RKB(i), RKC(i)));
TValue *upval = cl->upvals[GETARG_A(i)]->v;
TValue *rb = RKB(i);
TValue *rc = RKC(i);
settableProtected(L, upval, rb, rc);
vmbreak;
}
vmcase(OP_SETUPVAL) {
@@ -827,7 +869,9 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_SETTABLE) {
Protect(luaV_settable(L, ra, RKB(i), RKC(i)));
TValue *rb = RKB(i);
TValue *rc = RKC(i);
settableProtected(L, ra, rb, rc);
vmbreak;
}
vmcase(OP_NEWTABLE) {
@@ -841,9 +885,15 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_SELF) {
const TValue *aux;
StkId rb = RB(i);
setobjs2s(L, ra+1, rb);
Protect(luaV_gettable(L, rb, RKC(i), ra));
TValue *rc = RKC(i);
TString *key = tsvalue(rc); /* key must be a string */
setobjs2s(L, ra + 1, rb);
if (luaV_fastget(L, rb, key, aux, luaH_getstr)) {
setobj2s(L, ra, aux);
}
else Protect(luaV_finishget(L, rb, rc, ra, aux));
vmbreak;
}
vmcase(OP_ADD) {
@@ -1030,7 +1080,7 @@ void luaV_execute (lua_State *L) {
StkId rb;
L->top = base + c + 1; /* mark the end of concat operands */
Protect(luaV_concat(L, c - b + 1));
ra = RA(i); /* 'luav_concat' may invoke TMs and move the stack */
ra = RA(i); /* 'luaV_concat' may invoke TMs and move the stack */
rb = base + b;
setobjs2s(L, ra, rb);
checkGC(L, (ra >= rb ? ra + 1 : rb));
@@ -1046,7 +1096,7 @@ void luaV_execute (lua_State *L) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
Protect(
if (cast_int(luaV_equalobj(L, rb, rc)) != GETARG_A(i))
if (luaV_equalobj(L, rb, rc) != GETARG_A(i))
ci->u.l.savedpc++;
else
donextjump(ci);
@@ -1094,12 +1144,12 @@ void luaV_execute (lua_State *L) {
lua_checksig(L);
if (b != 0) L->top = ra+b; /* else previous instruction set top */
if (luaD_precall(L, ra, nresults)) { /* C function? */
if (nresults >= 0) L->top = ci->top; /* adjust results */
base = ci->u.l.base;
if (nresults >= 0)
L->top = ci->top; /* adjust results */
Protect((void)0); /* update 'base' */
}
else { /* Lua function */
ci = L->ci;
ci->callstatus |= CIST_REENTRY;
goto newframe; /* restart luaV_execute over new Lua function */
}
vmbreak;
@@ -1109,8 +1159,9 @@ void luaV_execute (lua_State *L) {
lua_checksig(L);
if (b != 0) L->top = ra+b; /* else previous instruction set top */
lua_assert(GETARG_C(i) - 1 == LUA_MULTRET);
if (luaD_precall(L, ra, LUA_MULTRET)) /* C function? */
base = ci->u.l.base;
if (luaD_precall(L, ra, LUA_MULTRET)) { /* C function? */
Protect((void)0); /* update 'base' */
}
else {
/* tail call: put called frame (n) in place of caller one (o) */
CallInfo *nci = L->ci; /* called frame */
@@ -1130,7 +1181,7 @@ void luaV_execute (lua_State *L) {
oci->u.l.savedpc = nci->u.l.savedpc;
oci->callstatus |= CIST_TAIL; /* function was tail called */
ci = L->ci = oci; /* remove new frame */
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->maxstacksize);
lua_assert(L->top == oci->u.l.base + getproto(ofunc)->sp->maxstacksize);
goto newframe; /* restart luaV_execute over new Lua function */
}
vmbreak;
@@ -1138,8 +1189,8 @@ void luaV_execute (lua_State *L) {
vmcase(OP_RETURN) {
int b = GETARG_B(i);
if (cl->p->sp->sizep > 0) luaF_close(L, base);
b = luaD_poscall(L, ra, (b != 0 ? b - 1 : L->top - ra));
if (!(ci->callstatus & CIST_REENTRY)) /* 'ci' still the called one */
b = luaD_poscall(L, ci, ra, (b != 0 ? b - 1 : cast_int(L->top - ra)));
if (ci->callstatus & CIST_FRESH) /* local 'ci' still from callee */
return; /* external invocation: return */
else { /* invocation via reentry: continue execution */
ci = L->ci;
@@ -1152,7 +1203,7 @@ void luaV_execute (lua_State *L) {
vmcase(OP_FORLOOP) {
if (ttisinteger(ra)) { /* integer loop? */
lua_Integer step = ivalue(ra + 2);
lua_Integer idx = ivalue(ra) + step; /* increment index */
lua_Integer idx = intop(+, ivalue(ra), step); /* increment index */
lua_Integer limit = ivalue(ra + 1);
if ((0 < step) ? (idx <= limit) : (limit <= idx)) {
ci->u.l.savedpc += GETARG_sBx(i); /* jump back */
@@ -1184,7 +1235,7 @@ void luaV_execute (lua_State *L) {
/* all values are integer */
lua_Integer initv = (stopnow ? 0 : ivalue(init));
setivalue(plimit, ilimit);
setivalue(init, initv - ivalue(pstep));
setivalue(init, intop(-, initv, ivalue(pstep)));
}
else { /* try making all values floats */
lua_Number ninit; lua_Number nlimit; lua_Number nstep;
@@ -1207,7 +1258,7 @@ void luaV_execute (lua_State *L) {
setobjs2s(L, cb+1, ra+1);
setobjs2s(L, cb, ra);
L->top = cb + 3; /* func. + 2 args (state and index) */
Protect(luaD_call(L, cb, GETARG_C(i), 1));
Protect(luaD_call(L, cb, GETARG_C(i)));
L->top = ci->top;
i = *(ci->u.l.savedpc++); /* go to next instruction */
ra = RA(i);
@@ -1233,11 +1284,10 @@ void luaV_execute (lua_State *L) {
lua_assert(GET_OPCODE(*ci->u.l.savedpc) == OP_EXTRAARG);
c = GETARG_Ax(*ci->u.l.savedpc++);
}
luai_runtimecheck(L, ttistable(ra));
h = hvalue(ra);
last = ((c-1)*LFIELDS_PER_FLUSH) + n;
if (last > h->sizearray) /* needs more space? */
luaH_resizearray(L, h, last); /* pre-allocate it at once */
luaH_resizearray(L, h, last); /* preallocate it at once */
for (; n > 0; n--) {
TValue *val = ra+n;
luaH_setint(L, h, last--, val);
@@ -1257,23 +1307,21 @@ void luaV_execute (lua_State *L) {
vmbreak;
}
vmcase(OP_VARARG) {
int b = GETARG_B(i) - 1;
int b = GETARG_B(i) - 1; /* required results */
int j;
int n = cast_int(base - ci->func) - cl->p->sp->numparams - 1;
if (n < 0) /* less arguments than parameters? */
n = 0; /* no vararg arguments */
if (b < 0) { /* B == 0? */
b = n; /* get all var. arguments */
Protect(luaD_checkstack(L, n));
ra = RA(i); /* previous call may change the stack */
L->top = ra + n;
}
for (j = 0; j < b; j++) {
if (j < n) {
setobjs2s(L, ra + j, base - n + j);
}
else {
setnilvalue(ra + j);
}
}
for (j = 0; j < b && j < n; j++)
setobjs2s(L, ra + j, base - n + j);
for (; j < b; j++) /* complete required results with nil */
setnilvalue(ra + j);
vmbreak;
}
vmcase(OP_EXTRAARG) {

View File

@@ -1,5 +1,5 @@
/*
** $Id: lvm.h,v 2.35 2015/02/20 14:27:53 roberto Exp $
** $Id: lvm.h,v 2.40 2016/01/05 16:07:21 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -48,15 +48,60 @@
#define luaV_rawequalobj(t1,t2) luaV_equalobj(NULL,t1,t2)
/*
** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
** return 1 with 'slot' pointing to 't[k]' (final result). Otherwise,
** return 0 (meaning it will have to check metamethod) with 'slot'
** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
** 'f' is the raw get function to use.
*/
#define luaV_fastget(L,t,k,slot,f) \
(!ttistable(t) \
? (slot = NULL, 0) /* not a table; 'slot' is NULL and result is 0 */ \
: (slot = f(hvalue(t), k), /* else, do raw access */ \
!ttisnil(slot))) /* result not nil? */
/*
** standard implementation for 'gettable'
*/
#define luaV_gettable(L,t,k,v) { const TValue *slot; \
if (luaV_fastget(L,t,k,slot,luaH_get)) { setobj2s(L, v, slot); } \
else luaV_finishget(L,t,k,v,slot); }
/*
** Fast track for set table. If 't' is a table and 't[k]' is not nil,
** call GC barrier, do a raw 't[k]=v', and return true; otherwise,
** return false with 'slot' equal to NULL (if 't' is not a table) or
** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro
** returns true, there is no need to 'invalidateTMcache', because the
** call is not creating a new entry.
*/
#define luaV_fastset(L,t,k,slot,f,v) \
(!ttistable(t) \
? (slot = NULL, 0) \
: (slot = f(hvalue(t), k), \
ttisnil(slot) ? 0 \
: (luaC_barrierback(L, hvalue(t), v), \
setobj2t(L, cast(TValue *,slot), v), \
1)))
#define luaV_settable(L,t,k,v) { const TValue *slot; \
if (!luaV_fastset(L,t,k,slot,luaH_get,v)) \
luaV_finishset(L,t,k,v,slot); }
LUAI_FUNC int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2);
LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_tonumber_ (const TValue *obj, lua_Number *n);
LUAI_FUNC int luaV_tointeger (const TValue *obj, lua_Integer *p, int mode);
LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
StkId val);
LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
StkId val);
LUAI_FUNC void luaV_finishget (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total);

View File

@@ -1,5 +1,5 @@
/*
** $Id: lzio.c,v 1.36 2014/11/02 19:19:04 roberto Exp $
** $Id: lzio.c,v 1.37 2015/09/08 15:41:05 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -66,13 +66,3 @@ size_t luaZ_read (ZIO *z, void *b, size_t n) {
return 0;
}
/* ------------------------------------------------------------------------ */
char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n) {
if (n > buff->buffsize) {
if (n < LUA_MINBUFFER) n = LUA_MINBUFFER;
luaZ_resizebuffer(L, buff, n);
}
return buff->buffer;
}

View File

@@ -1,5 +1,5 @@
/*
** $Id: lzio.h,v 1.30 2014/12/19 17:26:14 roberto Exp $
** $Id: lzio.h,v 1.31 2015/09/08 15:41:05 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
@@ -44,7 +44,6 @@ typedef struct Mbuffer {
#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0)
LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n);
LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
void *data);
LUAI_FUNC size_t luaZ_read (ZIO* z, void *b, size_t n); /* read next n bytes */

View File

@@ -1,3 +1,85 @@
v1.0.0-rc4 (2016-6-13)
-----------
* Update lua to 5.3.3
* Update jemalloc to 4.2.1
* Add debug console command ping
* Lua bson support __pairs
* Add mongo.createIndexes and fix bug in old mongo.createIndex
* Handle signal HUP to reopen log file (for logrotate)
v1.0.0-rc3 (2016-5-9)
-----------
* Update jemalloc 4.1.1
* Update lua 5.3.3 rc1
* Update sproto to support encoding empty table
* Make skynet.init stable (keep order)
* skynet.getenv can return empty string
* Add lua VM memory warning
* lua VM support memory limit
* skynet.pcall suport varargs
* Bugfix : Global name query
* Bugfix : snax.queryglobal
v1.0.0-rc2 (2016-3-7)
-----------
* Fix a bug in lua 5.3.2
* Update sproto (fix bugs and add ud for package)
* Fix a bug in http
* Fix a bug in harbor
* Fix a bug in socket channel
* Enhance remote debugger
v1.0.0-rc (2015-12-28)
-----------
* Update to lua 5.3.2
* Add skynet.coroutine lib
* Add new debug api to show c memory used
* httpc can use async dns query
* Redis driver support pipeline
* socket.send support string table, and rewrite redis driver
* socket.shutdown would abandon unsend buffer
* Improve some sproto api
* c memory doesn't count the memory allocated by lua vm
* some other bugfix (In multicast, socketchannel, etc)
v1.0.0-beta (2015-11-10)
-----------
* Improve and fix bug for sproto
* Add global short string pool for lua vm
* Add code cache mode
* Add a callback for mysql auth
* Add hmac_md5
* Sharedata support filename as a string
* Fix a bug in socket.httpc
* Fix a lua stack overflow bug in lua bson
* Fix a socketchannel bug may block the data steam
* Avoid dead loop when sending message to the service exiting
* Fix memory leak in netpack
* Improve DH key exchange implement
* Minor fix for socket
* Minor fix for multicast
* Update jemalloc to 4.0.4
* Update lpeg to 1.0.0
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)
-----------
* Update lua 5.3.1

View File

@@ -5,7 +5,8 @@ CSERVICE_PATH ?= cservice
SKYNET_BUILD_PATH ?= .
CFLAGS = -g -O2 -Wall -I$(LUA_INC) $(MYCFLAGS)
CFLAGS = -g -O2 -Wall -I$(LUA_INC) $(MYCFLAGS)
# CFLAGS += -DUSE_PTHREAD_LOCK
# lua
@@ -23,7 +24,7 @@ JEMALLOC_INC := 3rd/jemalloc/include/jemalloc
all : jemalloc
.PHONY : jemalloc
.PHONY : jemalloc update3rd
MALLOC_STATICLIB := $(JEMALLOC_STATICLIB)
@@ -38,6 +39,9 @@ $(JEMALLOC_STATICLIB) : 3rd/jemalloc/Makefile
jemalloc : $(MALLOC_STATICLIB)
update3rd :
rm -rf 3rd/jemalloc && git submodule update --init
# skynet
CSERVICE = snlua logger gate harbor
@@ -79,7 +83,7 @@ $(LUA_CLIB_PATH)/socketdriver.so : lualib-src/lua-socket.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src -Iservice-src
$(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)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@ -Iskynet-src
@@ -109,7 +113,7 @@ $(LUA_CLIB_PATH)/crypt.so : lualib-src/lua-crypt.c lualib-src/lsha1.c | $(LUA_CL
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(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)
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
@@ -124,13 +128,15 @@ $(LUA_CLIB_PATH)/mysqlaux.so : lualib-src/lua-mysqlaux.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(LUA_CLIB_PATH)/debugchannel.so : lualib-src/lua-debugchannel.c | $(LUA_CLIB_PATH)
$(CC) $(CFLAGS) $(SHARED) $^ -o $@
$(CC) $(CFLAGS) $(SHARED) -Iskynet-src $^ -o $@
clean :
rm -f $(SKYNET_BUILD_PATH)/skynet $(CSERVICE_PATH)/*.so $(LUA_CLIB_PATH)/*.so
cleanall: clean
ifneq (,$(wildcard 3rd/jemalloc/Makefile))
cd 3rd/jemalloc && $(MAKE) clean
endif
cd 3rd/lua && $(MAKE) clean
rm -f $(LUA_STATICLIB)

View File

@@ -1,6 +1,6 @@
## Build
For linux, install autoconf first for jemalloc
For Linux, install autoconf first for jemalloc:
```
git clone https://github.com/cloudwu/skynet.git
@@ -8,31 +8,33 @@ cd skynet
make 'PLATFORM' # PLATFORM can be linux, macosx, freebsd now
```
Or you can :
Or you can:
```
export PLAT=linux
make
```
For freeBSD , use gmake instead of make .
For FreeBSD , use gmake instead of make.
## Test
Run these in different console
Run these in different consoles:
```
./skynet examples/config # Launch first skynet node (Gate server) and a skynet-master (see config for standalone option)
./3rd/lua/lua examples/client.lua # Launch a client, and try to input hello.
```
## About Lua
## About Lua version
Skynet now use Lua 5.3.0 final, http://www.lua.org/ftp/lua-5.3.0.tar.gz
Skynet now uses a modified version of lua 5.3.3 ( http://www.lua.org/ftp/lua-5.3.3.tar.gz ) .
You can also use the other official Lua version , edit the makefile by yourself .
For details: http://lua-users.org/lists/lua-l/2014-03/msg00489.html
## How To (in Chinese)
You can also use official Lua versions, just edit the Makefile by yourself.
## How To Use (Sorry, Only in Chinese now)
* Read Wiki https://github.com/cloudwu/skynet/wiki
* The FAQ in wiki https://github.com/cloudwu/skynet/wiki/FAQ

View File

@@ -0,0 +1,30 @@
local skynet = require "skynet"
local list = {}
local function timeout_check(ti)
if not next(list) then
return
end
skynet.sleep(ti) -- sleep 10 sec
for k,v in pairs(list) do
skynet.error("timout",ti,k,v)
end
end
skynet.start(function()
skynet.error("ping all")
local list_ret = skynet.call(".launcher", "lua", "LIST")
for addr, desc in pairs(list_ret) do
list[addr] = desc
skynet.fork(function()
skynet.call(addr,"debug","INFO")
list[addr] = nil
end)
end
skynet.sleep(0)
timeout_check(100)
timeout_check(400)
timeout_check(500)
skynet.exit()
end)

View File

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

View File

@@ -2,10 +2,18 @@ local skynet = require "skynet"
local cluster = require "cluster"
skynet.start(function()
local proxy = cluster.proxy("db", ".simpledb")
print(skynet.call(proxy, "lua", "GET", "a"))
print(cluster.call("db", ".simpledb", "GET", "a"))
print(cluster.call("db2", ".simpledb", "GET", "b"))
-- query name "sdb" of cluster db.
local sdb = cluster.query("db", "sdb")
print("db.sbd=",sdb)
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
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
print("connect")
local fd = assert(socket.connect("127.0.0.1", 8888))
fd = assert(socket.connect("127.0.0.1", 8888))
last = ""
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
print("connect again")
local fd = assert(socket.connect("127.0.0.1", 8888))
fd = assert(socket.connect("127.0.0.1", 8888))
last = ""
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
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
local agent = skynet.newservice "msgagent"
@@ -25,11 +26,11 @@ function server.login_handler(uid, secret)
username = username,
agent = agent,
uid = uid,
subid = internal_id,
subid = id,
}
-- trash subid (no used)
skynet.call(agent, "lua", "login", uid, internal_id, secret)
skynet.call(agent, "lua", "login", uid, id, secret)
users[uid] = u
username_map[username] = u
@@ -37,7 +38,7 @@ function server.login_handler(uid, secret)
msgserver.login(username, secret)
-- you should return unique subid
return internal_id
return id
end
-- call by agent
@@ -73,9 +74,9 @@ function server.disconnect_handler(username)
end
-- 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]
return skynet.tostring(skynet.rawcall(u.agent, "client", msg, sz))
return skynet.tostring(skynet.rawcall(u.agent, "client", msg))
end
-- call by self (when gate open)

View File

@@ -19,7 +19,7 @@ function server.auth_handler(token)
user = crypt.base64decode(user)
server = crypt.base64decode(server)
password = crypt.base64decode(password)
assert(password == "password")
assert(password == "password", "Invalid password")
return server, user
end

View File

@@ -46,7 +46,7 @@ skynet.start(function()
end)
skynet.dispatch("client", function(_,_, msg)
-- the simple ehco service
-- the simple echo service
skynet.sleep(10) -- sleep a while
skynet.ret(msg)
end)

View File

@@ -4,7 +4,7 @@ local sprotoloader = require "sprotoloader"
local max_client = 64
skynet.start(function()
print("Server start")
skynet.error("Server start")
skynet.uniqueservice("protoloader")
local console = skynet.newservice("console")
skynet.newservice("debug_console",8000)
@@ -15,7 +15,6 @@ skynet.start(function()
maxclient = max_client,
nodelay = true,
})
print("Watchdog listen on ", 8888)
skynet.error("Watchdog listen on", 8888)
skynet.exit()
end)

View File

@@ -37,6 +37,16 @@ skynet.start(function()
skynet.error(string.format("b[%d]=%s", k,v))
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
skynet.sleep(100)
skynet.error("second " ..i)

25
examples/userlog.lua Normal file
View File

@@ -0,0 +1,25 @@
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(":%08x(%.2f): %s", address, skynet.time(), msg))
end
}
skynet.register_protocol {
name = "SYSTEM",
id = skynet.PTYPE_SYSTEM,
unpack = function(...) return ... end,
dispatch = function()
-- reopen signal
print("SIGHUP")
end
}
skynet.start(function()
skynet.register ".logger"
end)

View File

@@ -32,6 +32,11 @@ function SOCKET.error(fd, msg)
close_agent(fd)
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)
end

View File

@@ -8,9 +8,12 @@
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "atomic.h"
#define DEFAULT_CAP 64
#define MAX_NUMBER 1024
// avoid circular reference while encodeing
#define MAX_DEPTH 128
#define BSON_REAL 1
#define BSON_STRING 2
@@ -235,7 +238,7 @@ write_double(struct bson *b, lua_Number d) {
}
}
static void pack_dict(lua_State *L, struct bson *b, bool array);
static void pack_dict(lua_State *L, struct bson *b, bool array, int depth);
static inline void
append_key(struct bson *bs, int type, const char *key, size_t sz) {
@@ -243,12 +246,16 @@ append_key(struct bson *bs, int type, const char *key, size_t sz) {
write_string(bs, key, sz);
}
static inline int
is_32bit(int64_t v) {
return v >= INT32_MIN && v <= INT32_MAX;
}
static void
append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) {
if (lua_isinteger(L, -1)) {
int64_t i = lua_tointeger(L, -1);
int si = i >> 31;
if (si == 0 || si == -1) {
if (is_32bit(i)) {
append_key(bs, BSON_INT32, key, sz);
write_int32(bs, i);
} else {
@@ -263,7 +270,7 @@ append_number(struct bson *bs, lua_State *L, const char *key, size_t sz) {
}
static void
append_table(struct bson *bs, lua_State *L, const char *key, size_t sz) {
append_table(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) {
size_t len = lua_rawlen(L, -1);
bool isarray = false;
if (len > 0) {
@@ -279,7 +286,7 @@ append_table(struct bson *bs, lua_State *L, const char *key, size_t sz) {
} else {
append_key(bs, BSON_DOCUMENT, key, sz);
}
pack_dict(L, bs, isarray);
pack_dict(L, bs, isarray, depth);
}
static void
@@ -292,7 +299,7 @@ write_binary(struct bson *b, const void * buffer, size_t sz) {
}
static void
append_one(struct bson *bs, lua_State *L, const char *key, size_t sz) {
append_one(struct bson *bs, lua_State *L, const char *key, size_t sz, int depth) {
int vt = lua_type(L,-1);
switch(vt) {
case LUA_TNUMBER:
@@ -380,7 +387,7 @@ append_one(struct bson *bs, lua_State *L, const char *key, size_t sz) {
break;
}
case LUA_TTABLE:
append_table(bs, L, key, sz);
append_table(bs, L, key, sz, depth+1);
break;
case LUA_TBOOLEAN:
append_key(bs, BSON_BOOLEAN, key, sz);
@@ -402,51 +409,97 @@ bson_numstr( char *str, unsigned int i ) {
}
static void
pack_dict(lua_State *L, struct bson *b, bool isarray) {
pack_dict_data(lua_State *L, struct bson *b, bool isarray, int depth, int kt) {
char numberkey[32];
const char * key = NULL;
size_t sz;
if (isarray) {
if (kt != LUA_TNUMBER) {
luaL_error(L, "Invalid array key type : %s", lua_typename(L, kt));
return;
}
sz = bson_numstr(numberkey, (unsigned int)lua_tointeger(L,-2)-1);
key = numberkey;
append_one(b, L, key, sz, depth);
lua_pop(L,1);
} else {
switch(kt) {
case LUA_TNUMBER:
// copy key, don't change key type
lua_pushvalue(L,-2);
lua_insert(L,-2);
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz, depth);
lua_pop(L,2);
break;
case LUA_TSTRING:
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz, depth);
lua_pop(L,1);
break;
default:
luaL_error(L, "Invalid key type : %s", lua_typename(L, kt));
return;
}
}
}
static void
pack_simple_dict(lua_State *L, struct bson *b, bool isarray, int depth) {
if (depth > MAX_DEPTH) {
luaL_error(L, "Too depth while encoding bson");
}
luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table
int length = reserve_length(b);
lua_pushnil(L);
while(lua_next(L,-2) != 0) {
int kt = lua_type(L, -2);
char numberkey[32];
const char * key = NULL;
size_t sz;
if (isarray) {
if (kt != LUA_TNUMBER) {
luaL_error(L, "Invalid array key type : %s", lua_typename(L, kt));
return;
}
sz = bson_numstr(numberkey, (unsigned int)lua_tointeger(L,-2)-1);
key = numberkey;
pack_dict_data(L, b, isarray, depth, kt);
}
write_byte(b,0);
write_length(b, b->size - length, length);
}
append_one(b, L, key, sz);
lua_pop(L,1);
} else {
switch(kt) {
case LUA_TNUMBER:
// copy key, don't change key type
lua_pushvalue(L,-2);
lua_insert(L,-2);
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz);
lua_pop(L,2);
break;
case LUA_TSTRING:
key = lua_tolstring(L,-2,&sz);
append_one(b, L, key, sz);
lua_pop(L,1);
break;
default:
luaL_error(L, "Invalid key type : %s", lua_typename(L, kt));
return;
}
static void
pack_meta_dict(lua_State *L, struct bson *b, bool isarray, int depth) {
if (depth > MAX_DEPTH) {
luaL_error(L, "Too depth while encoding bson");
}
luaL_checkstack(L, 16, NULL); // reserve enough stack space to pack table
int length = reserve_length(b);
lua_pushvalue(L, -2); // push meta_obj
lua_call(L, 1, 3); // call __pairs_func => next_func, t_data, first_k
for(;;) {
lua_pushvalue(L, -2); // copy data
lua_pushvalue(L, -2); // copy k
lua_copy(L, -5, -3); // copy next_func replace old_k
lua_call(L, 2, 2); // call next_func
int kt = lua_type(L, -2);
if (kt == LUA_TNIL) {
lua_pop(L, 4); // pop all k, v, next_func, obj
break;
}
pack_dict_data(L, b, isarray, depth, kt);
}
write_byte(b,0);
write_length(b, b->size - length, length);
}
static void
pack_ordered_dict(lua_State *L, struct bson *b, int n) {
pack_dict(lua_State *L, struct bson *b, bool isarray, int depth) {
if (luaL_getmetafield(L, -1, "__pairs") != LUA_TNIL) {
pack_meta_dict(L, b, isarray, depth);
} else {
pack_simple_dict(L, b, isarray, depth);
}
}
static void
pack_ordered_dict(lua_State *L, struct bson *b, int n, int depth) {
int length = reserve_length(b);
int i;
for (i=0;i<n;i+=2) {
@@ -456,7 +509,7 @@ pack_ordered_dict(lua_State *L, struct bson *b, int n) {
luaL_error(L, "Argument %d need a string", i+1);
}
lua_pushvalue(L, i+2);
append_one(b, L, key, sz);
append_one(b, L, key, sz, depth);
lua_pop(L,1);
}
write_byte(b,0);
@@ -490,6 +543,7 @@ make_object(lua_State *L, int type, const void * ptr, size_t len) {
static void
unpack_dict(lua_State *L, struct bson_reader *br, bool array) {
luaL_checkstack(L, 16, NULL); // reserve enough stack space to unpack table
int sz = read_int32(L, br);
const void * bytes = read_bytes(L, br, sz-5);
struct bson_reader t = { bytes, sz-5 };
@@ -841,7 +895,7 @@ lencode(lua_State *L) {
bson_create(&b);
lua_settop(L,1);
luaL_checktype(L, 1, LUA_TTABLE);
pack_dict(L, &b, false);
pack_dict(L, &b, false, 0);
void * ud = lua_newuserdata(L, b.size);
memcpy(ud, b.ptr, b.size);
bson_destroy(&b);
@@ -857,7 +911,7 @@ lencode_order(lua_State *L) {
if (n%2 != 0) {
return luaL_error(L, "Invalid ordered dict");
}
pack_ordered_dict(L, &b, n);
pack_ordered_dict(L, &b, n, 0);
lua_settop(L,1);
void * ud = lua_newuserdata(L, b.size);
memcpy(ud, b.ptr, b.size);
@@ -1136,7 +1190,7 @@ lobjectid(lua_State *L) {
} else {
time_t ti = time(NULL);
// 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[3] = (ti>>16) & 0xff;

View File

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

View File

@@ -1,6 +1,7 @@
#include <lua.h>
#include <lauxlib.h>
#include <string.h>
#include <assert.h>
#include "skynet.h"
@@ -15,7 +16,8 @@
uint32_t next_session
*/
#define TEMP_LENGTH 0x10007
#define TEMP_LENGTH 0x8200
#define MULTI_PART 0x8000
static void
fill_uint32(uint8_t * buf, uint32_t n) {
@@ -26,30 +28,75 @@ fill_uint32(uint8_t * buf, uint32_t n) {
}
static void
fill_header(lua_State *L, uint8_t *buf, int sz, void *msg) {
if (sz >= 0x10000) {
skynet_free(msg);
luaL_error(L, "request message is too long %d", sz);
}
fill_header(lua_State *L, uint8_t *buf, int sz) {
assert(sz < 0x10000);
buf[0] = (sz >> 8) & 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);
uint8_t buf[TEMP_LENGTH];
fill_header(L, buf, sz+9, msg);
buf[2] = 0;
fill_uint32(buf+3, addr);
fill_uint32(buf+7, (uint32_t)session);
memcpy(buf+11,msg,sz);
if (sz < MULTI_PART) {
fill_header(L, buf, sz+9);
buf[2] = 0;
fill_uint32(buf+3, addr);
fill_uint32(buf+7, (uint32_t)session);
memcpy(buf+11,msg,sz);
lua_pushlstring(L, (const char *)buf, sz+11);
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
packreq_string(lua_State *L, int session, void * msg, size_t sz) {
static int
packreq_string(lua_State *L, int session, void * msg, uint32_t sz) {
size_t namelen = 0;
const char *name = lua_tolstring(L, 1, &namelen);
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];
fill_header(L, buf, sz+5+namelen, msg);
buf[2] = (uint8_t)namelen;
memcpy(buf+3, name, namelen);
fill_uint32(buf+3+namelen, (uint32_t)session);
memcpy(buf+7+namelen,msg,sz);
if (sz < MULTI_PART) {
fill_header(L, buf, sz+6+namelen);
buf[2] = 0x80;
buf[3] = (uint8_t)namelen;
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
@@ -73,23 +160,33 @@ lpackrequest(lua_State *L) {
if (msg == NULL) {
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);
if (session <= 0) {
skynet_free(msg);
return luaL_error(L, "Invalid request session %d", session);
}
int addr_type = lua_type(L,1);
int multipak;
if (addr_type == LUA_TNUMBER) {
packreq_number(L, session, msg, sz);
multipak = packreq_number(L, session, msg, sz);
} else {
packreq_string(L, session, msg, sz);
multipak = packreq_string(L, session, msg, sz);
}
int current_session = session;
if (++session < 0) {
session = 1;
}
skynet_free(msg);
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
int session
string msg
boolean padding
*/
static inline uint32_t
@@ -106,44 +204,122 @@ unpack_uint32(const uint8_t * buf) {
}
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) {
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 session = unpack_uint32(buf+5);
lua_pushinteger(L, (uint32_t)address);
lua_pushinteger(L, (uint32_t)session);
lua_pushinteger(L, address);
lua_pushinteger(L, session);
lua_pushlstring(L, (const char *)buf+9, sz-9);
return 3;
}
static int
unpackreq_string(lua_State *L, const uint8_t * buf, size_t sz) {
size_t namesz = buf[0];
if (sz < namesz + 5) {
return luaL_error(L, "Invalid cluster message");
unpackmreq_number(lua_State *L, const uint8_t * buf, int sz) {
if (sz != 13) {
return luaL_error(L, "Invalid cluster message size %d (multi req must be 13)", sz);
}
lua_pushlstring(L, (const char *)buf+1, namesz);
uint32_t session = unpack_uint32(buf + namesz + 1);
uint32_t address = unpack_uint32(buf+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_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;
}
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
lunpackrequest(lua_State *L) {
size_t sz;
const char *msg = luaL_checklstring(L,1,&sz);
if (msg[0] == 0) {
size_t ssz;
const char *msg = luaL_checklstring(L,1,&ssz);
int sz = (int)ssz;
switch (msg[0]) {
case 0:
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);
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
boolean ok
@@ -162,16 +338,56 @@ lpackresponse(lua_State *L) {
if (lua_type(L,3) == LUA_TSTRING) {
msg = (void *)lua_tolstring(L, 3, &sz);
if (sz > 0x1000) {
sz = 0x1000;
}
} else {
msg = lua_touserdata(L,3);
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];
fill_header(L, buf, sz+5, msg);
fill_header(L, buf, sz+5);
fill_uint32(buf+2, session);
buf[6] = ok;
memcpy(buf+7,msg,sz);
@@ -186,6 +402,7 @@ lpackresponse(lua_State *L) {
return integer session
boolean ok
string msg
boolean padding
*/
static int
lunpackresponse(lua_State *L) {
@@ -196,10 +413,66 @@ lunpackresponse(lua_State *L) {
}
uint32_t session = unpack_uint32((const uint8_t *)buf);
lua_pushinteger(L, (lua_Integer)session);
lua_pushboolean(L, buf[4]);
lua_pushlstring(L, buf+5, sz-5);
switch(buf[4]) {
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
@@ -209,6 +482,7 @@ luaopen_cluster_core(lua_State *L) {
{ "unpackrequest", lunpackrequest },
{ "packresponse", lpackresponse },
{ "unpackresponse", lunpackresponse },
{ "concat", lconcat },
{ NULL, NULL },
};
luaL_checkversion(L);

View File

@@ -338,8 +338,13 @@ static int
lrandomkey(lua_State *L) {
char tmp[8];
int i;
char x = 0;
for (i=0;i<8;i++) {
tmp[i] = random() & 0xff;
x ^= tmp[i];
}
if (x==0) {
tmp[0] |= 1; // avoid 0
}
lua_pushlstring(L, tmp, 8);
return 1;
@@ -718,8 +723,11 @@ static int
ldhsecret(lua_State *L) {
uint32_t x[2], y[2];
read64(L, x, y);
uint64_t r = powmodp((uint64_t)x[0] | (uint64_t)x[1]<<32,
(uint64_t)y[0] | (uint64_t)y[1]<<32);
uint64_t xx = (uint64_t)x[0] | (uint64_t)x[1]<<32;
uint64_t yy = (uint64_t)y[0] | (uint64_t)y[1]<<32;
if (xx == 0 || yy == 0)
return luaL_error(L, "Can't be 0");
uint64_t r = powmodp(xx, yy);
push64(L, r);
@@ -739,7 +747,11 @@ ldhexchange(lua_State *L) {
xx[0] = x[0] | x[1]<<8 | x[2]<<16 | x[3]<<24;
xx[1] = x[4] | x[5]<<8 | x[6]<<16 | x[7]<<24;
uint64_t r = powmodp(5, (uint64_t)xx[0] | (uint64_t)xx[1]<<32);
uint64_t x64 = (uint64_t)xx[0] | (uint64_t)xx[1]<<32;
if (x64 == 0)
return luaL_error(L, "Can't be 0");
uint64_t r = powmodp(5, x64);
push64(L, r);
return 1;
}
@@ -873,7 +885,12 @@ int lhmac_sha1(lua_State *L);
int
luaopen_crypt(lua_State *L) {
luaL_checkversion(L);
srandom(time(NULL));
static int init = 0;
if (!init) {
// Don't need call srandom more than once.
init = 1 ;
srandom(time(NULL));
}
luaL_Reg l[] = {
{ "hashkey", lhashkey },
{ "randomkey", lrandomkey },

View File

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

View File

@@ -2,6 +2,7 @@
#include <lauxlib.h>
#include "malloc_hook.h"
#include "luashrtbl.h"
static int
ltotal(lua_State *L) {
@@ -33,6 +34,19 @@ ldump(lua_State *L) {
return 0;
}
static int
lexpandshrtbl(lua_State *L) {
int n = luaL_checkinteger(L, 1);
luaS_expandshr(n);
return 0;
}
static int
lcurrent(lua_State *L) {
lua_pushinteger(L, malloc_current_memory());
return 1;
}
int
luaopen_memory(lua_State *L) {
luaL_checkversion(L);
@@ -42,6 +56,10 @@ luaopen_memory(lua_State *L) {
{ "block", lblock },
{ "dumpinfo", ldumpinfo },
{ "dump", ldump },
{ "info", dump_mem_lua },
{ "ssinfo", luaS_shrinfo },
{ "ssexpand", lexpandshrtbl },
{ "current", lcurrent },
{ NULL, NULL },
};

View File

@@ -5,6 +5,8 @@
#include <stdint.h>
#include <string.h>
#include "atomic.h"
struct mc_package {
int reference;
uint32_t size;
@@ -116,7 +118,7 @@ static int
mc_closelocal(lua_State *L) {
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) {
skynet_free(pack->data);
skynet_free(pack);

View File

@@ -19,6 +19,7 @@
#define TYPE_ERROR 3
#define TYPE_OPEN 4
#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 .
@@ -48,6 +49,7 @@ struct queue {
static void
clear_list(struct uncomplete * uc) {
while (uc) {
skynet_free(uc->pack.buffer);
void * tmp = uc;
uc = uc->next;
skynet_free(tmp);
@@ -371,6 +373,11 @@ lfilter(lua_State *L) {
lua_pushinteger(L, message->id);
pushstring(L, buffer, size);
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:
// never get here
return 1;
@@ -428,7 +435,7 @@ static int
lpack(lua_State *L) {
size_t len;
const char * ptr = tolstring(L, &len, 1);
if (len > 0x10000) {
if (len >= 0x10000) {
return luaL_error(L, "Invalid size (too long) of data : %d", (int)len);
}
@@ -442,57 +449,6 @@ lpack(lua_State *L) {
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
ltostring(lua_State *L) {
void * ptr = lua_touserdata(L, 1);
@@ -500,19 +456,8 @@ ltostring(lua_State *L) {
if (ptr == NULL) {
lua_pushliteral(L, "");
} else {
if (lua_isnumber(L, 3)) {
int offset = lua_tointeger(L, 3);
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);
}
lua_pushlstring(L, (const char *)ptr, size);
skynet_free(ptr);
}
return 1;
}
@@ -523,8 +468,6 @@ luaopen_netpack(lua_State *L) {
luaL_Reg l[] = {
{ "pop", lpop },
{ "pack", lpack },
{ "pack_string", lpack_string },
{ "pack_padding", lpack_padding },
{ "clear", lclear },
{ "tostring", ltostring },
{ NULL, NULL },
@@ -537,8 +480,9 @@ luaopen_netpack(lua_State *L) {
lua_pushliteral(L, "error");
lua_pushliteral(L, "open");
lua_pushliteral(L, "close");
lua_pushliteral(L, "warning");
lua_pushcclosure(L, lfilter, 5);
lua_pushcclosure(L, lfilter, 6);
lua_setfield(L, -2, "filter");
return 1;

View File

@@ -1,3 +1,4 @@
#include <stdio.h>
#include <lua.h>
#include <lauxlib.h>
@@ -11,6 +12,8 @@
#define NANOSEC 1000000000
#define MICROSEC 1000000
// #define DEBUG_LOG
static double
get_time() {
#if !defined(__APPLE__)
@@ -47,7 +50,11 @@ diff_time(double start) {
static int
lstart(lua_State *L) {
lua_pushthread(L);
if (lua_type(L,1) == LUA_TTHREAD) {
lua_settop(L,1);
} else {
lua_pushthread(L);
}
lua_rawget(L, lua_upvalueindex(2));
if (!lua_isnil(L, -1)) {
return luaL_error(L, "Thread %p start profile more than once", lua_topointer(L, 1));
@@ -57,7 +64,11 @@ lstart(lua_State *L) {
lua_rawset(L, lua_upvalueindex(2));
lua_pushthread(L);
lua_pushnumber(L, get_time());
double ti = get_time();
#ifdef DEBUG_LOG
fprintf(stderr, "PROFILE [%p] start\n", L);
#endif
lua_pushnumber(L, ti);
lua_rawset(L, lua_upvalueindex(1));
return 0;
@@ -65,9 +76,15 @@ lstart(lua_State *L) {
static int
lstop(lua_State *L) {
lua_pushthread(L);
if (lua_type(L,1) == LUA_TTHREAD) {
lua_settop(L,1);
} else {
lua_pushthread(L);
}
lua_rawget(L, lua_upvalueindex(1));
luaL_checktype(L, -1, LUA_TNUMBER);
if (lua_type(L, -1) != LUA_TNUMBER) {
return luaL_error(L, "Call profile.start() before profile.stop()");
}
double ti = diff_time(lua_tonumber(L, -1));
lua_pushthread(L);
lua_rawget(L, lua_upvalueindex(2));
@@ -81,14 +98,20 @@ lstop(lua_State *L) {
lua_pushnil(L);
lua_rawset(L, lua_upvalueindex(2));
lua_pushnumber(L, ti + total_time);
total_time += ti;
lua_pushnumber(L, total_time);
#ifdef DEBUG_LOG
fprintf(stderr, "PROFILE [%p] stop (%lf / %lf)\n", L, ti, total_time);
#endif
return 1;
}
static int
lresume(lua_State *L) {
lua_pushvalue(L,1);
timing_resume(lua_State *L) {
#ifdef DEBUG_LOG
lua_State *from = lua_tothread(L, -1);
#endif
lua_rawget(L, lua_upvalueindex(2));
if (lua_isnil(L, -1)) { // check total time
lua_pop(L,1);
@@ -96,6 +119,9 @@ lresume(lua_State *L) {
lua_pop(L,1);
lua_pushvalue(L,1);
double ti = get_time();
#ifdef DEBUG_LOG
fprintf(stderr, "PROFILE [%p] resume\n", from);
#endif
lua_pushnumber(L, ti);
lua_rawset(L, lua_upvalueindex(1)); // set start time
}
@@ -106,8 +132,25 @@ lresume(lua_State *L) {
}
static int
lyield(lua_State *L) {
lua_pushthread(L);
lresume(lua_State *L) {
lua_pushvalue(L,1);
return timing_resume(L);
}
static int
lresume_co(lua_State *L) {
luaL_checktype(L, 2, LUA_TTHREAD);
lua_rotate(L, 2, -1);
return timing_resume(L);
}
static int
timing_yield(lua_State *L) {
#ifdef DEBUG_LOG
lua_State *from = lua_tothread(L, -1);
#endif
lua_rawget(L, lua_upvalueindex(2)); // check total time
if (lua_isnil(L, -1)) {
lua_pop(L,1);
@@ -120,7 +163,11 @@ lyield(lua_State *L) {
double starttime = lua_tonumber(L, -1);
lua_pop(L,1);
ti += diff_time(starttime);
double diff = diff_time(starttime);
ti += diff;
#ifdef DEBUG_LOG
fprintf(stderr, "PROFILE [%p] yield (%lf/%lf)\n", from, diff, ti);
#endif
lua_pushthread(L);
lua_pushnumber(L, ti);
@@ -132,6 +179,21 @@ lyield(lua_State *L) {
return co_yield(L);
}
static int
lyield(lua_State *L) {
lua_pushthread(L);
return timing_yield(L);
}
static int
lyield_co(lua_State *L) {
luaL_checktype(L, 1, LUA_TTHREAD);
lua_rotate(L, 1, -1);
return timing_yield(L);
}
int
luaopen_profile(lua_State *L) {
luaL_checkversion(L);
@@ -140,6 +202,8 @@ luaopen_profile(lua_State *L) {
{ "stop", lstop },
{ "resume", lresume },
{ "yield", lyield },
{ "resume_co", lresume_co },
{ "yield_co", lyield_co },
{ NULL, NULL },
};
luaL_newlibtable(L,l);
@@ -154,7 +218,7 @@ luaopen_profile(lua_State *L) {
lua_setmetatable(L, -3);
lua_setmetatable(L, -3);
lua_pushnil(L);
lua_pushnil(L); // cfunction (coroutine.resume or coroutine.yield)
luaL_setfuncs(L,l,3);
int libtable = lua_gettop(L);
@@ -166,20 +230,33 @@ luaopen_profile(lua_State *L) {
if (co_resume == NULL)
return luaL_error(L, "Can't get coroutine.resume");
lua_pop(L,1);
lua_getfield(L, libtable, "resume");
lua_pushcfunction(L, co_resume);
lua_setupvalue(L, -2, 3);
lua_pop(L,1);
lua_getfield(L, libtable, "resume_co");
lua_pushcfunction(L, co_resume);
lua_setupvalue(L, -2, 3);
lua_pop(L,1);
lua_getfield(L, -1, "yield");
lua_CFunction co_yield = lua_tocfunction(L, -1);
if (co_yield == NULL)
return luaL_error(L, "Can't get coroutine.yield");
lua_pop(L,1);
lua_getfield(L, libtable, "yield");
lua_pushcfunction(L, co_yield);
lua_setupvalue(L, -2, 3);
lua_pop(L,1);
lua_getfield(L, libtable, "yield_co");
lua_pushcfunction(L, co_yield);
lua_setupvalue(L, -2, 3);
lua_pop(L,1);
lua_settop(L, libtable);

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);
}
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
wb_table(lua_State *L, struct write_block *wb, int index, int depth) {
luaL_checkstack(L, LUA_MINSTACK, NULL);
if (index < 0) {
index = lua_gettop(L) + index + 1;
}
int array_size = wb_table_array(L, wb, index, depth);
wb_table_hash(L, wb, index, depth, array_size);
if (luaL_getmetafield(L, index, "__pairs") != LUA_TNIL) {
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
@@ -524,7 +551,7 @@ seri(lua_State *L, struct block *b, int len) {
}
int
_luaseri_unpack(lua_State *L) {
luaseri_unpack(lua_State *L) {
if (lua_isnoneornil(L,1)) {
return 0;
}
@@ -545,7 +572,7 @@ _luaseri_unpack(lua_State *L) {
return luaL_error(L, "deserialize null pointer");
}
lua_settop(L,0);
lua_settop(L,1);
struct read_block rb;
rball_init(&rb, buffer, len);
@@ -564,11 +591,11 @@ _luaseri_unpack(lua_State *L) {
// Need not free buffer
return lua_gettop(L);
return lua_gettop(L) - 1;
}
int
_luaseri_pack(lua_State *L) {
luaseri_pack(lua_State *L) {
struct block temp;
temp.next = NULL;
struct write_block wb;

View File

@@ -3,7 +3,7 @@
#include <lua.h>
int _luaseri_pack(lua_State *L);
int _luaseri_unpack(lua_State *L);
int luaseri_pack(lua_State *L);
int luaseri_unpack(lua_State *L);
#endif

View File

@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "atomic.h"
#define KEYTYPE_INTEGER 0
#define KEYTYPE_STRING 1
@@ -35,8 +36,6 @@ struct node {
uint8_t nocolliding; // 0 means colliding slot
};
struct table;
struct state {
int dirty;
int ref;
@@ -376,6 +375,7 @@ pconv(lua_State *L) {
static void
convert_stringmap(struct context *ctx, struct table *tbl) {
lua_State *L = ctx->L;
lua_checkstack(L, ctx->string_index + LUA_MINSTACK);
lua_settop(L, ctx->string_index + 1);
lua_pushvalue(L, 1);
struct state * s = lua_newuserdata(L, sizeof(*s));
@@ -662,7 +662,7 @@ releaseobj(lua_State *L) {
struct ctrl *c = lua_touserdata(L, 1);
struct table *tbl = c->root;
struct state *s = lua_touserdata(tbl->L, 1);
__sync_fetch_and_sub(&s->ref, 1);
ATOM_DEC(&s->ref);
c->root = NULL;
c->update = NULL;
@@ -673,7 +673,7 @@ static int
lboxconf(lua_State *L) {
struct table * tbl = get_table(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));
c->root = tbl;
@@ -718,7 +718,7 @@ static int
lincref(lua_State *L) {
struct table *tbl = get_table(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);
return 1;
@@ -728,7 +728,7 @@ static int
ldecref(lua_State *L) {
struct table *tbl = get_table(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);
return 1;

View File

@@ -81,7 +81,7 @@ forward_cb(struct skynet_context * context, void * ud, int type, int session, ui
}
static int
_callback(lua_State *L) {
lcallback(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
int forward = lua_toboolean(L, 2);
luaL_checktype(L,1,LUA_TFUNCTION);
@@ -101,7 +101,7 @@ _callback(lua_State *L) {
}
static int
_command(lua_State *L) {
lcommand(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
const char * cmd = luaL_checkstring(L,1);
const char * result;
@@ -119,7 +119,29 @@ _command(lua_State *L) {
}
static int
_genid(lua_State *L) {
lintcommand(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
lgenid(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
int session = skynet_send(context, 0, 0, PTYPE_TAG_ALLOCSESSION , 0 , NULL, 0);
lua_pushinteger(L, session);
@@ -145,11 +167,14 @@ get_dest_string(lua_State *L, int index) {
integer len
*/
static int
_send(lua_State *L) {
lsend(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
uint32_t dest = (uint32_t)lua_tointeger(L, 1);
const char * dest_string = NULL;
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);
}
@@ -199,7 +224,7 @@ _send(lua_State *L) {
}
static int
_redirect(lua_State *L) {
lredirect(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
uint32_t dest = (uint32_t)lua_tointeger(L,1);
const char * dest_string = NULL;
@@ -242,14 +267,32 @@ _redirect(lua_State *L) {
}
static int
_error(lua_State *L) {
lerror(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
skynet_error(context, "%s", luaL_checkstring(L,1));
int n = lua_gettop(L);
if (n <= 1) {
lua_settop(L, 1);
const char * s = luaL_tolstring(L, 1, NULL);
skynet_error(context, "%s", s);
return 0;
}
luaL_Buffer b;
luaL_buffinit(L, &b);
int i;
for (i=1; i<=n; i++) {
luaL_tolstring(L, i, NULL);
luaL_addvalue(&b);
if (i<n) {
luaL_addchar(&b, ' ');
}
}
luaL_pushresult(&b);
skynet_error(context, "%s", lua_tostring(L, -1));
return 0;
}
static int
_tostring(lua_State *L) {
ltostring(lua_State *L) {
if (lua_isnoneornil(L,1)) {
return 0;
}
@@ -260,7 +303,7 @@ _tostring(lua_State *L) {
}
static int
_harbor(lua_State *L) {
lharbor(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
uint32_t handle = (uint32_t)luaL_checkinteger(L,1);
int harbor = 0;
@@ -273,7 +316,7 @@ _harbor(lua_State *L) {
static int
lpackstring(lua_State *L) {
_luaseri_pack(L);
luaseri_pack(L);
char * str = (char *)lua_touserdata(L, -2);
int sz = lua_tointeger(L, -1);
lua_pushlstring(L, str, sz);
@@ -301,23 +344,32 @@ ltrash(lua_State *L) {
return 0;
}
static int
lnow(lua_State *L) {
uint64_t ti = skynet_now();
lua_pushinteger(L, ti);
return 1;
}
int
luaopen_skynet_core(lua_State *L) {
luaL_checkversion(L);
luaL_Reg l[] = {
{ "send" , _send },
{ "genid", _genid },
{ "redirect", _redirect },
{ "command" , _command },
{ "error", _error },
{ "tostring", _tostring },
{ "harbor", _harbor },
{ "pack", _luaseri_pack },
{ "unpack", _luaseri_unpack },
{ "send" , lsend },
{ "genid", lgenid },
{ "redirect", lredirect },
{ "command" , lcommand },
{ "intcommand", lintcommand },
{ "error", lerror },
{ "tostring", ltostring },
{ "harbor", lharbor },
{ "pack", luaseri_pack },
{ "unpack", luaseri_unpack },
{ "packstring", lpackstring },
{ "trash" , ltrash },
{ "callback", _callback },
{ "callback", lcallback },
{ "now", lnow },
{ NULL, NULL },
};

View File

@@ -461,6 +461,14 @@ lclose(lua_State *L) {
return 0;
}
static int
lshutdown(lua_State *L) {
int id = luaL_checkinteger(L,1);
struct skynet_context * ctx = lua_touserdata(L, lua_upvalueindex(1));
skynet_socket_shutdown(ctx, id);
return 0;
}
static int
llisten(lua_State *L) {
const char * host = luaL_checkstring(L,1);
@@ -476,18 +484,66 @@ llisten(lua_State *L) {
return 1;
}
static size_t
count_size(lua_State *L, int index) {
size_t tlen = 0;
int i;
for (i=1;lua_geti(L, index, i) != LUA_TNIL; ++i) {
size_t len;
luaL_checklstring(L, -1, &len);
tlen += len;
lua_pop(L,1);
}
lua_pop(L,1);
return tlen;
}
static void
concat_table(lua_State *L, int index, void *buffer, size_t tlen) {
char *ptr = buffer;
int i;
for (i=1;lua_geti(L, index, i) != LUA_TNIL; ++i) {
size_t len;
const char * str = lua_tolstring(L, -1, &len);
if (str == NULL || tlen < len) {
break;
}
memcpy(ptr, str, len);
ptr += len;
tlen -= len;
lua_pop(L,1);
}
if (tlen != 0) {
skynet_free(buffer);
luaL_error(L, "Invalid strings table");
}
lua_pop(L,1);
}
static void *
get_buffer(lua_State *L, int index, int *sz) {
void *buffer;
if (lua_isuserdata(L,index)) {
switch(lua_type(L, index)) {
const char * str;
size_t len;
case LUA_TUSERDATA:
case LUA_TLIGHTUSERDATA:
buffer = lua_touserdata(L,index);
*sz = luaL_checkinteger(L,index+1);
} else {
size_t len = 0;
const char * str = luaL_checklstring(L, index, &len);
break;
case LUA_TTABLE:
// concat the table as a string
len = count_size(L, index);
buffer = skynet_malloc(len);
concat_table(L, index, buffer, len);
*sz = (int)len;
break;
default:
str = luaL_checklstring(L, index, &len);
buffer = skynet_malloc(len);
memcpy(buffer, str, len);
*sz = (int)len;
break;
}
return buffer;
}
@@ -639,6 +695,7 @@ luaopen_socketdriver(lua_State *L) {
luaL_Reg l2[] = {
{ "connect", lconnect },
{ "close", lclose },
{ "shutdown", lshutdown },
{ "listen", llisten },
{ "send", lsend },
{ "lsend", lsendlow },

View File

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

View File

@@ -158,10 +158,11 @@ A schema text can be self-described by the sproto schema language.
.type {
.field {
name 0 : string
type 1 : string
id 2 : integer
array 3 : boolean
key 4 : integer # optional tag for map
buildin 1 : integer
type 2 : integer
tag 3 : integer
array 4 : boolean
key 5 : integer # If key exists, array must be true, and it's a map.
}
name 0 : string
fields 1 : *field
@@ -169,9 +170,9 @@ A schema text can be self-described by the sproto schema language.
.protocol {
name 0 : string
id 1 : integer
request 2 : string
response 3 : string
tag 1 : integer
request 2 : integer # index
response 3 : integer # index
}
.group {
@@ -209,20 +210,40 @@ Each integer number must be serialized in little-endian format.
The sproto message must be a user defined type struct, and a struct is encoded in three parts. The header, the field part, and the data part.
The tag and small integer or boolean will be encoded in field part, and others are in data part.
All the fields must be encoded in ascending order (by tag). The tags of fields can be discontinuous, if a field is nil. (default value in lua), don't encode it in message.
All the fields must be encoded in ascending order (by tag, base 0). The tags of fields can be discontinuous, if a field is nil. (default value in lua), don't encode it in message.
The header is a 16bit integer. It is the number of fields.
Each field in field part is a 16bit integer (n). If n is zero, that means the field data is encoded in data part ;
If n is even (and not zero), the value of this field is n/2-1 ;
If n is even (and not zero), the value of this field is n/2-1 , and the tag increases 1;
If n is odd, that means the tags is not continuous, and we should add current tag by (n+1)/2 .
Arrays are always encode in data part, 4 bytes header for the size, and the following bytes is the contents. See the example 2 for the struct array; example 3/4 for the integer array ; example 5 for the boolean array.
Fot integer array, an additional byte (4 or 8) to indicate the value is 32bit or 64bit.
Read the examples below to see more details.
Notice: If the tag is not declared in schema, the decoder will simply ignore the field for protocol version compatibility.
```
.Person {
name 0 : string
age 1 : integer
marital 2 : boolean
children 3 : *Person
}
.Data {
numbers 0 : *integer
bools 1 : *boolean
number 2 : integer
bignumber 3 : integer
}
```
Example 1:
```
@@ -243,7 +264,8 @@ person {
name = "Bob",
age = 40,
children = {
{ name = "Alice" , age = 13, marital = false },
{ name = "Alice" , age = 13 },
{ name = "Carol" , age = 5 },
}
}
@@ -256,13 +278,95 @@ person {
03 00 00 00 (sizeof "Bob")
42 6F 62 ("Bob")
11 00 00 00 (sizeof struct)
03 00 (fn = 3)
26 00 00 00 (sizeof children)
0F 00 00 00 (sizeof child 1)
02 00 (fn = 2)
00 00 (id = 0, value in data part)
1C 00 (id = 1, value = 13)
02 00 (id = 2, value = false)
05 00 00 00 (sizeof "Alice")
41 6C 69 63 65 ("Alice")
0F 00 00 00 (sizeof child 2)
02 00 (fn = 2)
00 00 (id = 0, value in data part)
0C 00 (id = 1, value = 5)
05 00 00 00 (sizeof "Carol")
43 61 72 6F 6C ("Carol")
```
Example 3:
```
data {
numbers = { 1,2,3,4,5 }
}
01 00 (fn = 1)
00 00 (id = 0, value in data part)
15 00 00 00 (sizeof numbers)
04 ( sizeof int32 )
01 00 00 00 (1)
02 00 00 00 (2)
03 00 00 00 (3)
04 00 00 00 (4)
05 00 00 00 (5)
```
Example 4:
```
data {
numbers = {
(1<<32)+1,
(1<<32)+2,
(1<<32)+3,
}
}
01 00 (fn = 1)
00 00 (id = 0, value in data part)
19 00 00 00 (sizeof numbers)
08 ( sizeof int64 )
01 00 00 00 01 00 00 00 ( (1<32) + 1)
02 00 00 00 01 00 00 00 ( (1<32) + 2)
03 00 00 00 01 00 00 00 ( (1<32) + 3)
```
Example 5:
```
data {
bools = { false, true, false }
}
02 00 (fn = 2)
01 00 (skip id = 0)
00 00 (id = 1, value in data part)
03 00 00 00 (sizeof bools)
00 (false)
01 (true)
00 (false)
```
Example 6:
```
data {
number = 100000,
bignumber = -10000000000,
}
03 00 (fn = 3)
03 00 (skip id = 1)
00 00 (id = 2, value in data part)
00 00 (id = 3, value in data part)
04 00 00 00 (sizeof number, data part)
A0 86 01 00 (100000, 32bit integer)
08 00 00 00 (sizeof bignumber, data part)
00 1C F4 AB FD FF FF FF (-10000000000, 64bit integer)
```
0 Packing
@@ -270,7 +374,7 @@ person {
The algorithm is very similar to [Cap'n proto](http://kentonv.github.io/capnproto/), but 0x00 is not treated specially.
In packed format, the message if padding to 8. Each 8 byte is reduced to a tag byte followed by zero to eight content bytes.
In packed format, the message is padding to 8. Each 8 byte is reduced to a tag byte followed by zero to eight content bytes.
The bits of the tag byte correspond to the bytes of the unpacked word, with the least-significant bit corresponding to the first byte.
Each zero bit indicates that the corresponding byte is zero. The non-zero bytes are packed following the tag.
@@ -281,7 +385,7 @@ unpacked (hex): 08 00 00 00 03 00 02 00 19 00 00 00 aa 01 00 00
packed (hex): 51 08 03 02 31 19 aa 01
```
Tag 0xff is treated specially. A number N is following the 0xff tag. N means (N+1)*8 bytes should be copied directly.
Tag 0xff is treated specially. A number N is following the 0xff tag. N means (N+1)\*8 bytes should be copied directly.
The bytes may or may not contain zeros. Because of this rule, the worst-case space overhead of packing is 2 bytes per 2 KiB of input.
For example:

View File

@@ -41,8 +41,18 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
#if LUA_VERSION_NUM < 503
// lua_isinteger is lua 5.3 api
#define lua_isinteger lua_isnumber
#if LUA_VERSION_NUM < 502
static lua_Integer lua_tointegerx(lua_State *L, int idx, int *isnum) {
if (lua_isnumber(L, idx)) {
if (isnum) *isnum = 1;
return lua_tointeger(L, idx);
}
else {
if (isnum) *isnum = 0;
return 0;
}
}
#endif
// work around , use push & lua_gettable may be better
#define lua_geti lua_rawgeti
@@ -87,8 +97,7 @@ lquerytype(lua_State *L) {
lua_pushlightuserdata(L, st);
return 1;
}
return luaL_error(L, "type %s not found", type_name);
return 0;
}
struct encode_ud {
@@ -117,7 +126,7 @@ encode(const struct sproto_arg *args) {
lua_replace(L, self->array_index);
}
self->array_index = 0;
return 0;
return SPROTO_CB_NOARRAY;
}
if (!lua_istable(L, -1)) {
return luaL_error(L, ".*%s(%d) should be a table (Is a %s)",
@@ -138,7 +147,7 @@ encode(const struct sproto_arg *args) {
// iterate end
lua_pushnil(L);
lua_replace(L, self->iter_index);
return 0;
return SPROTO_CB_NIL;
}
lua_insert(L, -2);
lua_replace(L, self->iter_index);
@@ -150,17 +159,17 @@ encode(const struct sproto_arg *args) {
}
if (lua_isnil(L, -1)) {
lua_pop(L,1);
return 0;
return SPROTO_CB_NIL;
}
switch (args->type) {
case SPROTO_TINTEGER: {
lua_Integer v;
lua_Integer vh;
if (!lua_isinteger(L, -1)) {
int isnum;
v = lua_tointegerx(L, -1, &isnum);
if(!isnum) {
return luaL_error(L, ".%s[%d] is not an integer (Is a %s)",
args->tagname, args->index, lua_typename(L, lua_type(L, -1)));
} else {
v = lua_tointeger(L, -1);
}
lua_pop(L,1);
// notice: in lua 5.2, lua_Integer maybe 52bit
@@ -194,10 +203,10 @@ encode(const struct sproto_arg *args) {
str = lua_tolstring(L, -1, &sz);
}
if (sz > args->length)
return -1;
return SPROTO_CB_ERROR;
memcpy(args->value, str, sz);
lua_pop(L,1);
return sz + 1; // The length of empty string is 1.
return sz;
}
case SPROTO_TSTRUCT: {
struct encode_ud sub;
@@ -217,6 +226,8 @@ encode(const struct sproto_arg *args) {
sub.iter_index = sub.tbl_index + 1;
r = sproto_encode(args->subtype, args->value, args->length, encode, &sub);
lua_settop(L, top-1); // pop the value
if (r < 0)
return SPROTO_CB_ERROR;
return r;
}
default:
@@ -300,7 +311,7 @@ decode(const struct sproto_arg *args) {
lua_State *L = self->L;
if (self->deep >= ENCODE_DEEPLEVEL)
return luaL_error(L, "The table is too deep");
if (args->index > 0) {
if (args->index != 0) {
// It's array
if (args->tagname != self->array_tag) {
self->array_tag = args->tagname;
@@ -312,6 +323,10 @@ decode(const struct sproto_arg *args) {
} else {
self->array_index = lua_gettop(L);
}
if (args->index < 0) {
// It's a empty array, return now.
return 0;
}
}
}
switch (args->type) {
@@ -346,9 +361,10 @@ decode(const struct sproto_arg *args) {
sub.key_index = lua_gettop(L);
r = sproto_decode(args->subtype, args->value, args->length, decode, &sub);
if (r < 0 || r != args->length)
if (r < 0)
return SPROTO_CB_ERROR;
if (r != args->length)
return r;
// assert(args->index > 0);
lua_pushvalue(L, sub.key_index);
if (lua_isnil(L, -1)) {
luaL_error(L, "Can't find main index (tag=%d) in [%s]", args->mainindex, args->tagname);
@@ -361,7 +377,9 @@ decode(const struct sproto_arg *args) {
sub.mainindex_tag = -1;
sub.key_index = 0;
r = sproto_decode(args->subtype, args->value, args->length, decode, &sub);
if (r < 0 || r != args->length)
if (r < 0)
return SPROTO_CB_ERROR;
if (r != args->length)
return r;
lua_settop(L, sub.result_index);
break;
@@ -460,7 +478,7 @@ lpack(lua_State *L) {
size_t sz=0;
const void * buffer = getbuffer(L, 1, &sz);
// the worst-case space overhead of packing is 2 bytes per 2 KiB of input (256 words = 2KiB).
size_t maxsz = (sz + 2047) / 2048 * 2 + sz;
size_t maxsz = (sz + 2047) / 2048 * 2 + sz + 2;
void * output = lua_touserdata(L, lua_upvalueindex(1));
int bytes;
int osz = lua_tointeger(L, lua_upvalueindex(2));
@@ -487,10 +505,10 @@ lunpack(lua_State *L) {
return luaL_error(L, "Invalid unpack stream");
if (r > osz) {
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);
return 1;
}
@@ -523,6 +541,9 @@ lprotocol(lua_State *L) {
lua_pushstring(L, name);
} else {
const char * name = lua_tostring(L, 2);
if (name == NULL) {
return luaL_argerror(L, 2, "Should be number or string");
}
tag = sproto_prototag(sp, name);
if (tag < 0)
return 0;
@@ -583,6 +604,8 @@ encode_default(const struct sproto_arg *args) {
lua_pushstring(L, args->tagname);
if (args->index > 0) {
lua_newtable(L);
lua_rawset(L, -3);
return SPROTO_CB_NOARRAY;
} else {
switch(args->type) {
case SPROTO_TINTEGER:
@@ -600,9 +623,9 @@ encode_default(const struct sproto_arg *args) {
lua_setfield(L, -2, "__type");
break;
}
lua_rawset(L, -3);
return SPROTO_CB_NIL;
}
lua_rawset(L, -3);
return 0;
}
/*

View File

@@ -83,7 +83,7 @@ static void *
pool_alloc(struct pool *p, size_t sz) {
// align by 8
sz = (sz + 7) & ~7;
if (sz > CHUNK_SIZE) {
if (sz >= CHUNK_SIZE) {
return pool_newchunk(p, sz);
}
if (p->current == NULL) {
@@ -97,7 +97,7 @@ pool_alloc(struct pool *p, size_t sz) {
return ret;
}
if (sz > p->current_used) {
if (sz >= p->current_used) {
return pool_newchunk(p, sz);
} else {
void * ret = pool_newchunk(p, CHUNK_SIZE);
@@ -152,7 +152,7 @@ struct_field(const uint8_t * stream, size_t sz) {
sz -= header;
stream += header;
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;
if (value != 0)
continue;
@@ -305,7 +305,7 @@ import_type(struct sproto *s, struct sproto_type *t, const uint8_t * stream) {
if (stream == NULL)
return NULL;
tag = f->tag;
if (tag < last)
if (tag <= last)
return NULL; // tag must in ascending order
if (tag > last+1) {
++maxn;
@@ -394,7 +394,7 @@ create_from_bundle(struct sproto *s, const uint8_t * stream, size_t sz) {
const uint8_t * protocoldata = NULL;
int fn = struct_field(stream, sz);
int i;
if (fn < 0)
if (fn < 0 || fn > 2)
return NULL;
stream += SIZEOF_HEADER;
@@ -677,11 +677,12 @@ encode_object(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int si
args->value = data+SIZEOF_LENGTH;
args->length = size-SIZEOF_LENGTH;
sz = cb(args);
if (sz <= 0)
return sz;
if (args->type == SPROTO_TSTRING) {
--sz; // the length of null string is 1
if (sz < 0) {
if (sz == SPROTO_CB_NIL)
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
assert(sz <= size-SIZEOF_LENGTH); // verify buffer overflow
return fill_size(data, sz);
}
@@ -701,7 +702,7 @@ uint32_to_uint64(int negative, uint8_t *buffer) {
}
static uint8_t *
encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffer, int size) {
encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffer, int size, int *noarray) {
uint8_t * header = buffer;
int intlen;
int index;
@@ -711,6 +712,8 @@ encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffe
size--;
intlen = sizeof(uint32_t);
index = 1;
*noarray = 0;
for (;;) {
int sz;
union {
@@ -721,10 +724,15 @@ encode_integer_array(sproto_callback cb, struct sproto_arg *args, uint8_t *buffe
args->length = sizeof(u);
args->index = index;
sz = cb(args);
if (sz < 0)
return NULL;
if (sz == 0) // nil object, end of array
break;
if (sz <= 0) {
if (sz == SPROTO_CB_NIL) // nil object, end of array
break;
if (sz == SPROTO_CB_NOARRAY) { // no array, don't encode it
*noarray = 1;
break;
}
return NULL; // sz == SPROTO_CB_ERROR
}
if (size < sizeof(uint64_t))
return NULL;
if (sz == sizeof(uint32_t)) {
@@ -789,11 +797,17 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
size -= SIZEOF_LENGTH;
buffer = data + SIZEOF_LENGTH;
switch (args->type) {
case SPROTO_TINTEGER:
buffer = encode_integer_array(cb,args,buffer,size);
case SPROTO_TINTEGER: {
int noarray;
buffer = encode_integer_array(cb,args,buffer,size, &noarray);
if (buffer == NULL)
return -1;
if (noarray) {
return 0;
}
break;
}
case SPROTO_TBOOLEAN:
args->index = 1;
for (;;) {
@@ -801,10 +815,13 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
args->value = &v;
args->length = sizeof(v);
sz = cb(args);
if (sz < 0)
return -1;
if (sz == 0) // nil object , end of array
break;
if (sz < 0) {
if (sz == SPROTO_CB_NIL) // nil object , end of array
break;
if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
if (size < 1)
return -1;
buffer[0] = v ? 1: 0;
@@ -822,12 +839,13 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
args->value = buffer+SIZEOF_LENGTH;
args->length = size;
sz = cb(args);
if (sz == 0)
break;
if (sz < 0)
return -1;
if (args->type == SPROTO_TSTRING) {
--sz;
if (sz < 0) {
if (sz == SPROTO_CB_NIL) {
break;
}
if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
fill_size(buffer, sz);
buffer += SIZEOF_LENGTH+sz;
@@ -837,8 +855,6 @@ encode_array(sproto_callback cb, struct sproto_arg *args, uint8_t *data, int siz
break;
}
sz = buffer - (data + SIZEOF_LENGTH);
if (sz == 0) // empty array
return 0;
return fill_size(data, sz);
}
@@ -884,10 +900,13 @@ sproto_encode(const struct sproto_type *st, void * buffer, int size, sproto_call
args.value = &u;
args.length = sizeof(u);
sz = cb(&args);
if (sz < 0)
return -1;
if (sz == 0) // nil object
continue;
if (sz < 0) {
if (sz == SPROTO_CB_NIL)
continue;
if (sz == SPROTO_CB_NOARRAY) // no array, don't encode it
return 0;
return -1; // sz == SPROTO_CB_ERROR
}
if (sz == sizeof(uint32_t)) {
if (u.u32 < 0x7fff) {
value = (u.u32+1) * 2;
@@ -984,13 +1003,18 @@ decode_array(sproto_callback cb, struct sproto_arg *args, uint8_t * stream) {
uint32_t sz = todword(stream);
int type = args->type;
int i;
if (sz == 0) {
// It's empty array, call cb with index == -1 to create the empty array.
args->index = -1;
args->value = NULL;
args->length = 0;
cb(args);
return 0;
}
stream += SIZEOF_LENGTH;
switch (type) {
case SPROTO_TINTEGER: {
int len;
if (sz < 1)
return -1;
len = *stream;
int len = *stream;
++stream;
--sz;
if (len == sizeof(uint32_t)) {

View File

@@ -14,6 +14,10 @@ struct sproto_type;
#define SPROTO_TSTRING 2
#define SPROTO_TSTRUCT 3
#define SPROTO_CB_ERROR -1
#define SPROTO_CB_NIL -2
#define SPROTO_CB_NOARRAY -3
struct sproto * sproto_create(const void * proto, size_t sz);
void sproto_release(struct sproto *);

View File

@@ -33,6 +33,16 @@ function cluster.snax(node, name, address)
return snax.bind(handle, name)
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()
clusterd = skynet.uniqueservice("clusterd")
end)

View File

@@ -71,6 +71,7 @@ local MAX_DOMAIN_LEN = 1024
local MAX_LABEL_LEN = 63
local MAX_PACKET_LEN = 2048
local DNS_HEADER_LEN = 12
local TIMEOUT = 30 * 100 -- 30 seconds
local QTYPE = {
A = 1,
@@ -82,8 +83,18 @@ local QCLASS = {
IN = 1,
}
local weak = {__mode = "kv"}
local CACHE = {}
local dns = {}
function dns.flush()
CACHE[QTYPE.A] = setmetatable({},weak)
CACHE[QTYPE.AAAA] = setmetatable({},weak)
end
dns.flush()
local function verify_domain_name(name)
if #name > MAX_DOMAIN_LEN then
return false
@@ -206,33 +217,51 @@ local function resolve(content)
-- verify answer
assert(answer_header.qdcount == 1, "malformed packet")
local resp = request_pool[answer_header.tid]
if not resp then
skynet.error("Recv an invalid tid when dns query")
return
end
local question,left = unpack_question(content, left)
if question.name ~= resp.name then
skynet.error("Recv an invalid name when dns query")
return
end
local ttl
local answer
local answers = {}
local answers_ipv4
local answers_ipv6
for i=1, answer_header.ancount do
answer, left = unpack_answer(content, left)
-- only extract qtype address
if answer.atype == resp.qtype then
local ip = unpack_rdata(resp.qtype, answer.rdata)
local answers
if answer.atype == QTYPE.A then
answers_ipv4 = answers_ipv4 or {}
answers = answers_ipv4
elseif answer.atype == QTYPE.AAAA then
answers_ipv6 = answers_ipv6 or {}
answers = answers_ipv6
end
if answers then
local ip = unpack_rdata(answer.atype, answer.rdata)
ttl = ttl and math.min(ttl, answer.ttl) or answer.ttl
answers[#answers+1] = ip
end
end
if #answers > 0 then
resp.answers = answers
if answers_ipv4 then
CACHE[QTYPE.A][question.name] = { answers = answers_ipv4, ttl = skynet.now() + ttl * 100 }
end
if answers_ipv6 then
CACHE[QTYPE.AAAA][question.name] = { answers = answers_ipv6, ttl = skynet.now() + ttl * 100 }
end
local resp = request_pool[answer_header.tid]
if not resp then
-- the resp may be timeout
return
end
if question.name ~= resp.name then
skynet.error("Recv an invalid name when dns query")
end
local r = CACHE[resp.qtype][resp.name]
if r then
resp.answers = r.answers
end
skynet.wakeup(resp.co)
@@ -247,6 +276,7 @@ function dns.server(server, port)
break
end
end
f:close()
assert(server, "Can't get nameserver")
end
dns_server = socket.udp(function(str, from)
@@ -256,26 +286,54 @@ function dns.server(server, port)
return server
end
local function lookup_cache(name, qtype, ignorettl)
local result = CACHE[qtype][name]
if result then
if ignorettl or (result.ttl > skynet.now()) then
return result.answers
end
end
end
local function suspend(tid, name, qtype)
local req = {
name = name,
tid = tid,
qtype = qtype,
time = skynet.now(), -- for timeout
co = coroutine.running(),
}
request_pool[tid] = req
skynet.wait()
local answers = request_pool[tid].answers
skynet.fork(function()
skynet.sleep(TIMEOUT)
local req = request_pool[tid]
if req then
-- cancel tid
skynet.error(string.format("DNS query %s timeout", name))
request_pool[tid] = nil
skynet.wakeup(req.co)
end
end)
skynet.wait(req.co)
local answers = req.answers
request_pool[tid] = nil
assert(answers, "no ip")
return answers[1], answers
if not req.answers then
local answers = lookup_cache(name, qtype, true)
if answers then
return answers[1], answers
end
error "timeout or no answer"
end
return req.answers[1], req.answers
end
function dns.resolve(name, ipv6)
local qtype = ipv6 and QTYPE.AAAA or QTYPE.A
local name = name:lower()
assert(verify_domain_name(name) , "illegal name")
local answers = lookup_cache(name, qtype)
if answers then
return answers[1], answers
end
local question_header = {
tid = gen_tid(),
flags = 0x100, -- flags: 00000001 00000000, set RD

Some files were not shown because too many files have changed in this diff Show More