diff --git a/src/Makefile b/src/Makefile index a9b706f44..eb74178cb 100644 --- a/src/Makefile +++ b/src/Makefile @@ -462,6 +462,7 @@ DBGNAME?=$(EXENAME).debug OBJS:=$(i_main_o) \ $(OBJDIR)/comptime.o \ $(OBJDIR)/string.o \ + $(OBJDIR)/d_async.o \ $(OBJDIR)/d_main.o \ $(OBJDIR)/d_protocol.o \ $(OBJDIR)/d_clisrv.o \ diff --git a/src/command.c b/src/command.c index 165cbb584..ad4afb2b7 100644 --- a/src/command.c +++ b/src/command.c @@ -18,6 +18,7 @@ #include "doomdef.h" #include "doomstat.h" +#include "d_main.h" #include "command.h" #include "console.h" #include "z_zone.h" @@ -34,6 +35,8 @@ #include "p_setup.h" #include "lua_script.h" #include "d_netfil.h" // findfile +#include "d_async.h" +#include "filesrch.h" //======== // protos. @@ -121,11 +124,9 @@ void COM_BufAddText(const char *ptext) l = strlen(ptext); if (com_text.cursize + l >= com_text.maxsize) - { CONS_Alert(CONS_WARNING, M_GetText("Command buffer full!\n")); - return; - } - VS_Write(&com_text, ptext, l); + else + VS_Write(&com_text, ptext, l); } /** Adds command text and executes it immediately. @@ -752,12 +753,60 @@ static void COM_CEchoDuration_f(void) HU_SetCEchoDuration(atoi(COM_Argv(1))); } +struct COM_Exec_Ctx +{ + boolean noerror; + boolean silent; + UINT8 * buf; +}; + +static void Free_COM_Exec_Ctx (struct COM_Exec_Ctx *ctx) +{ + Z_Free(ctx->buf); + Z_Free(ctx); +} + +void COM_ExecuteFile (void *p, void *u) +{ + filequery_t * q = p; + struct COM_Exec_Ctx * ctx = u; + + ctx->buf = NULL; + + if (q->status == FS_FOUND) + { + FIL_ReadFile(q->filename, &ctx->buf); + } + + if (ctx->buf) + { + if (! ctx->silent) + CONS_Printf(M_GetText("executing %s\n"), q->filename); + + // insert text file into the command buffer + COM_BufAddText((char *)ctx->buf); + COM_BufAddText("\n"); + } + else + { + if (! ctx->noerror) + CONS_Printf(M_GetText("couldn't execute file %s\n"), q->filename); + } + + Free_COM_Exec_Ctx(ctx); +} + /** Executes a script file. */ static void COM_Exec_f(void) { - UINT8 *buf = NULL; - char filename[256]; + char filenamebuf[MAX_WADPATH]; + + struct COM_Exec_Ctx *ctx; + + const char * filename; + + filequery_t q; if (COM_Argc() < 2 || COM_Argc() > 3) { @@ -765,37 +814,39 @@ static void COM_Exec_f(void) return; } - // load file - // Try with Argv passed verbatim first, for back compat - FIL_ReadFile(COM_Argv(1), &buf); + filename = COM_Argv(1); - if (!buf) + ctx = ZZ_Alloc(sizeof *ctx); + + ctx->noerror = COM_CheckParm("-noerror"); + ctx->silent = COM_CheckParm("-silent"); + + if (COM_CheckParm("-sync")) { - // Now try by searching the file path - // filename is modified with the full found path - strcpy(filename, COM_Argv(1)); - if (findfile(filename, NULL, true) != FS_NOTFOUND) - FIL_ReadFile(filename, &buf); + q.filename = filenamebuf; - if (!buf) + strcpy(q.filename, filename); + + if (FIL_FileOK(filename)) { - if (!COM_CheckParm("-noerror")) - CONS_Printf(M_GetText("couldn't execute file %s\n"), COM_Argv(1)); - return; + q.status = FS_FOUND; } + else + { + q.status = findfile(q.filename, NULL, true); + } + + COM_ExecuteFile(&q, ctx); + } + else + { + q.filename = strcpy(ZZ_Alloc(MAX_WADPATH), filename); + Append_async_addfile(ASYNC_EXEC, q.filename, ctx); } - if (!COM_CheckParm("-silent")) - CONS_Printf(M_GetText("executing %s\n"), COM_Argv(1)); - - // insert text file into the command buffer - COM_BufAddText((char *)buf); - COM_BufAddText("\n"); - - // free buffer - Z_Free(buf); } + /** Delays execution of the rest of the commands until the next frame. * Allows sequences of commands like "jump; fire; backward". */ diff --git a/src/command.h b/src/command.h index 2276a0ae2..5a32d0241 100644 --- a/src/command.h +++ b/src/command.h @@ -59,6 +59,9 @@ void COM_ImmedExecute(const char *ptext); // Execute commands in buffer, flush them void COM_BufExecute(void); +// Execute a whole file (internal use only :v) +void COM_ExecuteFile(void *query, void *ctx); + // As above; and progress the wait timer. void COM_BufTicker(void); diff --git a/src/console.c b/src/console.c index 73eac9ff9..3e22c295d 100644 --- a/src/console.c +++ b/src/console.c @@ -1414,6 +1414,14 @@ void CONS_Printf(const char *fmt, ...) startup = con_startup; Unlock_state(); + + +#ifdef HAVE_THREADS + if (! I_on_main_thread()) + { + return; + } +#endif // if not in display loop, force screen update if (startup) diff --git a/src/d_async.c b/src/d_async.c new file mode 100644 index 000000000..67483b917 --- /dev/null +++ b/src/d_async.c @@ -0,0 +1,259 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by James R. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file d_async.c +/// \brief Add wad/exec config asynchronously to the main thread, but in order + +#include "doomdef.h" +#include "d_main.h" +#include "d_async.h" +#include "filesrch.h" +#include "i_threads.h" +#include "m_misc.h" +#include "p_setup.h" +#include "z_zone.h" + +struct filename_queue; +struct async_addfile; + +typedef struct filename_queue filename_queue_t; +typedef struct async_addfile async_addfile_t; + +struct filename_queue +{ + int type; + char * name; + void * u;/* exec command has some parameters that need know */ + filename_queue_t * next; +}; + +struct async_addfile +{ + int done; + int query_size; + int query_position; + filequery_t * query; + int * type; + void ** u; + async_addfile_t * next; +}; + +static filename_queue_t * queue_head; +static filename_queue_t * queue_tail; +static int queue_size; + +static I_mutex async_mutex; + +static async_addfile_t * async_head; +static async_addfile_t * async_tail; + +static void +Async_addfile_thread (async_addfile_t *file) +{ + findmultiplefiles(file->query_size, file->query, false, true, &async_mutex); + + I_lock_mutex(&async_mutex); + { + file->done = 1; + } + I_unlock_mutex(async_mutex); +} + +static void +Do_addfile (int type, filequery_t *q, void *ctx) +{ + switch (type) + { + case ASYNC_EXEC: + COM_ExecuteFile(q, ctx); + break; + } +} + +void +Finish_async_addfile (void) +{ + async_addfile_t * file = async_head; + async_addfile_t * next; + + filequery_t * q; + + filestatus_t status; + + int type; + int done; + + while (file != NULL) + { + while (file->query_position < file->query_size) + { + q = &file->query [file->query_position]; + type = file->type [file->query_position]; + + I_lock_mutex(&async_mutex); + { + status = q->status; + } + I_unlock_mutex(async_mutex); + + if (status == FS_NOTCHECKED) + { + break; + } + else + { + Do_addfile(type, q, file->u[file->query_position]); + } + + Z_Free(q->filename); + + file->query_position++; + } + + if (file->query_position < file->query_size) + { + break; + } + + I_lock_mutex(&async_mutex); + { + done = file->done; + } + I_unlock_mutex(async_mutex); + + if (done) + { + next = file->next; + + Z_Free(file->u); + Z_Free(file->type); + Z_Free(file->query); + Z_Free(file); + + file = next; + } + else + { + break; + } + } + + async_head = file; + + if (file == NULL) + { + async_tail = NULL; + } +} + +void +Append_async_addfile (int type, const char * filename, void * userdata) +{ + char filenamebuf[MAX_WADPATH]; + + filename_queue_t * q; + + filequery_t file; + + if (FIL_FileOK(filename)) + { + file.status = FS_FOUND; + file.filename = filenamebuf; + + strcpy(file.filename, filename); + + Do_addfile(type, &file, userdata); + } + else + { + q = ZZ_Alloc(sizeof *q); + + if (queue_tail != NULL) + { + queue_tail->next = q; + } + else + { + queue_head = q; + } + + queue_tail = q; + queue_size++; + + q->type = type; + q->name = strcpy(ZZ_Alloc(MAX_WADPATH), filename); + q->u = userdata; + q->next = NULL; + } +} + +void +Detach_async_addfile (void) +{ + filename_queue_t * q = queue_head; + filename_queue_t * next; + + async_addfile_t * file; + + filequery_t * query; + int * type; + void ** udata; + + if (q != NULL) + { + file = ZZ_Alloc(sizeof *file); + + if (async_tail != NULL) + { + async_tail->next = file; + } + else + { + async_head = file; + } + + async_tail = file; + + file->done = 0; + file->next = NULL; + + file->query_size = queue_size; + file->query_position = 0; + + file->query = ZZ_Alloc(queue_size * sizeof (*file->query)); + file->type = ZZ_Alloc(queue_size * sizeof (*file->type)); + file->u = ZZ_Alloc(queue_size * sizeof (*file->u)); + + query = file->query; + type = file->type; + udata = file->u; + + do + { + *type++ = q->type; + *udata++ = q->u; + + query->status = FS_NOTCHECKED; + query->wantedmd5sum = NULL; + query->filename = q->name; + query++; + + next = q->next; + + Z_Free(q); + } + while (( q = next ) != NULL) ; + + I_spawn_thread("async-addfile", + (I_thread_fn)Async_addfile_thread, file); + + queue_head = NULL; + queue_tail = NULL; + queue_size = 0; + } +} diff --git a/src/d_async.h b/src/d_async.h new file mode 100644 index 000000000..9c2b7e34e --- /dev/null +++ b/src/d_async.h @@ -0,0 +1,44 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2020 by James R. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file d_async.h +/// \brief Add wad/exec config asynchronously to the main thread, but in order + +#ifndef D_ASYNC_H +#define D_ASYNC_H + +enum +{ + ASYNC_ADDFILE, + ASYNC_EXEC, +}; + +/* +Queue a file to be added. Detach_async_addfile will spawn a thread that +searches for any files if necessary. +*/ + +void Append_async_addfile (int type, const char * filename, void * ctx); + +/* +Although the file searching is done on another thread, the actual adding of the +wad or executing the config must be done on the main thread. This function is +called every tic to check if a file was found so it can perform that last step. +It does this in order. +*/ + +void Finish_async_addfile (void); + +/* +Spawns a thread that searches for files that were queued. +Called at the end of each tic. +*/ + +void Detach_async_addfile (void); + +#endif/*D_ASYNC_H*/ diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 1749d9aea..3d4e3b674 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -45,6 +45,7 @@ #include "lua_script.h" #include "lua_hook.h" #include "k_kart.h" +#include "d_async.h" #include "s_sound.h" // sfx_syfail #include "m_perfstats.h" #include "d_main.h" @@ -6041,6 +6042,8 @@ boolean TryRunTics(tic_t realtics) if (singletics) realtics = 1; + + Finish_async_addfile(); if (realtics >= 1) { @@ -6118,6 +6121,8 @@ boolean TryRunTics(tic_t realtics) { hu_stopped = true; } + + Detach_async_addfile(); return ticking; } diff --git a/src/d_netfil.c b/src/d_netfil.c index a51d44f80..436926269 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -1164,13 +1164,13 @@ filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum) // Rewritten by Monster Iestyn to be less stupid // Note: if completepath is true, "filename" is modified, but only if FS_FOUND is going to be returned // (Don't worry about WinCE's version of filesearch, nobody cares about that OS anymore) -filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean completepath) +filestatus_t findmultiplefiles(int n, filequery_t *files, boolean checkmd5, boolean completepath, void *mutex_ptr) { filestatus_t homecheck; // store result of last file search boolean badmd5 = false; // store whether md5 was bad from either of the first two searches (if nothing was found in the third) // first, check SRB2's "home" directory - homecheck = filesearch(filename, srb2home, wantedmd5sum, completepath, 10); + homecheck = filesearch(n, files, srb2home, checkmd5, completepath, 10, mutex_ptr); if (homecheck == FS_FOUND) // we found the file, so return that we have :) return FS_FOUND; @@ -1179,7 +1179,7 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean complet // if not found at all, just move on without doing anything // next, check SRB2's "path" directory - homecheck = filesearch(filename, srb2path, wantedmd5sum, completepath, 10); + homecheck = filesearch(n, files, srb2path, checkmd5, completepath, 10, mutex_ptr); if (homecheck == FS_FOUND) // we found the file, so return that we have :) return FS_FOUND; @@ -1188,7 +1188,7 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean complet // if not found at all, just move on without doing anything // finally check "." directory - homecheck = filesearch(filename, ".", wantedmd5sum, completepath, 10); + homecheck = filesearch(n, files, ".", checkmd5, completepath, 10, mutex_ptr); if (homecheck != FS_NOTFOUND) // if not found this time, fall back on the below return statement return homecheck; // otherwise return the result we got @@ -1196,6 +1196,12 @@ filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean complet return (badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND); // md5 sum bad or file not found } +filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean completepath) +{ + filequery_t q = { FS_NOTFOUND, wantedmd5sum, filename }; + return findmultiplefiles(1, &q, ( wantedmd5sum != NULL ), completepath, NULL); +} + #ifdef HAVE_CURL size_t curlwrite_data(void *ptr, size_t size, size_t nmemb, FILE *stream) { diff --git a/src/filesrch.c b/src/filesrch.c index e2acdf324..09b238376 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -29,6 +29,7 @@ #include "m_misc.h" #include "z_zone.h" #include "m_menu.h" // Addons_option_Onchange +#include "i_threads.h" #if defined (_WIN32) && defined (_MSC_VER) @@ -354,17 +355,44 @@ INT32 pathisdirectory(const char *path) return 0; } -filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, boolean completepath, int maxsearchdepth) +filestatus_t filesearch(int nfiles, filequery_t *files, const char *startpath, boolean checkmd5, boolean completepath, int maxsearchdepth, void *mutex_ptr) { filestatus_t retval = FS_NOTFOUND; + const UINT8 *wantedmd5sum = NULL; DIR **dirhandle; struct dirent *dent; struct stat fsstat; - int found = 0; - char *searchname = strdup(filename); int depthleft = maxsearchdepth; char searchpath[1024]; size_t *searchpathindex; + int matched; + int files_left = 0; + int i; + +#ifdef HAVE_THREADS +#define Lock() I_lock_mutex ((I_mutex *)mutex_ptr) +#define Unlock() I_unlock_mutex (((mutex_ptr) ? *(I_mutex *)mutex_ptr : NULL)) +#else +#define Lock() ((void)0) +#define Unlock() ((void)0) +#endif + + Lock(); + + for (i = 0; i < nfiles; ++i) + { + if (files[i].status != FS_FOUND) + { + files_left++; + } + } + + Unlock(); + + if (! files_left) + { + return FS_FOUND; + } dirhandle = (DIR**) malloc(maxsearchdepth * sizeof (DIR*)); searchpathindex = (size_t *) malloc(maxsearchdepth * sizeof (size_t)); @@ -376,7 +404,6 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want if (dirhandle[depthleft] == NULL) { - free(searchname); free(dirhandle); free(searchpathindex); return FS_NOTFOUND; @@ -390,7 +417,7 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want else searchpathindex[depthleft]--; - while ((!found) && (depthleft < maxsearchdepth)) + while ((files_left) && (depthleft < maxsearchdepth)) { searchpath[searchpathindex[depthleft]]=0; dent = readdir(dirhandle[depthleft]); @@ -448,34 +475,75 @@ filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *want searchpath[searchpathindex[depthleft]-1]='/'; searchpath[searchpathindex[depthleft]]=0; } - else if (!strcasecmp(searchname, dent->d_name)) + else { - switch (checkfilemd5(searchpath, wantedmd5sum)) + for (i = 0; i < nfiles; ++i) { - case FS_FOUND: - if (completepath) - strcpy(filename,searchpath); - else - strcpy(filename,dent->d_name); - retval = FS_FOUND; - found = 1; - break; - case FS_MD5SUMBAD: - retval = FS_MD5SUMBAD; - break; - default: // prevent some compiler warnings - break; + Lock(); + + if (checkmd5) + { + wantedmd5sum = files[i].wantedmd5sum; + } + + matched = ( + files[i].status != FS_FOUND && + !strcasecmp(files[i].filename, dent->d_name) + ); + + Unlock(); + + if (matched) + { + switch (checkfilemd5(searchpath, wantedmd5sum)) + { + case FS_FOUND: + Lock(); + + if (completepath) + strcpy(files[i].filename,searchpath); + else + strcpy(files[i].filename,dent->d_name); + files[i].status = FS_FOUND; + + Unlock(); + + files_left--; + break; + case FS_MD5SUMBAD: + Lock(); + retval = files[i].status = FS_MD5SUMBAD; + Unlock(); + break; + default: // prevent some compiler warnings + break; + } + } } } } for (; depthleft < maxsearchdepth; closedir(dirhandle[depthleft++])); - free(searchname); free(searchpathindex); free(dirhandle); - return retval; + Lock(); + { + for (i = 0; i < nfiles; ++i) + { + if (files[i].status != FS_FOUND && files[i].status != FS_MD5SUMBAD) + { + files[i].status = FS_NOTFOUND; + } + } + } + Unlock(); + + return ( (files_left) ? retval : FS_FOUND ); + +#undef Lock +#undef Unlock } char exttable[NUM_EXT_TABLE][7] = { // maximum extension length (currently 4) plus 3 (null terminator, stop, and length including previous two) diff --git a/src/filesrch.h b/src/filesrch.h index b991e8b16..6d10561ae 100644 --- a/src/filesrch.h +++ b/src/filesrch.h @@ -8,25 +8,38 @@ #include "d_netfil.h" #include "m_menu.h" // MAXSTRINGLENGTH +typedef struct +{ + filestatus_t status; + const UINT8 * wantedmd5sum; + char * filename; +} +filequery_t; + extern consvar_t cv_addons_option, cv_addons_folder, cv_addons_md5, cv_addons_showall, cv_addons_search_case, cv_addons_search_type; /** \brief The filesearch function This function search files, manly WADs and return back the status of the file - \param filename the file to look for + \param nfiles number of files + \param queries the files to look for \param startpath where to start look from - \param wantedmd5sum want to check with MD5 \param completepath want to return the complete path of the file? \param maxsearchdepth the max depth to search for the file - \return filestatus_t + \return FS_FOUND if all files were found, FS_NOTFOUND or FS_MD5SUMBAD + if some files were not found */ -filestatus_t filesearch(char *filename, const char *startpath, const UINT8 *wantedmd5sum, - boolean completepath, int maxsearchdepth); +filestatus_t filesearch(int nfiles, filequery_t *queries, const char *startpath, + boolean checkmd5, boolean completepath, int maxsearchdepth, void *mutex_ptr); + +/* this is a better place for it tbh (im still too lazy to move the other) */ +filestatus_t findmultiplefiles(int nfiles, filequery_t *files, + boolean checkmd5, boolean completepath, void *mutex_ptr); #define menudepth 20 diff --git a/src/i_threads.h b/src/i_threads.h index 45a3dcc3e..2e02713a9 100644 --- a/src/i_threads.h +++ b/src/i_threads.h @@ -27,6 +27,8 @@ void I_spawn_thread (const char *name, I_thread_fn, void *userdata); /* check in your thread whether to return early */ int I_thread_is_stopped (void); +int I_on_main_thread (void); + void I_lock_mutex (I_mutex *); void I_unlock_mutex (I_mutex); diff --git a/src/m_misc.c b/src/m_misc.c index a8cc28f0b..015972672 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -504,7 +504,7 @@ void M_FirstLoadConfig(void) CV_InitFilterVar(); // load config, make sure those commands doesnt require the screen... - COM_BufInsertText(va("exec \"%s\"\n", configfile)); + COM_BufInsertText(va("exec \"%s\" -sync\n", configfile)); // no COM_BufExecute() needed; that does it right away // don't filter anymore vars and don't let this convsvar be changed diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 0e921d73b..faa7d1ab0 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -3871,10 +3871,14 @@ static void pathonly(char *s) static const char *searchWad(const char *searchDir) { static char tempsw[256] = ""; + filequery_t fsquery; filestatus_t fstemp; + + fsquery.filename = tempsw; strcpy(tempsw, WADKEYWORD1); - fstemp = filesearch(tempsw,searchDir,NULL,true,20); + fsquery.status = FS_NOTFOUND; + fstemp = filesearch(1,&fsquery,searchDir,false,true,20,NULL); if (fstemp == FS_FOUND) { pathonly(tempsw); @@ -3882,7 +3886,7 @@ static const char *searchWad(const char *searchDir) } strcpy(tempsw, WADKEYWORD2); - fstemp = filesearch(tempsw, searchDir, NULL, true, 20); + fstemp = filesearch(1, &fsquery, searchDir, false, true, 20, NULL); if (fstemp == FS_FOUND) { pathonly(tempsw); diff --git a/src/sdl/i_threads.c b/src/sdl/i_threads.c index 078f4e0f4..f2bd82c01 100644 --- a/src/sdl/i_threads.c +++ b/src/sdl/i_threads.c @@ -47,6 +47,8 @@ static I_mutex i_cond_pool_mutex; static SDL_atomic_t i_threads_running = {1}; +static SDL_threadID i_main_thread_id; + static Link Insert_link ( Link * head, @@ -197,6 +199,12 @@ I_thread_is_stopped (void) return ( ! SDL_AtomicGet(&i_threads_running) ); } +int +I_on_main_thread (void) +{ + return ( SDL_ThreadID() == i_main_thread_id ); +} + void I_start_threads (void) { @@ -211,6 +219,8 @@ I_start_threads (void) )){ abort(); } + + i_main_thread_id = SDL_ThreadID(); } void @@ -283,6 +293,12 @@ I_lock_mutex ( I_mutex * anchor ){ SDL_mutex * mutex; + + if (! i_threads_running.value) + return; + + if (anchor == NULL) + return; mutex = Identity( &i_mutex_pool, @@ -299,6 +315,12 @@ void I_unlock_mutex ( I_mutex id ){ + if (! i_threads_running.value) + return; + + if (id == NULL) + return; + if (SDL_UnlockMutex(id) == -1) abort(); } @@ -309,6 +331,12 @@ I_hold_cond ( I_mutex mutex_id ){ SDL_cond * cond; + + if (! i_threads_running.value) + return; + + if (cond_anchor == NULL || mutex_id == NULL) + return; cond = Identity( &i_cond_pool, @@ -326,6 +354,12 @@ I_wake_one_cond ( I_cond * anchor ){ SDL_cond * cond; + + if (! i_threads_running.value) + return; + + if (anchor == NULL) + return; cond = Identity( &i_cond_pool, @@ -343,6 +377,12 @@ I_wake_all_cond ( I_cond * anchor ){ SDL_cond * cond; + + if (! i_threads_running.value) + return; + + if (anchor == NULL) + return; cond = Identity( &i_cond_pool, diff --git a/src/w_wad.c b/src/w_wad.c index 44bb71ee9..ebc6c25cb 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -904,17 +904,46 @@ void W_UnloadWadFile(UINT16 num) */ INT32 W_InitMultipleFiles(char **filenames, boolean addons) { + char filenamebufs[MAX_WADFILES][MAX_WADPATH]; + filequery_t q[MAX_WADFILES]; + + int n = 0; + int i; + INT32 rc = 1; INT32 overallrc = 1; // will be realloced as lumps are added for (; *filenames; filenames++) { - if (addons && !W_VerifyNMUSlumps(*filenames)) + if (FIL_FileOK(*filenames)) + { + q[n].status = FS_FOUND; + q[n].filename = *filenames; + } + else + { + strcpy(filenamebufs[n], *filenames); + q[n].filename = filenamebufs[n]; + } + n++; + } + + findmultiplefiles(n, q, false, true, NULL); + + for (i = 0; i < n; ++i) + { + if (q[i].status != FS_FOUND) + { + CONS_Alert(CONS_ERROR, M_GetText("File %s not found.\n"), q[i].filename); + continue; + } + + if (addons && !W_VerifyNMUSlumps(q[i].filename)) G_SetGameModified(true, false); //CONS_Debug(DBG_SETUP, "Loading %s\n", *filenames); - rc = W_InitFile(*filenames, 0, 0, false); + rc = W_InitFile(q[i].filename, 0, 0, false); if (rc == INT16_MAX) CONS_Printf(M_GetText("Errors occurred while loading %s; not added.\n"), *filenames); overallrc &= (rc != INT16_MAX) ? 1 : 0; diff --git a/src/z_zone.c b/src/z_zone.c index b0223460b..c049e5e20 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -29,6 +29,7 @@ #include "doomstat.h" #include "r_patch.h" #include "i_system.h" // I_GetFreeMem +#include "i_threads.h" #include "i_video.h" // rendermode #include "z_zone.h" #include "m_misc.h" // M_Memcpy @@ -50,6 +51,16 @@ static boolean Z_calloc = false; //#define ZDEBUG2 #endif +#ifdef HAVE_THREADS +static I_mutex z_mutex; + +# define Lock_state() I_lock_mutex(&z_mutex) +# define Unlock_state() I_unlock_mutex(z_mutex) +#else/*HAVE_THREADS*/ +# define Lock_state() +# define Unlock_state() +#endif/*HAVE_THREADS*/ + typedef struct memblock_s { void **user; @@ -135,6 +146,8 @@ void Z_Free(void *ptr) CONS_Debug(DBG_MEMORY, "Z_Free %s:%d\n", file, line); #endif + Lock_state(); + block = MEMBLOCK(ptr); #ifdef PARANOIA if (block->id != ZONEID) @@ -167,6 +180,8 @@ void Z_Free(void *ptr) block->prev->next = block->next; block->next->prev = block->prev; free(block); + + Unlock_state(); } /** malloc() that doesn't accept failure. @@ -233,6 +248,8 @@ void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) Z_calloc = false; #endif + Lock_state(); + block->next = head.next; block->prev = &head; head.next = block; @@ -258,7 +275,10 @@ void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits) block->user = user; *(void **)user = ptr; } - else if (tag >= PU_PURGELEVEL) + + Unlock_state(); + + if (tag >= PU_PURGELEVEL) I_Error("Z_Malloc: attempted to allocate purgable block " "(size %s) with no user", sizeu1(size)); @@ -392,6 +412,8 @@ void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignb void Z_FreeTags(INT32 lowtag, INT32 hightag) { memblock_t *block, *next; + + Lock_state(); Z_CheckHeap(420); for (block = head.next; block != &head; block = next) @@ -400,6 +422,8 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag) if (block->tag >= lowtag && block->tag <= hightag) Z_Free(MEMORY(block)); } + + Unlock_state(); } /** Iterates through all memory for a given set of tags. @@ -627,6 +651,8 @@ size_t Z_TagsUsage(INT32 lowtag, INT32 hightag) { size_t cnt = 0; memblock_t *rover; + + Lock_state(); for (rover = head.next; rover != &head; rover = rover->next) { @@ -634,6 +660,8 @@ size_t Z_TagsUsage(INT32 lowtag, INT32 hightag) continue; cnt += rover->size + sizeof *rover; } + + Unlock_state(); return cnt; } @@ -648,6 +676,8 @@ size_t Z_TagsUsage(INT32 lowtag, INT32 hightag) static void Command_Memfree_f(void) { size_t freebytes, totalbytes; + + Lock_state(); Z_CheckHeap(-1); CONS_Printf("\x82%s", M_GetText("Memory Info\n")); @@ -677,6 +707,8 @@ static void Command_Memfree_f(void) freebytes = I_GetFreeMem(&totalbytes); CONS_Printf(M_GetText(" Total physical memory: %s KB\n"), sizeu1(totalbytes>>10)); CONS_Printf(M_GetText("Available physical memory: %s KB\n"), sizeu1(freebytes>>10)); + + Unlock_state(); } @@ -698,6 +730,8 @@ static void Command_Memdump_f(void) if ((i = COM_CheckParm("-max"))) maxtag = atoi(COM_Argv(i + 1)); + + Lock_state(); for (block = head.next; block != &head; block = block->next) if (block->tag >= mintag && block->tag <= maxtag) @@ -705,6 +739,8 @@ static void Command_Memdump_f(void) char *filename = strrchr(block->ownerfile, PATHSEP[0]); CONS_Printf("[%3d] %s (%s) bytes @ %s:%d\n", block->tag, sizeu1(block->size), sizeu2(block->realsize), filename ? filename + 1 : block->ownerfile, block->ownerline); } + + Unlock_state(); } #endif