diff --git a/imv.c b/imv.c index 4ef6492..7d8e579 100644 --- a/imv.c +++ b/imv.c @@ -155,8 +155,8 @@ typedef struct int lru; } ImageFile; -stb_semaphore cache_mutex; -stb_semaphore decode_queue, decode_mutex; +stb_mutex cache_mutex, decode_mutex; +stb_semaphore decode_queue; stb_semaphore disk_command_queue; typedef struct @@ -186,13 +186,13 @@ o("READ: Waiting for disk request.\n"); stb_sem_waitfor(disk_command_queue); // grab the command; don't let the command or the cache change while we do it - stb_sem_waitfor(cache_mutex); + stb_mutex_begin(cache_mutex); { dc = dc_shared; for (i=0; i < dc.num_files; ++i) dc.files[i]->status = LOAD_reading; } - stb_sem_release(cache_mutex); + stb_mutex_end(cache_mutex); o("READ: Got disk request, %d items.\n", dc.num_files); for (i=0; i < dc.num_files; ++i) { @@ -256,12 +256,12 @@ start: } if (best) { int retry = FALSE; - stb_sem_waitfor(cache_mutex); + stb_mutex_begin(cache_mutex); if (best->status == LOAD_reading_done) best->status = LOAD_decoding; else retry = TRUE; - stb_sem_release(cache_mutex); + stb_mutex_end(cache_mutex); if (retry) goto start; } return best; @@ -620,7 +620,7 @@ void flush_cache(int locked) limit = MAX_CACHED_IMAGES - MIN_CACHE; if (total > max_cache_bytes || occupied_slots > limit) { qsort((void *) list, n, sizeof(*list), ImageFilePtrCompare); - if (!locked) stb_sem_waitfor(cache_mutex); + if (!locked) stb_mutex_begin(cache_mutex); for (i=0; i < n && occupied_slots > MIN_CACHE && (occupied_slots > limit || total > max_cache_bytes); ++i) { ImageFile p; /* @TODO: this is totally squirrely and probably buggy. we need to @@ -641,7 +641,7 @@ void flush_cache(int locked) } } if (MAIN_OWNS(&p) && p.status != LOAD_unused) { - if (!locked) stb_sem_release(cache_mutex); + if (!locked) stb_mutex_end(cache_mutex); o("MAIN: freeing cache: %s\n", p.filename); stb_sdict_remove(file_cache, p.filename, NULL); --occupied_slots; // occupied slots @@ -653,10 +653,10 @@ o("MAIN: freeing cache: %s\n", p.filename); if (p.filedata) free(p.filedata); if (p.image) imfree(p.image); if (p.error) free(p.error); - if (!locked) stb_sem_waitfor(cache_mutex); + if (!locked) stb_mutex_begin(cache_mutex); } } - if (!locked) stb_sem_release(cache_mutex); + if (!locked) stb_mutex_end(cache_mutex); o("Reduced to %d megabytes\n", total >> 20); } } @@ -742,7 +742,7 @@ void advance(int dir) fileinfo[cur_loc].lru = ++lru_stamp; // need to grab the cache - stb_sem_waitfor(cache_mutex); + stb_mutex_begin(cache_mutex); dc.num_files = 0; queue_disk_command(&dc, cur_loc, 1); // first thing to load: this file queue_disk_command(&dc, wrap(cur_loc+dir), 0); // second thing to load: the next file (preload) @@ -752,7 +752,7 @@ void advance(int dir) dc_shared = dc; stb_sem_release(disk_command_queue); } - stb_sem_release(cache_mutex); + stb_mutex_end(cache_mutex); // tell loader not to bother with old data for (i=0; i < MAX_CACHED_IMAGES; ++i) if (cache[i].lru < lru_stamp-1) @@ -1147,10 +1147,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine if (argc < 1) { MessageBox(NULL, "Specify an image file to view", "imv(stb)", MB_OK); exit(0); } resize_workers = stb_workq_new(resize_threads, resize_threads * 4); - cache_mutex = stb_sem_new(1,0); + cache_mutex = stb_mutex_new(); disk_command_queue = stb_sem_new(1,1); decode_queue = stb_sem_new(1,1); - decode_mutex = stb_sem_new(1,0); + decode_mutex = stb_mutex_new(); image_data = stbi_load(argv[0], &image_x, &image_y, &image_n, BPP); if (image_data == NULL) { @@ -1173,6 +1173,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine cache[0].filename = strdup(filename); file_cache = stb_sdict_new(1); stb_sdict_add(file_cache, filename, (void *) &cache[0]); + source_c = (ImageFile *) &cache[0]; { diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..fd83eb7 --- /dev/null +++ b/readme.txt @@ -0,0 +1,5 @@ +COMPILING + +There is a workspace/project file for VC6 (VC98) in the "vc6" subdirectory. + +Or you can just directly compile imv.c, with multithreaded runtime. \ No newline at end of file diff --git a/stb.h b/stb.h index 1aa816c..2c04630 100644 --- a/stb.h +++ b/stb.h @@ -1,4 +1,4 @@ -/* stb-1.88 -- Sean's Tool Box -- public domain -- http://nothings.org/stb.h +/* stb-1.89 -- Sean's Tool Box -- public domain -- http://nothings.org/stb.h no warranty is offered or implied; use this code at your own risk This is a single header file with a bunch of useful utilities @@ -118,6 +118,8 @@ Bug reports, feature requests, etc. can be mailed to 'sean' at the above site. 3. Version History + 1.89 support ';' in constant-string wildcards; stb_mutex wrapper (can implement + with EnterCriticalRegion eventually) 1.88 portable threading API (only for win32 so far); worker thread queueing 1.87 fix wildcard handling in stb_readdir_recursive 1.86 support ';' in wildcards @@ -10579,10 +10581,17 @@ void stb_compress_stream_end(int close) // Threads // -typedef void *stb_thread; + typedef void * (*stb_thread_func)(void *); + +// do not rely on these types, this is an implementation detail. +// compare against STB_THREAD_NULL and ST_SEMAPHORE_NULL +typedef void *stb_thread; typedef void *stb_semaphore; +typedef void *stb_mutex; #define STB_SEMAPHORE_NULL NULL +#define STB_THREAD_NULL NULL +#define STB_MUTEX_NULL NULL // get the number of processors (limited to those in the affinity mask for this process). STB_EXTERN int stb_processor_count(void); @@ -10623,6 +10632,10 @@ STB_EXTERN void stb_sem_delete (stb_semaphore s); STB_EXTERN void stb_sem_waitfor(stb_semaphore s); STB_EXTERN void stb_sem_release(stb_semaphore s); +STB_EXTERN stb_mutex stb_mutex_new(void); +STB_EXTERN void stb_mutex_delete(stb_mutex m); +STB_EXTERN void stb_mutex_begin(stb_mutex m); +STB_EXTERN void stb_mutex_end(stb_mutex m); #ifdef STB_DEFINE @@ -10671,6 +10684,10 @@ static void stb__thread_run(void *t) static stb_thread stb_create_thread_raw(stb_thread_func f, void *d, volatile void **return_code, stb_semaphore rel) { #ifdef _MT +#if defined(STB_FASTMALLOC) && !defined(STB_FASTMALLOC_ITS_OKAY_I_ONLY_MALLOC_IN_ONE_THREAD) + stb_fatal("Error! Cannot use STB_FASTMALLOC with threads.\n"); + return STB_THREAD_NULL; +#else unsigned long id; stb__thread *data = (stb__thread *) malloc(sizeof(*data)); if (!data) return NULL; @@ -10683,6 +10700,7 @@ static stb_thread stb_create_thread_raw(stb_thread_func f, void *d, volatile voi id = _beginthread(stb__thread_run, 0, data); if (id == -1) return NULL; return (void *) id; +#endif #else stb_fatal("Must compile mult-threaded to use stb_thread/stb_work."); return NULL; @@ -10721,6 +10739,13 @@ stb_thread stb_create_thread(stb_thread_func f, void *d) return stb_create_thread2(f,d,NULL,STB_SEMAPHORE_NULL); } +// mutex implemented by wrapping semaphore +stb_mutex stb_mutex_new(void) { return stb_sem_new(1,0); } +void stb_mutex_delete(stb_mutex m) { stb_sem_delete (m); } +void stb_mutex_begin(stb_mutex m) { stb_sem_waitfor(m); } +void stb_mutex_end(stb_mutex m) { stb_sem_release(m); } + + static int stb__work_maxitems = 64; typedef struct diff --git a/vc6/stb_imv.dsp b/vc6/stb_imv.dsp index 7dcf436..6d506e4 100644 --- a/vc6/stb_imv.dsp +++ b/vc6/stb_imv.dsp @@ -42,7 +42,8 @@ RSC=rc.exe # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /G6 /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -65,9 +66,11 @@ LINK32=link.exe # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c -# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /G6 /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -85,17 +88,13 @@ LINK32=link.exe # Name "stb_imv - Win32 Release" # Name "stb_imv - Win32 Debug" -# Begin Group "Source Files" +# Begin Source File -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" -# End Group -# Begin Group "Header Files" +SOURCE=..\imv.c +# End Source File +# Begin Source File -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# End Group -# Begin Group "Resource Files" - -# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" -# End Group +SOURCE=..\stb.h +# End Source File # End Target # End Project