Changed buffer-per-socket to buffer-per-operation.

This is a difficult tradeoff to measure. I think large
datagrams won't be used very frequently. So it is better to
not lock a large buffer to each socket object and instead
allocate and deallocate for each operation receiving a
datagram larger than UDP_DATAGRAMSIZE.
This commit is contained in:
Diego Nehab 2015-10-06 11:33:50 +08:00
parent fd729b32a8
commit be67f63f4e
7 changed files with 64 additions and 62 deletions

View File

@ -147,6 +147,7 @@ Support, Manual">
<a href="socket.html#connect">connect</a>,
<a href="socket.html#connect">connect4</a>,
<a href="socket.html#connect">connect6</a>,
<a href="socket.html#datagramsize">_DATAGRAMSIZE</a>,
<a href="socket.html#debug">_DEBUG</a>,
<a href="dns.html#dns">dns</a>,
<a href="socket.html#gettime">gettime</a>,
@ -158,6 +159,7 @@ Support, Manual">
<a href="socket.html#skip">skip</a>,
<a href="socket.html#sleep">sleep</a>,
<a href="socket.html#setsize">_SETSIZE</a>,
<a href="socket.html#socketinvalid">_SOCKETINVALID</a>,
<a href="socket.html#source">source</a>,
<a href="tcp.html#socket.tcp">tcp</a>,
<a href="tcp.html#socket.tcp4">tcp4</a>,

View File

@ -99,6 +99,19 @@ This constant is set to <tt><b>true</b></tt> if the library was compiled
with debug support.
</p>
<!-- datagramsize +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=debug>
socket.<b>_DATAGRAMSIZE</b>
</p>
<p class=description>
Default datagram size used by calls to
<a href="udp.html#receive"<tt>receive</tt></a> and
<a href="udp.html#receivefrom"><tt>receivefrom</tt></a>.
(Unless changed in compile time, the value is 8192.)
</p>
<!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gettime>
@ -393,6 +406,16 @@ The maximum number of sockets that the <a
href=#select><tt>select</tt></a> function can handle.
</p>
<!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=socketinvalid>
socket.<b>_SOCKETINVALID</b>
</p>
<p class=description>
The OS value for an invalid socket.
</p>
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=try>

View File

@ -42,7 +42,7 @@
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp">
socket.<b>udp(</b>[buffersize]<b>)</b>
socket.<b>udp()</b>
</p>
<p class="description">
@ -62,13 +62,6 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object.
</p>
<p class="parameters">
The optional <tt>buffersize</tt> parameter
specifies the size of the largest datagram that will
ever be received by the UDP object. The default value is
8192.
</p>
<p class="return">
In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
@ -92,7 +85,7 @@ href=#setoption><tt>setoption</tt></a> will fail.
<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp">
socket.<b>udp4(</b>[buffersize]<b>)</b>
socket.<b>udp4()</b>
</p>
<p class="description">
@ -112,13 +105,6 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object.
</p>
<p class="parameters">
The optional <tt>buffersize</tt> parameter
specifies the size of the largest datagram that will
ever be received by the UDP object. The default value is
8192.
</p>
<p class="return">
In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
@ -128,7 +114,7 @@ an error message.
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp6">
socket.<b>udp6(</b>[buffersize]<b>)</b>
socket.<b>udp6()</b>
</p>
<p class="description">
@ -148,13 +134,6 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object.
</p>
<p class="parameters">
The optional <tt>buffersize</tt> parameter
specifies the size of the largest datagram that will
ever be received by the UDP object. The default value is
8192.
</p>
<p class="return">
In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
@ -261,8 +240,10 @@ the excess bytes are discarded. If there are less then
<tt>size</tt> bytes available in the current datagram, the
available bytes are returned.
If <tt>size</tt> is omitted, the
<tt>buffersize</tt> argument at creation time is used
(which defaults to 8192 bytes).
compile-time constant <a
href=socket.html#datagramsize><tt>socket._DATAGRAMSIZE</tt></a> is used
(it defaults to 8192 bytes). Larger sizes will cause a
temporary buffer to be allocated for the operation.
</p>
<p class="return">

View File

@ -39,7 +39,10 @@ static luaL_Reg func[] = {
\*-------------------------------------------------------------------------*/
int select_open(lua_State *L) {
lua_pushstring(L, "_SETSIZE");
lua_pushnumber(L, FD_SETSIZE);
lua_pushinteger(L, FD_SETSIZE);
lua_rawset(L, -3);
lua_pushstring(L, "_SOCKETINVALID");
lua_pushinteger(L, SOCKET_INVALID);
lua_rawset(L, -3);
luaL_setfuncs(L, func, 0);
return 0;

View File

@ -41,7 +41,6 @@ static int meth_setpeername(lua_State *L);
static int meth_close(lua_State *L);
static int meth_setoption(lua_State *L);
static int meth_getoption(lua_State *L);
static int meth_getbufferlength(lua_State *L);
static int meth_settimeout(lua_State *L);
static int meth_getfd(lua_State *L);
static int meth_setfd(lua_State *L);
@ -64,7 +63,6 @@ static luaL_Reg udp_methods[] = {
{"setfd", meth_setfd},
{"setoption", meth_setoption},
{"getoption", meth_getoption},
{"getoption", meth_getbufferlength},
{"setpeername", meth_setpeername},
{"setsockname", meth_setsockname},
{"settimeout", meth_settimeout},
@ -118,8 +116,7 @@ static luaL_Reg func[] = {
/*-------------------------------------------------------------------------*\
* Initializes module
\*-------------------------------------------------------------------------*/
int udp_open(lua_State *L)
{
int udp_open(lua_State *L) {
/* create classes */
auxiliar_newclass(L, "udp{connected}", udp_methods);
auxiliar_newclass(L, "udp{unconnected}", udp_methods);
@ -130,6 +127,10 @@ int udp_open(lua_State *L)
auxiliar_add2group(L, "udp{unconnected}", "select{able}");
/* define library functions */
luaL_setfuncs(L, func, 0);
/* export default UDP size */
lua_pushliteral(L, "_DATAGRAMSIZE");
lua_pushinteger(L, UDP_DATAGRAMSIZE);
lua_rawset(L, -3);
return 0;
}
@ -205,30 +206,26 @@ static int meth_sendto(lua_State *L) {
static int meth_receive(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
char buf[UDP_DATAGRAMSIZE];
size_t len = MAX(udp->len, UDP_DATAGRAMSIZE);
char *dgram = len > sizeof(buf)? udp->buf: buf;
size_t got, wanted = (size_t) luaL_optnumber(L, 2, len);
size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
int err;
p_timeout tm = &udp->tm;
timeout_markstart(tm);
wanted = MIN(wanted, len);
if (!dgram) {
lua_pushnil(L);
lua_pushliteral(L, "out of memory");
return 2;
}
err = socket_recv(&udp->sock, dgram, wanted, &got, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err != IO_DONE && err != IO_CLOSED ) {
if (err != IO_DONE && err != IO_CLOSED) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
if (wanted > sizeof(buf)) free(dgram);
return 2;
}
lua_pushlstring(L, dgram, got);
return 1;
}
/*-------------------------------------------------------------------------*\
* Receives data from a UDP socket
\*-------------------------------------------------------------------------*/
static int meth_getbufferlength(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
lua_pushinteger(L, MAX(UDP_DATAGRAMSIZE, udp->len));
if (wanted > sizeof(buf)) free(dgram);
return 1;
}
@ -238,9 +235,8 @@ static int meth_getbufferlength(lua_State *L) {
static int meth_receivefrom(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
char buf[UDP_DATAGRAMSIZE];
size_t len = MAX(udp->len, UDP_DATAGRAMSIZE);
char *dgram = len > sizeof(buf)? udp->buf: buf;
size_t got, wanted = (size_t) luaL_optnumber(L, 2, len);
size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
char addrstr[INET6_ADDRSTRLEN];
@ -248,13 +244,18 @@ static int meth_receivefrom(lua_State *L) {
int err;
p_timeout tm = &udp->tm;
timeout_markstart(tm);
wanted = MIN(wanted, len);
if (!dgram) {
lua_pushnil(L);
lua_pushliteral(L, "out of memory");
return 2;
}
err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr,
&addr_len, tm);
/* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
if (err != IO_DONE && err != IO_CLOSED) {
lua_pushnil(L);
lua_pushstring(L, udp_strerror(err));
if (wanted > sizeof(buf)) free(dgram);
return 2;
}
err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
@ -262,19 +263,20 @@ static int meth_receivefrom(lua_State *L) {
if (err) {
lua_pushnil(L);
lua_pushstring(L, gai_strerror(err));
if (wanted > sizeof(buf)) free(dgram);
return 2;
}
lua_pushlstring(L, dgram, got);
lua_pushstring(L, addrstr);
lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10));
if (wanted > sizeof(buf)) free(dgram);
return 3;
}
/*-------------------------------------------------------------------------*\
* Returns family as string
\*-------------------------------------------------------------------------*/
static int meth_getfamily(lua_State *L)
{
static int meth_getfamily(lua_State *L) {
p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
if (udp->family == AF_INET6) {
lua_pushliteral(L, "inet6");
@ -419,19 +421,13 @@ static int meth_setsockname(lua_State *L) {
* Creates a master udp object
\*-------------------------------------------------------------------------*/
static int udp_create(lua_State *L, int family) {
p_udp udp = NULL;
/* optional length for private datagram buffer. this is useful when
* you need larger datagrams than UDP_DATAGRAMSIZE */
size_t len = (size_t) luaL_optinteger(L, 1, 0);
if (len <= UDP_DATAGRAMSIZE) len = 0;
/* allocate udp object */
udp = (p_udp) lua_newuserdata(L, sizeof(t_udp) + len - 1);
p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
auxiliar_setclass(L, "udp{unconnected}", -1);
/* if family is AF_UNSPEC, we leave the socket invalid and
* store AF_UNSPEC into family. This will allow it to later be
* replaced with an AF_INET6 or AF_INET socket upon first use. */
udp->sock = SOCKET_INVALID;
udp->len = len;
timeout_init(&udp->tm, -1, -1);
udp->family = family;
if (family != AF_UNSPEC) {

View File

@ -23,8 +23,6 @@ typedef struct t_udp_ {
t_socket sock;
t_timeout tm;
int family;
size_t len; /* length of datagram buffer below */
char buf[1]; /* allocate larger structure to hold actual buffer */
} t_udp;
typedef t_udp *p_udp;

View File

@ -669,7 +669,6 @@ local udp_methods = {
"settimeout"
}
------------------------------------------------------------------------
test_methods(socket.udp(), udp_methods)
do local sock = socket.tcp6()