Don't clobber refcounting in SDL_Init.

- Fixes bug 1712 by not overwriting SDL_SubsystemRefCount in SDL_Init.
       - Removes the SDL_initialized variable, and makes SDL_SubsystemRefCount
         the canonical source of truth for whether or not a subsystem has been
         initialized.
       - Refactors SDL_InitSubSystem and SDL_QuitSubSystem to use helper
         functions to manage refcount.
       - Adds automated tests for SDL_Init/Quit*.
       - Adds SDL_bits.h which contains SDL_MostSignificantBitIndex.
This commit is contained in:
Jørgen P. Tjernø
2013-02-12 11:47:31 -08:00
parent 8e2aba3d97
commit e8a48ee6c0
9 changed files with 411 additions and 140 deletions

306
src/SDL.c
View File

@@ -23,6 +23,7 @@
/* Initialization code for SDL */
#include "SDL.h"
#include "SDL_bits.h"
#include "SDL_revision.h"
#include "SDL_fatal.h"
#include "SDL_assert_c.h"
@@ -42,134 +43,146 @@ extern int SDL_HelperWindowDestroy(void);
/* The initialized subsystems */
static Uint32 SDL_initialized = 0;
static Uint32 ticks_started = 0;
static SDL_bool SDL_bInMainQuit = SDL_FALSE;
static Uint8 SDL_SubsystemRefCount[ 32 ]; // keep a per subsystem init
static Uint8 SDL_SubsystemRefCount[ 32 ];
/* helper func to return the index of the MSB in an int */
int msb32_idx( Uint32 n)
/* Private helper to increment a subsystem's ref counter. */
static void SDL_PrivateSubsystemRefCountIncr(Uint32 subsystem)
{
int b = 0;
if (!n) return -1;
int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
SDL_assert(SDL_SubsystemRefCount[subsystem_index] < 255);
++SDL_SubsystemRefCount[subsystem_index];
}
#define step(x) if (n >= ((Uint32)1) << x) b += x, n >>= x
step(16); step(8); step(4); step(2); step(1);
#undef step
return b;
/* Private helper to decrement a subsystem's ref counter. */
void SDL_PrivateSubsystemRefCountDecr(Uint32 subsystem)
{
int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
if (SDL_SubsystemRefCount[subsystem_index] > 0) {
--SDL_SubsystemRefCount[subsystem_index];
}
}
/* Private helper to check if a system needs init. */
static SDL_bool
SDL_PrivateShouldInitSubsystem(Uint32 flags, Uint32 subsystem)
{
if ((flags & subsystem) == 0) {
return SDL_FALSE;
}
int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
SDL_assert(SDL_SubsystemRefCount[subsystem_index] < 255);
return (SDL_SubsystemRefCount[subsystem_index] == 0);
}
/* Private helper to check if a system needs to be quit. */
static SDL_bool
SDL_PrivateShouldQuitSubsystem(Uint32 subsystem) {
int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
if (SDL_SubsystemRefCount[subsystem_index] == 0) {
return SDL_FALSE;
}
/* If we're in SDL_Quit, we shut down every subsystem, even if refcount
* isn't zero.
*/
return SDL_SubsystemRefCount[subsystem_index] == 1 || SDL_bInMainQuit;
}
int
SDL_InitSubSystem(Uint32 flags)
{
#if !SDL_TIMERS_DISABLED
/* Initialize the timer subsystem */
if (!ticks_started) {
SDL_StartTicks();
ticks_started = 1;
}
if ((flags & SDL_INIT_TIMER) ){
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_TIMER) ]++;
SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_TIMER) ] < 254 );
if ( !(SDL_initialized & SDL_INIT_TIMER)) {
if (SDL_TimerInit() < 0) {
return (-1);
}
SDL_initialized |= SDL_INIT_TIMER;
}
}
#else
if (flags & SDL_INIT_TIMER) {
SDL_SetError("SDL not built with timer support");
return (-1);
}
#endif
#if !SDL_VIDEO_DISABLED
/* Initialize the video/event subsystem */
if ((flags & SDL_INIT_VIDEO) ) {
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_VIDEO) ]++;
SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_VIDEO) ] < 254 );
if ( !(SDL_initialized & SDL_INIT_VIDEO)) {
if (SDL_VideoInit(NULL) < 0) {
return (-1);
}
SDL_initialized |= SDL_INIT_VIDEO;
}
}
#else
if (flags & SDL_INIT_VIDEO) {
SDL_SetError("SDL not built with video support");
return (-1);
}
#endif
#if !SDL_AUDIO_DISABLED
/* Initialize the audio subsystem */
if ((flags & SDL_INIT_AUDIO) ) {
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_AUDIO) ]++;
SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_AUDIO) ] < 254 );
if ( !(SDL_initialized & SDL_INIT_AUDIO)) {
if (SDL_AudioInit(NULL) < 0) {
return (-1);
}
SDL_initialized |= SDL_INIT_AUDIO;
}
}
#else
if (flags & SDL_INIT_AUDIO) {
SDL_SetError("SDL not built with audio support");
return (-1);
}
#endif
#if !SDL_JOYSTICK_DISABLED
/* Initialize the joystick subsystem */
if ( ( (flags & SDL_INIT_JOYSTICK) ) || ((flags & SDL_INIT_GAMECONTROLLER) ) ) { // game controller implies joystick
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_JOYSTICK) ]++;
SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_JOYSTICK) ] < 254 );
if ( !(SDL_initialized & SDL_INIT_JOYSTICK) && SDL_JoystickInit() < 0) {
/* Initialize the timer subsystem */
if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_TIMER)) {
#if !SDL_TIMERS_DISABLED
if (SDL_TimerInit() < 0) {
return (-1);
}
if ((flags & SDL_INIT_GAMECONTROLLER) ) {
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_GAMECONTROLLER) ]++;
SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_GAMECONTROLLER) ] < 254 );
if ( !(SDL_initialized & SDL_INIT_GAMECONTROLLER)) {
if (SDL_GameControllerInit() < 0) {
return (-1);
}
SDL_initialized |= SDL_INIT_GAMECONTROLLER;
}
}
SDL_initialized |= SDL_INIT_JOYSTICK;
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_TIMER);
#else
SDL_SetError("SDL not built with timer support");
return (-1);
#endif
}
/* Initialize the video/event subsystem */
if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_VIDEO)) {
#if !SDL_VIDEO_DISABLED
if (SDL_VideoInit(NULL) < 0) {
return (-1);
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_VIDEO);
#else
SDL_SetError("SDL not built with video support");
return (-1);
#endif
}
/* Initialize the audio subsystem */
if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_AUDIO)) {
#if !SDL_AUDIO_DISABLED
if (SDL_AudioInit(NULL) < 0) {
return (-1);
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_AUDIO);
#else
SDL_SetError("SDL not built with audio support");
return (-1);
#endif
}
if ((flags & SDL_INIT_GAMECONTROLLER)) {
// Game controller implies Joystick.
flags |= SDL_INIT_JOYSTICK;
}
/* Initialize the joystick subsystem */
if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_JOYSTICK)) {
#if !SDL_JOYSTICK_DISABLED
if (SDL_JoystickInit() < 0) {
return (-1);
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_JOYSTICK);
#else
if (flags & SDL_INIT_JOYSTICK) {
SDL_SetError("SDL not built with joystick support");
return (-1);
}
#endif
#if !SDL_HAPTIC_DISABLED
/* Initialize the haptic subsystem */
if ((flags & SDL_INIT_HAPTIC) ) {
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_HAPTIC) ]++;
SDL_assert( SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_HAPTIC) ] < 254 );
if ( !(SDL_initialized & SDL_INIT_HAPTIC)) {
if (SDL_HapticInit() < 0) {
return (-1);
}
SDL_initialized |= SDL_INIT_HAPTIC;
}
}
if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_GAMECONTROLLER)) {
#if !SDL_JOYSTICK_DISABLED
if (SDL_GameControllerInit() < 0) {
return (-1);
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_GAMECONTROLLER);
#else
SDL_SetError("SDL not built with joystick support");
return (-1);
#endif
}
/* Initialize the haptic subsystem */
if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_HAPTIC)) {
#if !SDL_HAPTIC_DISABLED
if (SDL_HapticInit() < 0) {
return (-1);
}
SDL_PrivateSubsystemRefCountIncr(SDL_INIT_HAPTIC);
#else
if (flags & SDL_INIT_HAPTIC) {
SDL_SetError("SDL not built with haptic (force feedback) support");
return (-1);
}
#endif
}
return (0);
}
@@ -199,7 +212,6 @@ SDL_Init(Uint32 flags)
SDL_InstallParachute();
}
SDL_memset( SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount) );
return (0);
}
@@ -208,62 +220,57 @@ SDL_QuitSubSystem(Uint32 flags)
{
/* Shut down requested initialized subsystems */
#if !SDL_JOYSTICK_DISABLED
if ((flags & SDL_initialized & SDL_INIT_JOYSTICK) || (flags & SDL_initialized & SDL_INIT_GAMECONTROLLER)) {
if ( (flags & SDL_initialized & SDL_INIT_GAMECONTROLLER) ) {
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_GAMECONTROLLER) ]--;
if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_GAMECONTROLLER) ] == 0 ) {
SDL_GameControllerQuit();
SDL_initialized &= ~SDL_INIT_GAMECONTROLLER;
}
}
if ((flags & SDL_INIT_GAMECONTROLLER)) {
// Game controller implies Joystick.
flags |= SDL_INIT_JOYSTICK;
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_JOYSTICK) ]--;
if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_JOYSTICK) ] == 0 )
{
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_GAMECONTROLLER)) {
SDL_GameControllerQuit();
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_GAMECONTROLLER);
}
if ((flags & SDL_INIT_JOYSTICK)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_JOYSTICK)) {
SDL_JoystickQuit();
SDL_initialized &= ~SDL_INIT_JOYSTICK;
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_JOYSTICK);
}
#endif
}
#endif
#if !SDL_HAPTIC_DISABLED
if ((flags & SDL_initialized & SDL_INIT_HAPTIC)) {
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_HAPTIC) ]--;
if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_HAPTIC) ] == 0 )
{
if ((flags & SDL_INIT_HAPTIC)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_HAPTIC)) {
SDL_HapticQuit();
SDL_initialized &= ~SDL_INIT_HAPTIC;
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_HAPTIC);
}
#endif
#if !SDL_AUDIO_DISABLED
if ((flags & SDL_initialized & SDL_INIT_AUDIO)) {
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_AUDIO) ]--;
if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_AUDIO) ] == 0 )
{
if ((flags & SDL_INIT_AUDIO)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_AUDIO)) {
SDL_AudioQuit();
SDL_initialized &= ~SDL_INIT_AUDIO;
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_AUDIO);
}
#endif
#if !SDL_VIDEO_DISABLED
if ((flags & SDL_initialized & SDL_INIT_VIDEO)) {
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_VIDEO) ]--;
if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_VIDEO) ] == 0 )
{
if ((flags & SDL_INIT_VIDEO)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_VIDEO)) {
SDL_VideoQuit();
SDL_initialized &= ~SDL_INIT_VIDEO;
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_VIDEO);
}
#endif
#if !SDL_TIMERS_DISABLED
if ((flags & SDL_initialized & SDL_INIT_TIMER)) {
SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_TIMER) ]--;
if ( SDL_bInMainQuit || SDL_SubsystemRefCount[ msb32_idx(SDL_INIT_TIMER) ] == 0 )
{
if ((flags & SDL_INIT_TIMER)) {
if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_TIMER)) {
SDL_TimerQuit();
SDL_initialized &= ~SDL_INIT_TIMER;
}
SDL_PrivateSubsystemRefCountDecr(SDL_INIT_TIMER);
}
#endif
}
@@ -271,16 +278,33 @@ SDL_QuitSubSystem(Uint32 flags)
Uint32
SDL_WasInit(Uint32 flags)
{
int i;
int num_subsystems = SDL_arraysize(SDL_SubsystemRefCount);
Uint32 initialized = 0;
if (!flags) {
flags = SDL_INIT_EVERYTHING;
}
return (SDL_initialized & flags);
num_subsystems = SDL_min(num_subsystems, SDL_MostSignificantBitIndex32(flags) + 1);
/* Iterate over each bit in flags, and check the matching subsystem. */
for (i = 0; i < num_subsystems; ++i) {
if ((flags & 1) && SDL_SubsystemRefCount[i] > 0) {
initialized |= (1 << i);
}
flags >>= 1;
}
return initialized;
}
void
SDL_Quit(void)
{
SDL_bInMainQuit = SDL_TRUE;
SDL_bInMainQuit = SDL_TRUE;
/* Quit all subsystems */
#if defined(__WIN32__)
SDL_HelperWindowDestroy();
@@ -294,8 +318,12 @@ SDL_Quit(void)
SDL_AssertionsQuit();
SDL_LogResetPriorities();
SDL_memset( SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount) );
SDL_bInMainQuit = SDL_FALSE;
/* Now that every subsystem has been quit, we reset the subsystem refcount
* and the list of initialized subsystems.
*/
SDL_memset( SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount) );
SDL_bInMainQuit = SDL_FALSE;
}
/* Get the library version number */