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">connect</a>,
<a href="socket.html#connect">connect4</a>, <a href="socket.html#connect">connect4</a>,
<a href="socket.html#connect">connect6</a>, <a href="socket.html#connect">connect6</a>,
<a href="socket.html#datagramsize">_DATAGRAMSIZE</a>,
<a href="socket.html#debug">_DEBUG</a>, <a href="socket.html#debug">_DEBUG</a>,
<a href="dns.html#dns">dns</a>, <a href="dns.html#dns">dns</a>,
<a href="socket.html#gettime">gettime</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#skip">skip</a>,
<a href="socket.html#sleep">sleep</a>, <a href="socket.html#sleep">sleep</a>,
<a href="socket.html#setsize">_SETSIZE</a>, <a href="socket.html#setsize">_SETSIZE</a>,
<a href="socket.html#socketinvalid">_SOCKETINVALID</a>,
<a href="socket.html#source">source</a>, <a href="socket.html#source">source</a>,
<a href="tcp.html#socket.tcp">tcp</a>, <a href="tcp.html#socket.tcp">tcp</a>,
<a href="tcp.html#socket.tcp4">tcp4</a>, <a href="tcp.html#socket.tcp4">tcp4</a>,

View File

@ -90,7 +90,7 @@ of connect are defined as simple helper functions that restrict the
<!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=debug> <p class=name id=debug>
socket.<b>_DEBUG</b> socket.<b>_DEBUG</b>
</p> </p>
@ -99,6 +99,19 @@ This constant is set to <tt><b>true</b></tt> if the library was compiled
with debug support. with debug support.
</p> </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 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=gettime> <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. href=#select><tt>select</tt></a> function can handle.
</p> </p>
<!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=socketinvalid>
socket.<b>_SOCKETINVALID</b>
</p>
<p class=description>
The OS value for an invalid socket.
</p>
<!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class=name id=try> <p class=name id=try>

View File

@ -42,7 +42,7 @@
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp"> <p class="name" id="socket.udp">
socket.<b>udp(</b>[buffersize]<b>)</b> socket.<b>udp()</b>
</p> </p>
<p class="description"> <p class="description">
@ -62,13 +62,6 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object. is used to connect the object.
</p> </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"> <p class="return">
In case of success, a new unconnected UDP object In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by 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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp"> <p class="name" id="socket.udp">
socket.<b>udp4(</b>[buffersize]<b>)</b> socket.<b>udp4()</b>
</p> </p>
<p class="description"> <p class="description">
@ -112,13 +105,6 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object. is used to connect the object.
</p> </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"> <p class="return">
In case of success, a new unconnected UDP object In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
@ -128,7 +114,7 @@ an error message.
<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> <!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<p class="name" id="socket.udp6"> <p class="name" id="socket.udp6">
socket.<b>udp6(</b>[buffersize]<b>)</b> socket.<b>udp6()</b>
</p> </p>
<p class="description"> <p class="description">
@ -148,13 +134,6 @@ The <a href="#setpeername"><tt>setpeername</tt></a>
is used to connect the object. is used to connect the object.
</p> </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"> <p class="return">
In case of success, a new unconnected UDP object In case of success, a new unconnected UDP object
returned. In case of error, <b><tt>nil</tt></b> is returned, followed by 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 <tt>size</tt> bytes available in the current datagram, the
available bytes are returned. available bytes are returned.
If <tt>size</tt> is omitted, the If <tt>size</tt> is omitted, the
<tt>buffersize</tt> argument at creation time is used compile-time constant <a
(which defaults to 8192 bytes). 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>
<p class="return"> <p class="return">

View File

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

View File

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

View File

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