Browse Source

Added "emergency collection" to 'io.tmpfile' and 'os.tmpname'

These operations also can give errors for lack of resources, so they
also will try "emergency collections" in case of resource errors.
Because there are now two libraries with that kind of handling,
'resourcetryagain' was moved to the auxiliary library to be shared
by the libraries.
pull/21/head
Roberto Ierusalimschy 6 years ago
parent
commit
3d838f635c
  1. 46
      lauxlib.c
  2. 5
      lauxlib.h
  3. 54
      liolib.c
  4. 2
      loslib.c
  5. 14
      manual/manual.of

46
lauxlib.c

@ -1,5 +1,5 @@
/*
** $Id: lauxlib.c,v 1.294 2018/02/27 18:47:32 roberto Exp roberto $
** $Id: lauxlib.c $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@ -290,6 +290,50 @@ LUALIB_API int luaL_execresult (lua_State *L, int stat) {
/* }====================================================== */
/*
** {======================================================
** 'luaL_resourcetryagain'
** This function uses 'errno' to check whether the last error was
** related to lack of resources (e.g., not enough memory or too many
** open files). If so, the function performs a full garbage collection
** to try to release resources, and then it returns 1 to signal to
** the caller that it is worth trying again the failed operation.
** Otherwise, it returns 0. Because error codes are not ANSI C, the
** code must handle any combination of error codes that are defined.
** =======================================================
*/
LUALIB_API int luaL_resourcetryagain (lua_State *L) {
/* these are the resource-related errors in Linux */
#if defined(EMFILE) || defined(ENFILE) || defined(ENOMEM)
#if !defined(EMFILE) /* too many open files in the process */
#define EMFILE -1 /* if not defined, use an impossible value */
#endif
#if !defined(ENFILE) /* too many open files in the system */
#define ENFILE -1
#endif
#if !defined(ENOMEM) /* not enough memory */
#define ENOMEM -1
#endif
if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
lua_gc(L, LUA_GCCOLLECT); /* try to release resources with a full GC */
return 1; /* signal to try again the creation */
}
#endif
return 0; /* else, asume errors are not due to lack of resources */
}
/* }====================================================== */
/*
** {======================================================
** Userdata's metatable manipulation

5
lauxlib.h

@ -1,5 +1,5 @@
/*
** $Id: lauxlib.h,v 1.133 2017/06/27 18:32:49 roberto Exp roberto $
** $Id: lauxlib.h $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
@ -77,6 +77,9 @@ 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);
LUALIB_API int (luaL_resourcetryagain) (lua_State *L);
/* predefined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)

54
liolib.c

@ -133,50 +133,6 @@ static int l_checkmode (const char *mode) {
/* }====================================================== */
/*
** {======================================================
** 'resourcetryagain'
** This function uses 'errno' to check whether the last error was
** related to lack of resources (e.g., not enough memory or too many
** open files). If so, the function performs a full garbage collection
** to try to release resources, and then it returns 1 to signal to
** the caller that it is worth trying again the failed operation.
** Otherwise, it returns 0. Because error codes are not ANSI C, the
** code must handle any combination of error codes that are defined.
** =======================================================
*/
static int resourcetryagain (lua_State *L) {
/* these are the resource-related errors in Linux */
#if defined(EMFILE) || defined(ENFILE) || defined(ENOMEM)
#if !defined(EMFILE) /* too many open files in the process */
#define EMFILE -1 /* if not defined, use an impossible value */
#endif
#if !defined(ENFILE) /* too many open files in the system */
#define ENFILE -1
#endif
#if !defined(ENOMEM) /* not enough memory */
#define ENOMEM -1
#endif
if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
lua_gc(L, LUA_GCCOLLECT); /* try to release resources with a full GC */
return 1; /* signal to try again the creation */
}
#endif
return 0; /* else, asume errors are not due to lack of resources */
}
/* }====================================================== */
#define IO_PREFIX "_IO_"
#define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1)
@ -292,12 +248,12 @@ static LStream *newfile (lua_State *L) {
/*
** Equivalent to 'fopen', but if it fails due to a lack of resources
** (see 'resourcetryagain'), do an "emergency" garbage collection to try
** to close some files and then tries to open the file again.
** (see 'luaL_resourcetryagain'), do an "emergency" garbage collection
** to try to close some files and then tries to open the file again.
*/
static FILE *trytoopen (lua_State *L, const char *path, const char *mode) {
FILE *f = fopen(path, mode);
if (f == NULL && resourcetryagain(L)) /* resource failure? */
if (f == NULL && luaL_resourcetryagain(L)) /* resource failure? */
f = fopen(path, mode); /* try to open again */
return f;
}
@ -336,7 +292,7 @@ static int io_popen (lua_State *L) {
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newprefile(L);
p->f = l_popen(L, filename, mode);
if (p->f == NULL && resourcetryagain(L)) /* resource failure? */
if (p->f == NULL && luaL_resourcetryagain(L)) /* resource failure? */
p->f = l_popen(L, filename, mode); /* try to open again */
p->closef = &io_pclose;
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
@ -346,6 +302,8 @@ static int io_popen (lua_State *L) {
static int io_tmpfile (lua_State *L) {
LStream *p = newfile(L);
p->f = tmpfile();
if (p->f == NULL && luaL_resourcetryagain(L)) /* resource failure? */
p->f = tmpfile(); /* try to open again */
return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
}

2
loslib.c

@ -166,6 +166,8 @@ static int os_tmpname (lua_State *L) {
char buff[LUA_TMPNAMBUFSIZE];
int err;
lua_tmpnam(buff, err);
if (err && luaL_resourcetryagain(L)) /* resource failure? */
lua_tmpnam(buff, err); /* try again */
if (err)
return luaL_error(L, "unable to generate a unique filename");
lua_pushstring(L, buff);

14
manual/manual.of

@ -5538,6 +5538,20 @@ Leaves a copy of the module on the stack.
}
@APIEntry{int luaL_resourcetryagain (lua_State *L);|
@apii{0,0,m}
Try to release resources in case of errors.
This function uses @id{errno} to check whether the last error was
related to lack of resources (e.g., not enough memory or too many
open files).
If so, the function performs a full garbage collection
to try to release resources, and then it returns 1 to signal to
the caller that it is worth trying again the failed operation.
Otherwise, it returns 0.
}
@APIEntry{void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);|
@apii{nup,0,m}

Loading…
Cancel
Save