Ticket #500: atlas-threading-osxfix-08282011.patch

File atlas-threading-osxfix-08282011.patch, 5.5 KB (added by historic_bruno, 13 years ago)
  • source/tools/atlas/GameInterface/GameLoop.cpp

     
    1 /* Copyright (C) 2010 Wildfire Games.
     1/* Copyright (C) 2011 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    7373static GameLoopState state;
    7474GameLoopState* g_GameLoop = &state;
    7575
    76 static void* LaunchWindow(void* data)
    77 {
    78     debug_SetThreadName("atlas_window");
    7976
    80     const wchar_t* windowName = reinterpret_cast<const wchar_t*>(data);
    81     Atlas_StartWindow(windowName);
    82     return NULL;
    83 }
    84 
    85 // Work out which Atlas window to launch, given the command-line arguments
    86 static const wchar_t* FindWindowName(const CmdLineArgs& UNUSED(args))
    87 {
    88     return L"ScenarioEditor";
    89     // (This is a bit pointless - there's no choice since we've deleted the ActorViewer)
    90 }
    91 
    9277static ErrorReactionInternal AtlasDisplayError(const wchar_t* text, size_t flags)
    9378{
    9479    // TODO: after Atlas has been unloaded, don't do this
     
    11499    while (more && timer_Time() - startTime < maxTime);
    115100}
    116101
    117 bool BeginAtlas(const CmdLineArgs& args, const DllLoader& dll)
     102static void* RunGame(void *data)
    118103{
    119     // Load required symbols from the DLL
    120     try
    121     {
    122         dll.LoadSymbol("Atlas_StartWindow", Atlas_StartWindow);
    123         dll.LoadSymbol("Atlas_SetMessagePasser", Atlas_SetMessagePasser);
    124         dll.LoadSymbol("Atlas_SetDataDirectory", Atlas_SetDataDirectory);
    125         dll.LoadSymbol("Atlas_GLSetCurrent", Atlas_GLSetCurrent);
    126         dll.LoadSymbol("Atlas_GLSwapBuffers", Atlas_GLSwapBuffers);
    127         dll.LoadSymbol("Atlas_NotifyEndOfFrame", Atlas_NotifyEndOfFrame);
    128         dll.LoadSymbol("Atlas_DisplayError", Atlas_DisplayError);
    129         dll.LoadSymbol("Atlas_ReportError", Atlas_ReportError);
    130         dll.LoadSymbol("ShareableMalloc", ShareableMallocFptr);
    131         dll.LoadSymbol("ShareableFree", ShareableFreeFptr);
    132     }
    133     catch (PSERROR_DllLoader&)
    134     {
    135         debug_warn(L"Failed to initialise DLL");
    136         return false;
    137     }
     104    debug_SetThreadName("game_thread");
    138105
    139     // Construct a message passer for communicating with Atlas
    140     MessagePasserImpl msgPasser;
    141     AtlasMessage::g_MessagePasser = &msgPasser;
     106    // Set new main thread so that all the thread-safety checks pass
     107    ThreadUtil::SetMainThread();
    142108
    143     // Pass our message handler to Atlas
    144     Atlas_SetMessagePasser(&msgPasser);
     109    const CmdLineArgs args = *reinterpret_cast<const CmdLineArgs*>(data);
    145110
    146     // Tell Atlas the location of the data directory
    147     const Paths paths(args);
    148     Atlas_SetDataDirectory(paths.RData().string().c_str());
     111    MessagePasserImpl* msgPasser = (MessagePasserImpl*)AtlasMessage::g_MessagePasser;   
    149112
    150113    // Register all the handlers for message which might be passed back
    151114    RegisterHandlers();
    152 
    153     // Create a new thread, and launch the Atlas window inside that thread
    154     const wchar_t* windowName = FindWindowName(args);
    155     pthread_t uiThread;
    156     pthread_create(&uiThread, NULL, LaunchWindow, reinterpret_cast<void*>(const_cast<wchar_t*>(windowName)));
    157 
     115   
    158116    // Override ah_display_error to pass all errors to the Atlas UI
    159117    AppHooks hooks = {0};
    160118    hooks.display_error = AtlasDisplayError;
     
    199157       
    200158        {
    201159            IMessage* msg;
    202             while ((msg = msgPasser.Retrieve()) != NULL)
     160            while ((msg = msgPasser->Retrieve()) != NULL)
    203161            {
    204162                recent_activity = true;
    205163
     
    294252                // (TODO: This should probably be done with something like semaphores)
    295253                Atlas_NotifyEndOfFrame(); // (TODO: rename to NotifyEndOfQuiteShortProcessingPeriodSoPleaseSendMeNewMessages or something)
    296254                SDL_Delay(50);
    297                 if (!msgPasser.IsEmpty())
     255                if (!msgPasser->IsEmpty())
    298256                    break;
    299257                time = timer_Time();
    300258            }
     
    306264        }
    307265    }
    308266
     267    return NULL;
     268}
     269
     270bool BeginAtlas(const CmdLineArgs& args, const DllLoader& dll)
     271{
     272    // Load required symbols from the DLL
     273    try
     274    {
     275        dll.LoadSymbol("Atlas_StartWindow", Atlas_StartWindow);
     276        dll.LoadSymbol("Atlas_SetMessagePasser", Atlas_SetMessagePasser);
     277        dll.LoadSymbol("Atlas_SetDataDirectory", Atlas_SetDataDirectory);
     278        dll.LoadSymbol("Atlas_GLSetCurrent", Atlas_GLSetCurrent);
     279        dll.LoadSymbol("Atlas_GLSwapBuffers", Atlas_GLSwapBuffers);
     280        dll.LoadSymbol("Atlas_NotifyEndOfFrame", Atlas_NotifyEndOfFrame);
     281        dll.LoadSymbol("Atlas_DisplayError", Atlas_DisplayError);
     282        dll.LoadSymbol("Atlas_ReportError", Atlas_ReportError);
     283        dll.LoadSymbol("ShareableMalloc", ShareableMallocFptr);
     284        dll.LoadSymbol("ShareableFree", ShareableFreeFptr);
     285    }
     286    catch (PSERROR_DllLoader&)
     287    {
     288        debug_warn(L"Failed to initialise DLL");
     289        return false;
     290    }
     291
     292    // Construct a message passer for communicating with Atlas
     293    // (here so that it's scope lasts beyond the game thread)
     294    MessagePasserImpl msgPasser;
     295    AtlasMessage::g_MessagePasser = &msgPasser;
     296
     297    // Pass our message handler to Atlas
     298    Atlas_SetMessagePasser(&msgPasser);
     299
     300    // Tell Atlas the location of the data directory
     301    const Paths paths(args);
     302    Atlas_SetDataDirectory(paths.RData().string().c_str());
     303
     304    // run the rest of the engine in a new thread
     305    pthread_t engineThread;
     306    pthread_create(&engineThread, NULL, RunGame, reinterpret_cast<void*>(const_cast<CmdLineArgs*>(&args)));
     307
     308    // start Atlas UI on main thread
     309    Atlas_StartWindow(L"ScenarioEditor");
     310
     311    // Wait for the engine to exit
     312    pthread_join(engineThread, NULL);
     313
    309314    // TODO: delete all remaining messages, to avoid memory leak warnings
    310315
    311     // Wait for the UI to exit
    312     pthread_join(uiThread, NULL);
     316    // Restore main thread
     317    ThreadUtil::SetMainThread();
    313318
    314319    // Clean up
    315320    View::DestroyViews();