mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2024-11-21 12:01:05 +00:00
Multithreading in my SRB2???
This commit is contained in:
parent
1584b7394b
commit
886bd34be5
4 changed files with 387 additions and 0 deletions
39
src/i_threads.h
Normal file
39
src/i_threads.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
// 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 i_threads.h
|
||||
/// \brief Multithreading abstraction
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
|
||||
#ifndef I_THREADS_H
|
||||
#define I_THREADS_H
|
||||
|
||||
typedef void (*I_thread_fn)(void *userdata);
|
||||
|
||||
typedef void * I_mutex;
|
||||
typedef void * I_cond;
|
||||
|
||||
void I_start_threads (void);
|
||||
void I_stop_threads (void);
|
||||
|
||||
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);
|
||||
|
||||
void I_lock_mutex (I_mutex *);
|
||||
void I_unlock_mutex (I_mutex);
|
||||
|
||||
void I_hold_cond (I_cond *, I_mutex);
|
||||
|
||||
void I_wake_one_cond (I_cond);
|
||||
void I_wake_all_cond (I_cond);
|
||||
|
||||
#endif/*I_THREADS_H*/
|
||||
#endif/*HAVE_THREADS*/
|
|
@ -88,6 +88,11 @@ else
|
|||
endif
|
||||
endif
|
||||
|
||||
ifndef NOTHREADS
|
||||
OPTS+=-DHAVE_THREADS
|
||||
OBJS+=$(OBJDIR)/i_threads.o
|
||||
endif
|
||||
|
||||
ifdef SDL_TTF
|
||||
OPTS+=-DHAVE_TTF
|
||||
SDL_LDFLAGS+=-lSDL2_ttf -lfreetype -lz
|
||||
|
|
|
@ -167,6 +167,7 @@ static char returnWadPath[256];
|
|||
#include "../i_video.h"
|
||||
#include "../i_sound.h"
|
||||
#include "../i_system.h"
|
||||
#include "../i_threads.h"
|
||||
#include "../screen.h" //vid.WndParent
|
||||
#include "../d_net.h"
|
||||
#include "../g_game.h"
|
||||
|
@ -2251,6 +2252,10 @@ INT32 I_StartupSystem(void)
|
|||
SDL_version SDLlinked;
|
||||
SDL_VERSION(&SDLcompiled)
|
||||
SDL_GetVersion(&SDLlinked);
|
||||
#ifdef HAVE_THREADS
|
||||
I_start_threads();
|
||||
atexit(I_stop_threads);
|
||||
#endif
|
||||
I_StartupConsole();
|
||||
#ifdef NEWSIGNALHANDLER
|
||||
I_Fork();
|
||||
|
|
338
src/sdl/i_threads.c
Normal file
338
src/sdl/i_threads.c
Normal file
|
@ -0,0 +1,338 @@
|
|||
// 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 i_threads.c
|
||||
/// \brief Multithreading abstraction
|
||||
|
||||
#include "../doomdef.h"
|
||||
#include "../i_threads.h"
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
typedef void * (*Create_fn)(void);
|
||||
|
||||
struct Link;
|
||||
struct Thread;
|
||||
|
||||
typedef struct Link * Link;
|
||||
typedef struct Thread * Thread;
|
||||
|
||||
struct Link
|
||||
{
|
||||
void * data;
|
||||
Link next;
|
||||
Link prev;
|
||||
};
|
||||
|
||||
struct Thread
|
||||
{
|
||||
I_thread_fn entry;
|
||||
void * userdata;
|
||||
|
||||
SDL_Thread * thread;
|
||||
};
|
||||
|
||||
static Link i_thread_pool;
|
||||
static Link i_mutex_pool;
|
||||
static Link i_cond_pool;
|
||||
|
||||
static I_mutex i_thread_pool_mutex;
|
||||
static I_mutex i_mutex_pool_mutex;
|
||||
static I_mutex i_cond_pool_mutex;
|
||||
|
||||
static SDL_atomic_t i_threads_running = {1};
|
||||
|
||||
static Link
|
||||
Insert_link (
|
||||
Link * head,
|
||||
Link link
|
||||
){
|
||||
link->prev = NULL;
|
||||
link->next = (*head);
|
||||
if ((*head))
|
||||
(*head)->prev = link;
|
||||
(*head) = link;
|
||||
return link;
|
||||
}
|
||||
|
||||
static void
|
||||
Free_link (
|
||||
Link * head,
|
||||
Link link
|
||||
){
|
||||
if (link->prev)
|
||||
link->prev->next = link->next;
|
||||
else
|
||||
(*head) = link->next;
|
||||
|
||||
if (link->next)
|
||||
link->next->prev = link->prev;
|
||||
|
||||
free(link->data);
|
||||
free(link);
|
||||
}
|
||||
|
||||
static Link
|
||||
New_link (void *data)
|
||||
{
|
||||
Link link;
|
||||
|
||||
link = malloc(sizeof *link);
|
||||
|
||||
if (! link)
|
||||
abort();
|
||||
|
||||
link->data = data;
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
static void *
|
||||
Identity (
|
||||
Link * pool_anchor,
|
||||
I_mutex pool_mutex,
|
||||
|
||||
void ** anchor,
|
||||
|
||||
Create_fn create_fn
|
||||
){
|
||||
void * id;
|
||||
|
||||
id = SDL_AtomicGetPtr(anchor);
|
||||
|
||||
if (! id)
|
||||
{
|
||||
I_lock_mutex(&pool_mutex);
|
||||
{
|
||||
id = SDL_AtomicGetPtr(anchor);
|
||||
|
||||
if (! id)
|
||||
{
|
||||
id = (*create_fn)();
|
||||
|
||||
if (! id)
|
||||
abort();
|
||||
|
||||
Insert_link(pool_anchor, New_link(id));
|
||||
|
||||
SDL_AtomicSetPtr(anchor, id);
|
||||
}
|
||||
}
|
||||
I_unlock_mutex(pool_mutex);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static int
|
||||
Worker (
|
||||
Link link
|
||||
){
|
||||
Thread th;
|
||||
|
||||
th = link->data;
|
||||
|
||||
(*th->entry)(th->userdata);
|
||||
|
||||
if (SDL_AtomicGet(&i_threads_running))
|
||||
{
|
||||
I_lock_mutex(&i_thread_pool_mutex);
|
||||
{
|
||||
if (SDL_AtomicGet(&i_threads_running))
|
||||
{
|
||||
SDL_DetachThread(th->thread);
|
||||
Free_link(&i_thread_pool, link);
|
||||
}
|
||||
}
|
||||
I_unlock_mutex(i_thread_pool_mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
I_spawn_thread (
|
||||
const char * name,
|
||||
I_thread_fn entry,
|
||||
void * userdata
|
||||
){
|
||||
Link link;
|
||||
Thread th;
|
||||
|
||||
th = malloc(sizeof *th);
|
||||
|
||||
if (! th)
|
||||
abort();/* this is pretty GNU of me */
|
||||
|
||||
th->entry = entry;
|
||||
th->userdata = userdata;
|
||||
|
||||
I_lock_mutex(&i_thread_pool_mutex);
|
||||
{
|
||||
link = Insert_link(&i_thread_pool, New_link(th));
|
||||
|
||||
if (SDL_AtomicGet(&i_threads_running))
|
||||
{
|
||||
th->thread = SDL_CreateThread(
|
||||
(SDL_ThreadFunction)Worker,
|
||||
name,
|
||||
link
|
||||
);
|
||||
|
||||
if (! th->thread)
|
||||
abort();
|
||||
}
|
||||
}
|
||||
I_unlock_mutex(i_thread_pool_mutex);
|
||||
}
|
||||
|
||||
int
|
||||
I_thread_is_stopped (void)
|
||||
{
|
||||
return ( ! SDL_AtomicGet(&i_threads_running) );
|
||||
}
|
||||
|
||||
void
|
||||
I_start_threads (void)
|
||||
{
|
||||
i_thread_pool_mutex = SDL_CreateMutex();
|
||||
i_mutex_pool_mutex = SDL_CreateMutex();
|
||||
i_cond_pool_mutex = SDL_CreateMutex();
|
||||
|
||||
if (!(
|
||||
i_thread_pool_mutex &&
|
||||
i_mutex_pool_mutex &&
|
||||
i_cond_pool_mutex
|
||||
)){
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
I_stop_threads (void)
|
||||
{
|
||||
Link link;
|
||||
Link next;
|
||||
|
||||
Thread th;
|
||||
SDL_mutex * mutex;
|
||||
SDL_cond * cond;
|
||||
|
||||
if (i_threads_running.value)
|
||||
{
|
||||
/* rely on the good will of thread-san */
|
||||
SDL_AtomicSet(&i_threads_running, 0);
|
||||
|
||||
I_lock_mutex(&i_thread_pool_mutex);
|
||||
{
|
||||
for (
|
||||
link = i_thread_pool;
|
||||
link;
|
||||
link = next
|
||||
){
|
||||
next = link->next;
|
||||
th = link->data;
|
||||
|
||||
SDL_WaitThread(th->thread, NULL);
|
||||
|
||||
free(th);
|
||||
free(link);
|
||||
}
|
||||
}
|
||||
I_unlock_mutex(i_thread_pool_mutex);
|
||||
|
||||
for (
|
||||
link = i_mutex_pool;
|
||||
link;
|
||||
link = next
|
||||
){
|
||||
next = link->next;
|
||||
mutex = link->data;
|
||||
|
||||
SDL_DestroyMutex(mutex);
|
||||
|
||||
free(link);
|
||||
}
|
||||
|
||||
for (
|
||||
link = i_cond_pool;
|
||||
link;
|
||||
link = next
|
||||
){
|
||||
next = link->next;
|
||||
cond = link->data;
|
||||
|
||||
SDL_DestroyCond(cond);
|
||||
|
||||
free(link);
|
||||
}
|
||||
|
||||
SDL_DestroyMutex(i_thread_pool_mutex);
|
||||
SDL_DestroyMutex(i_mutex_pool_mutex);
|
||||
SDL_DestroyMutex(i_cond_pool_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
I_lock_mutex (
|
||||
I_mutex * anchor
|
||||
){
|
||||
SDL_mutex * mutex;
|
||||
|
||||
mutex = Identity(
|
||||
&i_mutex_pool,
|
||||
i_mutex_pool_mutex,
|
||||
anchor,
|
||||
(Create_fn)SDL_CreateMutex
|
||||
);
|
||||
|
||||
if (SDL_LockMutex(mutex) == -1)
|
||||
abort();
|
||||
}
|
||||
|
||||
void
|
||||
I_unlock_mutex (
|
||||
I_mutex id
|
||||
){
|
||||
if (SDL_UnlockMutex(id) == -1)
|
||||
abort();
|
||||
}
|
||||
|
||||
void
|
||||
I_hold_cond (
|
||||
I_cond * cond_anchor,
|
||||
I_mutex mutex_id
|
||||
){
|
||||
SDL_cond * cond;
|
||||
|
||||
cond = Identity(
|
||||
&i_cond_pool,
|
||||
i_cond_pool_mutex,
|
||||
cond_anchor,
|
||||
(Create_fn)SDL_CreateCond
|
||||
);
|
||||
|
||||
if (SDL_CondWait(cond, mutex_id) == -1)
|
||||
abort();
|
||||
}
|
||||
|
||||
void
|
||||
I_wake_one_cond (
|
||||
I_cond id
|
||||
){
|
||||
if (SDL_CondSignal(id) == -1)
|
||||
abort();
|
||||
}
|
||||
|
||||
void
|
||||
I_wake_all_cond (
|
||||
I_cond id
|
||||
){
|
||||
if (SDL_CondBroadcast(id) == -1)
|
||||
abort();
|
||||
}
|
Loading…
Reference in a new issue