src/SDL.c
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Tue, 12 Feb 2013 11:47:31 -0800
changeset 6866 e74a4b282450
parent 6690 9548c8a58103
child 6867 4c899e841091
permissions -rw-r--r--
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.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 /* Initialization code for SDL */
    24 
    25 #include "SDL.h"
    26 #include "SDL_bits.h"
    27 #include "SDL_revision.h"
    28 #include "SDL_fatal.h"
    29 #include "SDL_assert_c.h"
    30 #include "haptic/SDL_haptic_c.h"
    31 #include "joystick/SDL_joystick_c.h"
    32 
    33 /* Initialization/Cleanup routines */
    34 #if !SDL_TIMERS_DISABLED
    35 extern void SDL_StartTicks(void);
    36 extern int SDL_TimerInit(void);
    37 extern void SDL_TimerQuit(void);
    38 #endif
    39 #if defined(__WIN32__)
    40 extern int SDL_HelperWindowCreate(void);
    41 extern int SDL_HelperWindowDestroy(void);
    42 #endif
    43 
    44 
    45 /* The initialized subsystems */
    46 static Uint32 ticks_started = 0;
    47 static SDL_bool SDL_bInMainQuit = SDL_FALSE;
    48 static Uint8 SDL_SubsystemRefCount[ 32 ];
    49 
    50 /* Private helper to increment a subsystem's ref counter. */
    51 static void SDL_PrivateSubsystemRefCountIncr(Uint32 subsystem)
    52 {
    53     int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
    54     SDL_assert(SDL_SubsystemRefCount[subsystem_index] < 255);
    55     ++SDL_SubsystemRefCount[subsystem_index];
    56 }
    57 
    58 /* Private helper to decrement a subsystem's ref counter. */
    59 void SDL_PrivateSubsystemRefCountDecr(Uint32 subsystem)
    60 {
    61     int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
    62     if (SDL_SubsystemRefCount[subsystem_index] > 0) {
    63         --SDL_SubsystemRefCount[subsystem_index];
    64     }
    65 }
    66 
    67 /* Private helper to check if a system needs init. */
    68 static SDL_bool
    69 SDL_PrivateShouldInitSubsystem(Uint32 flags, Uint32 subsystem)
    70 {
    71     if ((flags & subsystem) == 0) {
    72       return SDL_FALSE;
    73     }
    74 
    75     int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
    76     SDL_assert(SDL_SubsystemRefCount[subsystem_index] < 255);
    77     return (SDL_SubsystemRefCount[subsystem_index] == 0);
    78 }
    79 
    80 /* Private helper to check if a system needs to be quit. */
    81 static SDL_bool
    82 SDL_PrivateShouldQuitSubsystem(Uint32 subsystem) {
    83     int subsystem_index = SDL_MostSignificantBitIndex32(subsystem);
    84     if (SDL_SubsystemRefCount[subsystem_index] == 0) {
    85       return SDL_FALSE;
    86     }
    87 
    88     /* If we're in SDL_Quit, we shut down every subsystem, even if refcount
    89      * isn't zero.
    90      */
    91     return SDL_SubsystemRefCount[subsystem_index] == 1 || SDL_bInMainQuit;
    92 }
    93 
    94 int
    95 SDL_InitSubSystem(Uint32 flags)
    96 {
    97 #if !SDL_TIMERS_DISABLED
    98     if (!ticks_started) {
    99         SDL_StartTicks();
   100         ticks_started = 1;
   101     }
   102 #endif
   103 
   104     /* Initialize the timer subsystem */
   105     if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_TIMER)) {
   106 #if !SDL_TIMERS_DISABLED
   107         if (SDL_TimerInit() < 0) {
   108             return (-1);
   109         }
   110         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_TIMER);
   111 #else
   112         SDL_SetError("SDL not built with timer support");
   113         return (-1);
   114 #endif
   115     }
   116 
   117     /* Initialize the video/event subsystem */
   118     if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_VIDEO)) {
   119 #if !SDL_VIDEO_DISABLED
   120         if (SDL_VideoInit(NULL) < 0) {
   121             return (-1);
   122         }
   123         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_VIDEO);
   124 #else
   125         SDL_SetError("SDL not built with video support");
   126         return (-1);
   127 #endif
   128     }
   129 
   130     /* Initialize the audio subsystem */
   131     if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_AUDIO)) {
   132 #if !SDL_AUDIO_DISABLED
   133         if (SDL_AudioInit(NULL) < 0) {
   134             return (-1);
   135         }
   136         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_AUDIO);
   137 #else
   138         SDL_SetError("SDL not built with audio support");
   139         return (-1);
   140 #endif
   141     }
   142 
   143     if ((flags & SDL_INIT_GAMECONTROLLER)) {
   144         // Game controller implies Joystick.
   145         flags |= SDL_INIT_JOYSTICK;
   146     }
   147 
   148     /* Initialize the joystick subsystem */
   149     if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_JOYSTICK)) {
   150 #if !SDL_JOYSTICK_DISABLED
   151         if (SDL_JoystickInit() < 0) {
   152             return (-1);
   153         }
   154         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_JOYSTICK);
   155 #else
   156         SDL_SetError("SDL not built with joystick support");
   157         return (-1);
   158 #endif
   159     }
   160 
   161     if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_GAMECONTROLLER)) {
   162 #if !SDL_JOYSTICK_DISABLED
   163         if (SDL_GameControllerInit() < 0) {
   164             return (-1);
   165         }
   166         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_GAMECONTROLLER);
   167 #else
   168         SDL_SetError("SDL not built with joystick support");
   169         return (-1);
   170 #endif
   171     }
   172 
   173     /* Initialize the haptic subsystem */
   174     if (SDL_PrivateShouldInitSubsystem(flags, SDL_INIT_HAPTIC)) {
   175 #if !SDL_HAPTIC_DISABLED
   176         if (SDL_HapticInit() < 0) {
   177             return (-1);
   178         }
   179         SDL_PrivateSubsystemRefCountIncr(SDL_INIT_HAPTIC);
   180 #else
   181         SDL_SetError("SDL not built with haptic (force feedback) support");
   182         return (-1);
   183 #endif
   184     }
   185 
   186     return (0);
   187 }
   188 
   189 int
   190 SDL_Init(Uint32 flags)
   191 {
   192     if (SDL_AssertionsInit() < 0) {
   193         return -1;
   194     }
   195 
   196     /* Clear the error message */
   197     SDL_ClearError();
   198 
   199 #if defined(__WIN32__)
   200     if (SDL_HelperWindowCreate() < 0) {
   201         return -1;
   202     }
   203 #endif
   204 
   205     /* Initialize the desired subsystems */
   206     if (SDL_InitSubSystem(flags) < 0) {
   207         return (-1);
   208     }
   209 
   210     /* Everything is initialized */
   211     if (!(flags & SDL_INIT_NOPARACHUTE)) {
   212         SDL_InstallParachute();
   213     }
   214 
   215     return (0);
   216 }
   217 
   218 void
   219 SDL_QuitSubSystem(Uint32 flags)
   220 {
   221     /* Shut down requested initialized subsystems */
   222 #if !SDL_JOYSTICK_DISABLED
   223     if ((flags & SDL_INIT_GAMECONTROLLER)) {
   224         // Game controller implies Joystick.
   225         flags |= SDL_INIT_JOYSTICK;
   226 
   227         if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_GAMECONTROLLER)) {
   228             SDL_GameControllerQuit();
   229 		}
   230         SDL_PrivateSubsystemRefCountDecr(SDL_INIT_GAMECONTROLLER);
   231     }
   232 
   233     if ((flags & SDL_INIT_JOYSTICK)) {
   234         if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_JOYSTICK)) {
   235 			SDL_JoystickQuit();
   236 		}
   237         SDL_PrivateSubsystemRefCountDecr(SDL_INIT_JOYSTICK);
   238     }
   239 #endif
   240 
   241 #if !SDL_HAPTIC_DISABLED
   242     if ((flags & SDL_INIT_HAPTIC)) {
   243         if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_HAPTIC)) {
   244 			SDL_HapticQuit();
   245 		}
   246         SDL_PrivateSubsystemRefCountDecr(SDL_INIT_HAPTIC);
   247     }
   248 #endif
   249 
   250 #if !SDL_AUDIO_DISABLED
   251     if ((flags & SDL_INIT_AUDIO)) {
   252         if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_AUDIO)) {
   253 			SDL_AudioQuit();
   254 		}
   255         SDL_PrivateSubsystemRefCountDecr(SDL_INIT_AUDIO);
   256     }
   257 #endif
   258 
   259 #if !SDL_VIDEO_DISABLED
   260     if ((flags & SDL_INIT_VIDEO)) {
   261         if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_VIDEO)) {
   262 			SDL_VideoQuit();
   263 		}
   264         SDL_PrivateSubsystemRefCountDecr(SDL_INIT_VIDEO);
   265     }
   266 #endif
   267 
   268 #if !SDL_TIMERS_DISABLED
   269     if ((flags & SDL_INIT_TIMER)) {
   270         if (SDL_PrivateShouldQuitSubsystem(SDL_INIT_TIMER)) {
   271 			SDL_TimerQuit();
   272 		}
   273         SDL_PrivateSubsystemRefCountDecr(SDL_INIT_TIMER);
   274     }
   275 #endif
   276 }
   277 
   278 Uint32
   279 SDL_WasInit(Uint32 flags)
   280 {
   281     int i;
   282     int num_subsystems = SDL_arraysize(SDL_SubsystemRefCount);
   283     Uint32 initialized = 0;
   284 
   285     if (!flags) {
   286         flags = SDL_INIT_EVERYTHING;
   287     }
   288 
   289     num_subsystems = SDL_min(num_subsystems, SDL_MostSignificantBitIndex32(flags) + 1);
   290 
   291     /* Iterate over each bit in flags, and check the matching subsystem. */
   292     for (i = 0; i < num_subsystems; ++i) {
   293         if ((flags & 1) && SDL_SubsystemRefCount[i] > 0) {
   294             initialized |= (1 << i);
   295         }
   296 
   297         flags >>= 1;
   298     }
   299 
   300     return initialized;
   301 }
   302 
   303 void
   304 SDL_Quit(void)
   305 {
   306     SDL_bInMainQuit = SDL_TRUE;
   307 
   308     /* Quit all subsystems */
   309 #if defined(__WIN32__)
   310     SDL_HelperWindowDestroy();
   311 #endif
   312     SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
   313 
   314     /* Uninstall any parachute signal handlers */
   315     SDL_UninstallParachute();
   316 
   317     SDL_ClearHints();
   318     SDL_AssertionsQuit();
   319     SDL_LogResetPriorities();
   320 
   321     /* Now that every subsystem has been quit, we reset the subsystem refcount
   322      * and the list of initialized subsystems.
   323      */
   324     SDL_memset( SDL_SubsystemRefCount, 0x0, sizeof(SDL_SubsystemRefCount) );
   325 
   326     SDL_bInMainQuit = SDL_FALSE;
   327 }
   328 
   329 /* Get the library version number */
   330 void
   331 SDL_GetVersion(SDL_version * ver)
   332 {
   333     SDL_VERSION(ver);
   334 }
   335 
   336 /* Get the library source revision */
   337 const char *
   338 SDL_GetRevision(void)
   339 {
   340     return SDL_REVISION;
   341 }
   342 
   343 /* Get the library source revision number */
   344 int
   345 SDL_GetRevisionNumber(void)
   346 {
   347     return SDL_REVISION_NUMBER;
   348 }
   349 
   350 /* Get the name of the platform */
   351 const char *
   352 SDL_GetPlatform()
   353 {
   354 #if __AIX__
   355     return "AIX";
   356 #elif __ANDROID__
   357     return "Android";
   358 #elif __HAIKU__
   359 /* Haiku must appear here before BeOS, since it also defines __BEOS__ */
   360     return "Haiku";
   361 #elif __BEOS__
   362     return "BeOS";
   363 #elif __BSDI__
   364     return "BSDI";
   365 #elif __DREAMCAST__
   366     return "Dreamcast";
   367 #elif __FREEBSD__
   368     return "FreeBSD";
   369 #elif __HPUX__
   370     return "HP-UX";
   371 #elif __IRIX__
   372     return "Irix";
   373 #elif __LINUX__
   374     return "Linux";
   375 #elif __MINT__
   376     return "Atari MiNT";
   377 #elif __MACOS__
   378     return "MacOS Classic";
   379 #elif __MACOSX__
   380     return "Mac OS X";
   381 #elif __NETBSD__
   382     return "NetBSD";
   383 #elif __NDS__
   384     return "Nintendo DS";
   385 #elif __OPENBSD__
   386     return "OpenBSD";
   387 #elif __OS2__
   388     return "OS/2";
   389 #elif __OSF__
   390     return "OSF/1";
   391 #elif __QNXNTO__
   392     return "QNX Neutrino";
   393 #elif __RISCOS__
   394     return "RISC OS";
   395 #elif __SOLARIS__
   396     return "Solaris";
   397 #elif __WIN32__
   398     return "Windows";
   399 #elif __IPHONEOS__
   400     return "iPhone OS";
   401 #else
   402     return "Unknown (see SDL_platform.h)";
   403 #endif
   404 }
   405 
   406 #if defined(__WIN32__)
   407 
   408 #if !defined(HAVE_LIBC) || (defined(__WATCOMC__) && defined(BUILD_DLL))
   409 /* Need to include DllMain() on Watcom C for some reason.. */
   410 #include "core/windows/SDL_windows.h"
   411 
   412 BOOL APIENTRY
   413 _DllMainCRTStartup(HANDLE hModule,
   414                    DWORD ul_reason_for_call, LPVOID lpReserved)
   415 {
   416     switch (ul_reason_for_call) {
   417     case DLL_PROCESS_ATTACH:
   418     case DLL_THREAD_ATTACH:
   419     case DLL_THREAD_DETACH:
   420     case DLL_PROCESS_DETACH:
   421         break;
   422     }
   423     return TRUE;
   424 }
   425 #endif /* building DLL with Watcom C */
   426 
   427 #endif /* __WIN32__ */
   428 
   429 /* vi: set ts=4 sw=4 expandtab: */