Ticket #3708: JS_ShutDown_SVN_1.0.diff

File JS_ShutDown_SVN_1.0.diff, 7.6 KB (added by Yves, 8 years ago)

JS_Shutdown patch for SVN with validation and RAII approach

  • source/main.cpp

     
    7373#include "graphics/TextureManager.h"
    7474#include "gui/GUIManager.h"
    7575#include "renderer/Renderer.h"
     76#include "scriptinterface/ScriptEngine.h"
    7677#include "simulation2/Simulation2.h"
    7778
    7879#if OS_UNIX
     
    422423        return;
    423424    }
    424425
    425     // We need to initialise libxml2 in the main thread before
    426     // any thread uses it. So initialise it here before we
    427     // might run Atlas.
     426    // We need to initialize libxml2 and SpiderMonkey in the main thread before
     427    // any thread uses them. So initialize them here before we might run Atlas.
    428428    CXeromyces::Startup();
     429    ScriptEngine scriptEngine;
    429430
    430431    // Atlas handles the whole init/shutdown/etc sequence by itself;
    431432    if (ATLAS_RunIfOnCmdLine(args, false))
  • source/scriptinterface/ScriptEngine.h

     
     1/* Copyright (C) 2016 Wildfire Games.
     2 * This file is part of 0 A.D.
     3 *
     4 * 0 A.D. is free software: you can redistribute it and/or modify
     5 * it under the terms of the GNU General Public License as published by
     6 * the Free Software Foundation, either version 2 of the License, or
     7 * (at your option) any later version.
     8 *
     9 * 0 A.D. is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 * GNU General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU General Public License
     15 * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
     16 */
     17
     18#ifndef INCLUDED_SCRIPTENGINE
     19#define INCLUDED_SCRIPTENGINE
     20
     21#include "ScriptTypes.h"
     22#include "ps/Singleton.h"
     23
     24/**
     25 * A class using the RAII (Resource Acquisition Is Initialization) idiom to manage initialization
     26 * and shutdown of the SpiderMonkey script engine. It also keeps a count of active script runtimes
     27 * in order to validate the following constraints:
     28 *  1. JS_Init must be called before any ScriptRuntimes are initialized
     29 *  2. JS_Shutdown must be called after all ScriptRuntimes have been destroyed
     30 */
     31
     32class ScriptEngine : public Singleton<ScriptEngine>
     33{
     34public:
     35    ScriptEngine()
     36    {
     37        ENSURE(m_Runtimes.size() == 0 && "JS_Init must be called before any runtimes are created!");
     38        JS_Init();
     39    }
     40
     41    ~ScriptEngine()
     42    {
     43        ENSURE(m_Runtimes.size() == 0 && "All runtimes must be destroyed before calling JS_ShutDown!");
     44        JS_ShutDown();
     45    }
     46
     47    void RegisterRuntime(const JSRuntime* rt) { m_Runtimes.push_back(rt); }
     48    void UnRegisterRuntime(const JSRuntime* rt) { m_Runtimes.remove(rt); }
     49
     50private:
     51
     52    std::list<const JSRuntime*> m_Runtimes;
     53};
     54
     55#endif // INCLUDED_SCRIPTENGINE
  • source/scriptinterface/ScriptInterface.cpp

     
    433433    }
    434434}
    435435
    436 void ScriptInterface::ShutDown()
    437 {
    438     JS_ShutDown();
    439 }
    440 
    441436void ScriptInterface::SetCallbackData(void* pCBData)
    442437{
    443438    m_CxPrivate.pCBData = pCBData;
  • source/scriptinterface/ScriptInterface.h

     
    9797
    9898    ~ScriptInterface();
    9999
    100     /**
    101      * Shut down the JS system to clean up memory. Must only be called when there
    102      * are no ScriptInterfaces alive.
    103      */
    104     static void ShutDown();
    105 
    106100    struct CxPrivate
    107101    {
    108102        ScriptInterface* pScriptInterface; // the ScriptInterface object the current context belongs to
  • source/scriptinterface/ScriptRuntime.cpp

     
    2121
    2222#include "ps/GameSetup/Config.h"
    2323#include "ps/Profile.h"
     24#include "scriptinterface/ScriptEngine.h"
    2425
    2526
    2627void GCSliceCallbackHook(JSRuntime* UNUSED(rt), JS::GCProgress progress, const JS::GCDescription& UNUSED(desc))
     
    104105    m_FinalizationListObjectIdCache.push_back(obj);
    105106}
    106107
    107 bool ScriptRuntime::m_Initialized = false;
    108 
    109108ScriptRuntime::ScriptRuntime(shared_ptr<ScriptRuntime> parentRuntime, int runtimeSize, int heapGrowthBytesGCTrigger):
    110109    m_LastGCBytes(0),
    111110    m_LastGCCheck(0.0f),
     
    112111    m_HeapGrowthBytesGCTrigger(heapGrowthBytesGCTrigger),
    113112    m_RuntimeSize(runtimeSize)
    114113{
    115     if (!m_Initialized)
    116     {
    117         ENSURE(JS_Init());
    118         m_Initialized = true;
    119     }
     114    ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be initialized before constructing any ScriptRuntimes!");
    120115
    121116    JSRuntime* parentJSRuntime = parentRuntime ? parentRuntime->m_rt : nullptr;
    122117    m_rt = JS_NewRuntime(runtimeSize, JS_USE_HELPER_THREADS, parentJSRuntime);
     
    135130   
    136131    m_dummyContext = JS_NewContext(m_rt, STACK_CHUNK_SIZE);
    137132    ENSURE(m_dummyContext);
     133
     134    ScriptEngine::GetSingleton().RegisterRuntime(m_rt);
    138135}
    139136
    140137ScriptRuntime::~ScriptRuntime()
     
    143140    JS_SetGCCallback(m_rt, nullptr, nullptr);
    144141    JS_DestroyRuntime(m_rt);
    145142    ENSURE(m_FinalizationListObjectIdCache.empty() && "Leak: Removing callback while some objects still aren't finalized!");
     143
     144    ENSURE(ScriptEngine::IsInitialised() && "The ScriptEngine must be active (initiaized and not yet shut down) when destroying a ScriptRuntime!");
     145    ScriptEngine::GetSingleton().UnRegisterRuntime(m_rt);
    146146}
    147147
    148148void ScriptRuntime::RegisterContext(JSContext* cx)
  • source/scriptinterface/ScriptRuntime.h

     
    7979   
    8080    std::list<JSContext*> m_Contexts;
    8181    std::vector<std::shared_ptr<void> > m_FinalizationListObjectIdCache;
    82     static bool m_Initialized;
    8382
    8483    int m_RuntimeSize;
    8584    int m_HeapGrowthBytesGCTrigger;
  • source/test_setup.cpp

     
    1 /* Copyright (C) 2014 Wildfire Games.
     1/* Copyright (C) 2016 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
     
    3636#include "lib/timer.h"
    3737#include "lib/sysdep/sysdep.h"
    3838#include "ps/Profiler2.h"
     39#include "scriptinterface/ScriptEngine.h"
    3940#include "scriptinterface/ScriptInterface.h"
    4041
    4142class LeakReporter : public CxxTest::GlobalFixture
     
    4243{
    4344    virtual bool tearDownWorld()
    4445    {
    45         // Shut down JS to prevent leak reports from it
    46         ScriptInterface::ShutDown();
    47 
    4846        // Enable leak reporting on exit.
    4947        // (This is done in tearDownWorld so that it doesn't report 'leaks'
    5048        // if the program is aborted before finishing cleanly.)
     
    8179        ThreadUtil::SetMainThread();
    8280
    8381        g_Profiler2.Initialise();
     82        m_ScriptEngine = new ScriptEngine;
    8483        g_ScriptRuntime = ScriptInterface::CreateRuntime();
    8584
    8685        return true;
     
    8988    virtual bool tearDownWorld()
    9089    {
    9190        g_ScriptRuntime.reset();
     91        delete m_ScriptEngine;
    9292        g_Profiler2.Shutdown();
    9393
    9494        return true;
    9595    }
     96
     97private:
     98
     99    // We're doing the initialization and shutdown of the ScriptEngine explicitly here
     100    // to make sure it's only initialized when setUpWorld is called.
     101    ScriptEngine* m_ScriptEngine;
    96102};
    97103
    98104static LeakReporter leakReporter;