diff --git a/apps/code/editor_controller.cpp b/apps/code/editor_controller.cpp index b048e0e21..ff79cc961 100644 --- a/apps/code/editor_controller.cpp +++ b/apps/code/editor_controller.cpp @@ -4,8 +4,7 @@ #include "variable_box_controller.h" #include #include - -extern Ion::Storage storage; +#include namespace Code { @@ -28,7 +27,7 @@ void EditorController::setScript(Script script) { m_script = script; const char * scriptBody = m_script.readContent(); size_t scriptBodySize = strlen(scriptBody)+1; - size_t availableScriptSize = scriptBodySize + storage.availableSize(); + size_t availableScriptSize = scriptBodySize + Ion::Storage::sharedStorage()->availableSize(); assert(m_areaBuffer == nullptr); m_areaBuffer = new char[availableScriptSize]; strlcpy(m_areaBuffer, scriptBody, scriptBodySize); diff --git a/apps/code/script_store.cpp b/apps/code/script_store.cpp index 53e7d7cd2..e9677930c 100644 --- a/apps/code/script_store.cpp +++ b/apps/code/script_store.cpp @@ -26,7 +26,7 @@ void ScriptStore::deleteAllScripts() { } bool ScriptStore::isFull() { - return (numberOfScripts() >= k_maxNumberOfScripts || storage.availableSize() < k_fullFreeSpaceSizeLimit); + return (numberOfScripts() >= k_maxNumberOfScripts || Ion::Storage::sharedStorage()->availableSize() < k_fullFreeSpaceSizeLimit); } void ScriptStore::scanScriptsForFunctionsAndVariables(void * context, ScanCallback storeFunction, ScanCallback storeVariable) { @@ -124,7 +124,7 @@ Script::ErrorStatus ScriptStore::addScriptFromTemplate(const ScriptTemplate * sc char * body = new char[scriptSize+Script::k_importationStatusSize]; body[0] = 1; strlcpy(body+Script::k_importationStatusSize, scriptTemplate->content(), scriptSize); - Script::ErrorStatus err = storage.createRecord(scriptTemplate->name(), body, scriptSize+Script::k_importationStatusSize); + Script::ErrorStatus err = Ion::Storage::sharedStorage()->createRecord(scriptTemplate->name(), body, scriptSize+Script::k_importationStatusSize); assert(err != Script::ErrorStatus::NonCompliantName); delete[] body; return err; diff --git a/apps/code/script_store.h b/apps/code/script_store.h index db37bd48d..d862d1791 100644 --- a/apps/code/script_store.h +++ b/apps/code/script_store.h @@ -1,6 +1,7 @@ #ifndef CODE_SCRIPT_STORE_H #define CODE_SCRIPT_STORE_H +#include #include "script.h" #include "script_template.h" #include @@ -8,8 +9,6 @@ extern "C" { #include "py/parse.h" } -extern Ion::Storage storage; - namespace Code { class ScriptStore : public MicroPython::ScriptProvider { @@ -20,13 +19,13 @@ public: ScriptStore(); Script scriptAtIndex(int index) { - return Script(storage.recordWithExtensionAtIndex(k_scriptExtension, index)); + return Script(Ion::Storage::sharedStorage()->recordWithExtensionAtIndex(k_scriptExtension, index)); } Script scriptNamed(const char * name) { - return Script(storage.recordNamed(name)); + return Script(Ion::Storage::sharedStorage()->recordNamed(name)); } int numberOfScripts() { - return storage.numberOfRecordsWithExtension(k_scriptExtension); + return Ion::Storage::sharedStorage()->numberOfRecordsWithExtension(k_scriptExtension); } Ion::Storage::Record::ErrorStatus addNewScript() { return addScriptFromTemplate(ScriptTemplate::Empty()); diff --git a/ion/include/ion/storage.h b/ion/include/ion/storage.h index 97b0356fe..23535d156 100644 --- a/ion/include/ion/storage.h +++ b/ion/include/ion/storage.h @@ -5,19 +5,12 @@ namespace Ion { -class Storage; - -} - -extern Ion::Storage storage; - -namespace Ion { - /* Storage : | Magic | Record1 | Record2 | ... | MagicĀ | * | Magic | Size1(uint16_t) | Name1 | Body1 | Size2(uint16_t) | Name2 | Body2 | ... | Magic */ class Storage { public: + static Storage * sharedStorage(); class Record { /* A Record is identified by the CRC32 on his name because: * - a record is identified by its name which is unique @@ -46,19 +39,19 @@ public: return m_nameCRC32 == 0; } const char * name() const { - return storage.nameOfRecord(*this); + return Storage::sharedStorage()->nameOfRecord(*this); } ErrorStatus setName(const char * name) { - return storage.setNameOfRecord(*this, name); + return Storage::sharedStorage()->setNameOfRecord(*this, name); } Data value() const { - return storage.valueOfRecord(*this); + return Storage::sharedStorage()->valueOfRecord(*this); } ErrorStatus setValue(Data data) { - return storage.setValueOfRecord(*this, data); + return Storage::sharedStorage()->setValueOfRecord(*this, data); } void destroy() { - return storage.destroyRecord(*this); + return Storage::sharedStorage()->destroyRecord(*this); } private: uint32_t m_nameCRC32; diff --git a/ion/src/shared/platform_info.cpp b/ion/src/shared/platform_info.cpp index 8d7fcbffb..ecebcc1a7 100644 --- a/ion/src/shared/platform_info.cpp +++ b/ion/src/shared/platform_info.cpp @@ -13,7 +13,10 @@ #define HEADER_SECTION #endif -extern Ion::Storage storage; +namespace Ion { +extern char staticStorageArea[]; +} +constexpr void * storageAddress = &(Ion::staticStorageArea); class PlatformInfo { public: @@ -21,7 +24,7 @@ public: m_header(Magic), m_version{EPSILON_VERSION}, m_patchLevel{PATCH_LEVEL}, - m_storageAddress(&storage), + m_storageAddress(storageAddress), m_footer(Magic) { } const char * version() const { assert(m_storageAddress != nullptr); diff --git a/ion/src/shared/storage.cpp b/ion/src/shared/storage.cpp index a551dbf11..f8ad21584 100644 --- a/ion/src/shared/storage.cpp +++ b/ion/src/shared/storage.cpp @@ -1,11 +1,31 @@ #include #include #include - -Ion::Storage storage; +#include namespace Ion { +/* We want to implement a simple singleton pattern, to make sure the storage is + * initialized on first use, therefore preventing the static init order fiasco. + * That being said, we rely on knowing where the storage resides in the device's + * memory at compile time. Indeed, we want to advertise the static storage's + * memory address in the PlatformInfo structure (so that we can read and write + * it in DFU). + * Using a "static Storage storage;" variable makes it a local symbol at best, + * preventing the PlatformInfo from retrieving its address. And making the + * Storage variable global yields the static init fiasco issue. We're working + * around both issues by creating a global staticStorageArea buffer, and by + * placement-newing the Storage into that area on first use. */ + +char staticStorageArea[sizeof(Storage)] = {0}; +Storage * Storage::sharedStorage() { + static Storage * storage = nullptr; + if (storage == nullptr) { + storage = new (staticStorageArea) Storage(); + } + return storage; +} + Storage::Record::Record(const char * name) { if (name == nullptr) { m_nameCRC32 = 0;