diff options
| -rw-r--r-- | liolib.c | 68 | ||||
| -rw-r--r-- | loslib.c | 3 |
2 files changed, 65 insertions, 6 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: liolib.c,v 2.155 2018/02/21 13:48:44 roberto Exp roberto $ | 2 | ** $Id: liolib.c $ |
| 3 | ** Standard I/O (and system) library | 3 | ** Standard I/O (and system) library |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -68,7 +68,7 @@ static int l_checkmode (const char *mode) { | |||
| 68 | 68 | ||
| 69 | /* ISO C definitions */ | 69 | /* ISO C definitions */ |
| 70 | #define l_popen(L,c,m) \ | 70 | #define l_popen(L,c,m) \ |
| 71 | ((void)((void)c, m), \ | 71 | ((void)c, (void)m, \ |
| 72 | luaL_error(L, "'popen' not supported"), \ | 72 | luaL_error(L, "'popen' not supported"), \ |
| 73 | (FILE*)0) | 73 | (FILE*)0) |
| 74 | #define l_pclose(L,file) ((void)L, (void)file, -1) | 74 | #define l_pclose(L,file) ((void)L, (void)file, -1) |
| @@ -133,6 +133,51 @@ static int l_checkmode (const char *mode) { | |||
| 133 | /* }====================================================== */ | 133 | /* }====================================================== */ |
| 134 | 134 | ||
| 135 | 135 | ||
| 136 | /* | ||
| 137 | ** {====================================================== | ||
| 138 | ** 'resourcetryagain' | ||
| 139 | ** This function uses 'errno' to check whether the last error was | ||
| 140 | ** related to lack of resources (e.g., not enough memory or too many | ||
| 141 | ** open files). If so, the function performs a full garbage collection | ||
| 142 | ** to try to release resources, and then it returns 1 to signal to | ||
| 143 | ** the caller that it is worth trying again the failed operation. | ||
| 144 | ** Otherwise, it returns 0. Because error codes are not ANSI C, the | ||
| 145 | ** code must handle any combination of error codes that are defined. | ||
| 146 | ** ======================================================= | ||
| 147 | */ | ||
| 148 | |||
| 149 | static int resourcetryagain (lua_State *L) { | ||
| 150 | |||
| 151 | /* these are the resource-related errors in Linux */ | ||
| 152 | #if defined(EMFILE) || defined(ENFILE) || defined(ENOMEM) | ||
| 153 | |||
| 154 | #if !defined(EMFILE) /* too many open files in the process */ | ||
| 155 | #define EMFILE -1 /* if not defined, use an impossible value */ | ||
| 156 | #endif | ||
| 157 | |||
| 158 | #if !defined(ENFILE) /* too many open files in the system */ | ||
| 159 | #define ENFILE -1 | ||
| 160 | #endif | ||
| 161 | |||
| 162 | #if !defined(ENOMEM) /* not enough memory */ | ||
| 163 | #define ENOMEM -1 | ||
| 164 | #endif | ||
| 165 | |||
| 166 | if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) { | ||
| 167 | lua_gc(L, LUA_GCCOLLECT); /* try to release resources with a full GC */ | ||
| 168 | return 1; /* signal to try again the creation */ | ||
| 169 | } | ||
| 170 | |||
| 171 | #endif | ||
| 172 | |||
| 173 | return 0; /* else, asume errors are not due to lack of resources */ | ||
| 174 | |||
| 175 | } | ||
| 176 | |||
| 177 | /* }====================================================== */ | ||
| 178 | |||
| 179 | |||
| 180 | |||
| 136 | #define IO_PREFIX "_IO_" | 181 | #define IO_PREFIX "_IO_" |
| 137 | #define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) | 182 | #define IOPREF_LEN (sizeof(IO_PREFIX)/sizeof(char) - 1) |
| 138 | #define IO_INPUT (IO_PREFIX "input") | 183 | #define IO_INPUT (IO_PREFIX "input") |
| @@ -245,9 +290,22 @@ static LStream *newfile (lua_State *L) { | |||
| 245 | } | 290 | } |
| 246 | 291 | ||
| 247 | 292 | ||
| 293 | /* | ||
| 294 | ** Equivalent to 'fopen', but if it fails due to a lack of resources | ||
| 295 | ** (see 'resourcetryagain'), do an "emergency" garbage collection to try | ||
| 296 | ** to close some files and then tries to open the file again. | ||
| 297 | */ | ||
| 298 | static FILE *trytoopen (lua_State *L, const char *path, const char *mode) { | ||
| 299 | FILE *f = fopen(path, mode); | ||
| 300 | if (f == NULL && resourcetryagain(L)) /* resource failure? */ | ||
| 301 | f = fopen(path, mode); /* try to open again */ | ||
| 302 | return f; | ||
| 303 | } | ||
| 304 | |||
| 305 | |||
| 248 | static void opencheck (lua_State *L, const char *fname, const char *mode) { | 306 | static void opencheck (lua_State *L, const char *fname, const char *mode) { |
| 249 | LStream *p = newfile(L); | 307 | LStream *p = newfile(L); |
| 250 | p->f = fopen(fname, mode); | 308 | p->f = trytoopen(L, fname, mode); |
| 251 | if (p->f == NULL) | 309 | if (p->f == NULL) |
| 252 | luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); | 310 | luaL_error(L, "cannot open file '%s' (%s)", fname, strerror(errno)); |
| 253 | } | 311 | } |
| @@ -259,7 +317,7 @@ static int io_open (lua_State *L) { | |||
| 259 | LStream *p = newfile(L); | 317 | LStream *p = newfile(L); |
| 260 | const char *md = mode; /* to traverse/check mode */ | 318 | const char *md = mode; /* to traverse/check mode */ |
| 261 | luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); | 319 | luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); |
| 262 | p->f = fopen(filename, mode); | 320 | p->f = trytoopen(L, filename, mode); |
| 263 | return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; | 321 | return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; |
| 264 | } | 322 | } |
| 265 | 323 | ||
| @@ -278,6 +336,8 @@ static int io_popen (lua_State *L) { | |||
| 278 | const char *mode = luaL_optstring(L, 2, "r"); | 336 | const char *mode = luaL_optstring(L, 2, "r"); |
| 279 | LStream *p = newprefile(L); | 337 | LStream *p = newprefile(L); |
| 280 | p->f = l_popen(L, filename, mode); | 338 | p->f = l_popen(L, filename, mode); |
| 339 | if (p->f == NULL && resourcetryagain(L)) /* resource failure? */ | ||
| 340 | p->f = l_popen(L, filename, mode); /* try to open again */ | ||
| 281 | p->closef = &io_pclose; | 341 | p->closef = &io_pclose; |
| 282 | return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; | 342 | return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; |
| 283 | } | 343 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: loslib.c,v 1.65 2016/07/18 17:58:58 roberto Exp roberto $ | 2 | ** $Id: loslib.c $ |
| 3 | ** Standard Operating System library | 3 | ** Standard Operating System library |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -10,7 +10,6 @@ | |||
| 10 | #include "lprefix.h" | 10 | #include "lprefix.h" |
| 11 | 11 | ||
| 12 | 12 | ||
| 13 | #include <errno.h> | ||
| 14 | #include <locale.h> | 13 | #include <locale.h> |
| 15 | #include <stdlib.h> | 14 | #include <stdlib.h> |
| 16 | #include <string.h> | 15 | #include <string.h> |
