/* common/threads.c */ #include #include #include #include #include /* * FIXME - Temporary hack while trying to get qbsp to use the common * thread/logging code. Error() would normally be defined in * either common/cmdlib.h or qbsp/qbsp.h. */ [[noreturn]] void Error(const char *error, ...) __attribute__((format(printf,1,2),noreturn)); /* Make the locks no-ops if we aren't running threads */ static bool threads_active = false; static int dispatch; static int workcount; static int oldpercent = -1; /* * ============= * GetThreadWork * ============= */ int GetThreadWork_Locked__(void) { int ret; int percent; if (dispatch == workcount) return -1; percent = 50 * dispatch / workcount; while (oldpercent < percent) { oldpercent++; logprint_locked__("%c", (oldpercent % 5) ? '.' : '0' + (oldpercent / 5)); } ret = dispatch; dispatch++; return ret; } int GetThreadWork(void) { int ret; ThreadLock(); ret = GetThreadWork_Locked__(); ThreadUnlock(); return ret; } void InterruptThreadProgress__(void) { if (oldpercent != -1) { logprint_locked__("\\\n"); oldpercent = -1; } } /* * =================================================================== * WIN32 * =================================================================== */ #ifdef USE_WIN32THREADS #define HAVE_THREADS #include int numthreads = 1; CRITICAL_SECTION crit; void LowerProcessPriority(void) { SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS); } int GetDefaultThreads(void) { SYSTEM_INFO info; GetSystemInfo(&info); return info.dwNumberOfProcessors; } void ThreadLock(void) { if (threads_active) EnterCriticalSection(&crit); } void ThreadUnlock(void) { if (threads_active) LeaveCriticalSection(&crit); } /* * ============= * RunThreadsOn * ============= */ void RunThreadsOn(int start, int workcnt, void *(func)(void *), void *arg) { uintptr_t i; /* avoid warning due to cast for the CreateThread API */ DWORD *threadid; HANDLE *threadhandle; dispatch = start; workcount = workcnt; oldpercent = -1; threadid = static_cast(malloc(sizeof(*threadid) * numthreads)); threadhandle = static_cast(malloc(sizeof(*threadhandle) * numthreads)); if (!threadid || !threadhandle) Error("Failed to allocate memory for threads"); /* run threads in parallel */ InitializeCriticalSection(&crit); threads_active = true; for (i = 0; i < numthreads; i++) { threadhandle[i] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)func, (LPVOID)arg, 0, &threadid[i]); } for (i = 0; i < numthreads; i++) WaitForSingleObject(threadhandle[i], INFINITE); threads_active = false; oldpercent = -1; DeleteCriticalSection(&crit); logprint("\n"); free(threadhandle); free(threadid); } #endif /* USE_WIN32THREADS */ /* * =================================================================== * PTHREADS * =================================================================== */ #ifdef USE_PTHREADS #define HAVE_THREADS #include #include int numthreads = 1; pthread_mutex_t *my_mutex; void LowerProcessPriority(void) { /* not implemented for now */ } int GetDefaultThreads(void) { int threads; #ifdef _SC_NPROCESSORS_ONLN threads = sysconf(_SC_NPROCESSORS_ONLN); if (threads < 1) threads = 1; #else threads = 4; #endif return threads; } void ThreadLock(void) { if (threads_active) pthread_mutex_lock(my_mutex); } void ThreadUnlock(void) { if (threads_active) pthread_mutex_unlock(my_mutex); } /* * ============= * RunThreadsOn * ============= */ void RunThreadsOn(int start, int workcnt, void *(func)(void *), void *arg) { pthread_t *threads; pthread_mutexattr_t mattrib; pthread_attr_t attrib; int status; int i; dispatch = start; workcount = workcnt; oldpercent = -1; status = pthread_mutexattr_init(&mattrib); if (status) Error("pthread_mutexattr_init failed"); my_mutex = static_cast(malloc(sizeof(*my_mutex))); if (!my_mutex) Error("failed to allocate memory for thread mutex"); status = pthread_mutex_init(my_mutex, &mattrib); if (status) Error("pthread_mutex_init failed"); status = pthread_attr_init(&attrib); if (status) Error("pthread_attr_init failed"); threads = static_cast(malloc(sizeof(*threads) * numthreads)); if (!threads) Error("failed to allocate memory for threads"); threads_active = true; for (i = 0; i < numthreads; i++) { status = pthread_create(&threads[i], &attrib, func, arg); if (status) Error("pthread_create failed"); } for (i = 0; i < numthreads; i++) { status = pthread_join(threads[i], NULL); if (status) Error("pthread_join failed"); } threads_active = false; oldpercent = -1; status = pthread_mutex_destroy(my_mutex); if (status) Error("pthread_mutex_destroy failed"); free(threads); free(my_mutex); logprint("\n"); } #endif /* USE_PTHREADS */ /* * ======================================================================= * SINGLE THREAD * ======================================================================= */ #ifndef HAVE_THREADS int numthreads = 1; void ThreadLock(void) {} void ThreadUnlock(void) {} /* * ============= * RunThreadsOn * ============= */ void RunThreadsOn(int start, int workcnt, void *(func)(void *), void *arg) { dispatch = start; workcount = workcnt; oldpercent = -1; func(arg); logprint("\n"); } #endif