threads.c

Go to the documentation of this file.
00001 /*
00002 Copyright(c) 1997-2001 Id Software, Inc.
00003 Copyright(c) 2002 The Quakeforge Project.
00004 Copyright(c) 2006 Quake2World.
00005 
00006 This program is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU General Public License
00008 as published by the Free Software Foundation; either version 2
00009 of the License, or(at your option) any later version.
00010 
00011 This program is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00014 
00015 See the GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with this program; if not, write to the Free Software
00019 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020 
00021 */
00022 
00023 #include <SDL_thread.h>
00024 
00025 #include "bsp.h"
00026 
00027 #define MAX_THREADS 8
00028 
00029 threadstate_t threadstate;
00030 
00034 static int GetThreadWork (void)
00035 {
00036     int r;
00037     int f;
00038 
00039     ThreadLock();
00040 
00041     if (threadstate.workindex == threadstate.workcount) {  /* done */
00042         ThreadUnlock();
00043         return -1;
00044     }
00045 
00046     /* update work fraction and output progress if desired */
00047     f = 10 * threadstate.workindex / threadstate.workcount;
00048     if (f != threadstate.workfrac) {
00049         threadstate.workfrac = f;
00050         if (threadstate.progress) {
00051             fprintf(stdout, "%i...", f);
00052             fflush(stdout);
00053         }
00054     } else if (threadstate.progress && threadstate.workindex % threadstate.worktick == 0) {
00055         fprintf(stdout, "%c\b", "-\\|/"[(threadstate.workindex / threadstate.worktick) & 3]);
00056         fflush(stdout);
00057     }
00058 
00059     /* assign the next work iteration */
00060     r = threadstate.workindex;
00061     threadstate.workindex++;
00062 
00063     ThreadUnlock();
00064 
00065     return r;
00066 }
00067 
00068 
00070 static void (*WorkFunction) (unsigned int);
00071 
00072 
00077 static int ThreadWork (void *p)
00078 {
00079     while (qtrue) {
00080         int work = GetThreadWork();
00081         if (work == -1)
00082             break;
00083         WorkFunction(work);
00084     }
00085 
00086     return 0;
00087 }
00088 
00089 
00090 static SDL_mutex *lock = NULL;
00091 
00092 static void ThreadInit (void)
00093 {
00094     if (lock != NULL)
00095         Sys_Error("Mutex already created!");
00096 
00097     lock = SDL_CreateMutex();
00098 
00099     if (lock == NULL)
00100         Sys_Error("Couldn't create mutex!");
00101 }
00102 
00103 static void ThreadRelease (void)
00104 {
00105     SDL_DestroyMutex(lock);
00106     lock = NULL;
00107 }
00108 
00112 void ThreadLock (void)
00113 {
00114     if (threadstate.numthreads == 1) {
00115         /* do nothing */
00116     } else if (lock != NULL && SDL_mutexP(lock) != -1) {
00117         /* already locked */
00118     } else {
00119         Sys_Error("Couldn't lock mutex (%p)!", lock);
00120     }
00121 }
00122 
00126 void ThreadUnlock (void)
00127 {
00128     if (threadstate.numthreads == 1) {
00129         /* do nothing */
00130     } else if (lock != NULL && SDL_mutexV(lock) != -1) {
00131         /* already locked */
00132     } else {
00133         Sys_Error("Couldn't unlock mutex (%p)!", lock);
00134     }
00135 }
00136 
00137 static void RunThreads (void)
00138 {
00139     SDL_Thread *threads[MAX_THREADS];
00140     int i;
00141 
00142     if (threadstate.numthreads == 1) {
00143         ThreadWork(0);
00144         return;
00145     }
00146 
00147     ThreadInit();
00148 
00149     for (i = 0; i < threadstate.numthreads; i++)
00150         threads[i] = SDL_CreateThread(ThreadWork, NULL);
00151 
00152     for (i = 0; i < threadstate.numthreads; i++)
00153         SDL_WaitThread(threads[i], NULL);
00154 
00155     ThreadRelease();
00156 }
00157 
00158 
00162 void RunThreadsOn (void (*func)(unsigned int), int unsigned workcount, qboolean progress, const char *id)
00163 {
00164     int start, end;
00165 
00166     if (threadstate.numthreads < 1)  /* ensure safe thread counts */
00167         threadstate.numthreads = 1;
00168 
00169     if (threadstate.numthreads > MAX_THREADS)
00170         threadstate.numthreads = MAX_THREADS;
00171 
00172     threadstate.workindex = 0;
00173     threadstate.workcount = workcount;
00174     threadstate.workfrac = -1;
00175     threadstate.progress = progress;
00176     threadstate.worktick = sqrt(workcount) + 1;
00177 
00178     WorkFunction = func;
00179 
00180     start = time(NULL);
00181 
00182     if (threadstate.progress) {
00183         fprintf(stdout, "%10s: ", id);
00184         fflush(stdout);
00185     }
00186 
00187     RunThreads();
00188 
00189     end = time(NULL);
00190 
00191     if (threadstate.progress) {
00192         Verb_Printf(VERB_NORMAL, " (time: %6is, #: %i)\n", end - start, workcount);
00193     }
00194 }
00195 
00199 void RunSingleThreadOn (void (*func)(unsigned int), int unsigned workcount, qboolean progress, const char *id)
00200 {
00201     int saved_numthreads = threadstate.numthreads;
00202 
00203     threadstate.numthreads = 1;
00204 
00205     RunThreadsOn(func, workcount, progress, id);
00206 
00207     threadstate.numthreads = saved_numthreads;
00208 }

Generated by  doxygen 1.6.2