diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/makefile | 3 | ||||
-rw-r--r-- | src/lib/tls.C | 123 | ||||
-rw-r--r-- | src/lib/tlsrt.C | 31 |
3 files changed, 115 insertions, 42 deletions
diff --git a/src/lib/makefile b/src/lib/makefile index 5e64025d1..406d5ead8 100644 --- a/src/lib/makefile +++ b/src/lib/makefile @@ -5,7 +5,7 @@ # # OpenPOWER HostBoot Project # -# Contributors Listed Below - COPYRIGHT 2010,2017 +# Contributors Listed Below - COPYRIGHT 2010,2019 # [+] International Business Machines Corp. # # @@ -50,6 +50,7 @@ OBJS += utilmisc.o OBJS += tls.o OBJS += errno.o +OBJS += tlsrt.o ifdef HOSTBOOT_MEMORY_LEAKS COMMONFLAGS += -DHOSTBOOT_MEMORY_LEAKS=1 diff --git a/src/lib/tls.C b/src/lib/tls.C index 4fcafb23b..3e2294251 100644 --- a/src/lib/tls.C +++ b/src/lib/tls.C @@ -31,9 +31,21 @@ #include <algorithm> #include <stdlib.h> #include <string.h> +#ifndef __HOSTBOOT_RUNTIME #include <util/lockfree/stack.H> +#else +#include <util/nolockfree/stack.H> +#endif #include <sys/vfs.h> +/** + * @brief Mask which suppresses ignored portions of a TLS module ID. When + * The linker creates a module ID, it prefixes it with "TLS" + 0x00 + * as the first 32 bits. This mask slices that off to leave just the + * normalized module ID + */ +const size_t TLS_MODULE_MASK = 0x00000000FFFFFFFFULL; + /** Thread Local Storage - How it works. * * For background: @@ -86,8 +98,36 @@ struct __tls_linker_tuple /** Info about the .tdata section for each module. */ struct __tls_module { - void* sect_addr; - size_t size; + void* sect_addr; //< Starting address of module + size_t size; //< Size of module + size_t module; //< Module ID of this module + //< (set by custom linker) + + /** + * @brief Default constructor + */ + __tls_module() + : sect_addr(0), + size(0), + module(0) + { + } + + /** + * @brief Specialized contstructor + * + * @param[in] i_start Module starting address. Must not be nullptr. + * @param[in] i_size Module size in bytes + * @param[in] i_module Modue ID of the module + */ + __tls_module(void* const i_start, + const size_t i_size, + const size_t i_module) + : sect_addr(i_start), + size(i_size), + module(i_module) + { + } }; /** TLS destructor data. */ @@ -103,7 +143,11 @@ struct __tls_dtor struct __tls_thread_info { size_t count; +#ifndef __HOSTBOOT_RUNTIME Util::Lockfree::Stack<__tls_dtor> dtors; +#else + Util::NoLockFree::Stack<__tls_dtor> dtors; +#endif void* blobs[0]; }; @@ -114,51 +158,47 @@ std::vector<__tls_module> __tls_pending_modules; /** Get the previously registered __tls_module data for a TLS variable */ const __tls_module* __tls_get_module(const __tls_linker_tuple* tuple) { + size_t tuple_module = tuple->module & TLS_MODULE_MASK; + // Look the module up in the __tls_modules first, in case we've seen // this module before in another thread. - if ((__tls_modules.size() > tuple->module) && - (__tls_modules[tuple->module].sect_addr != nullptr)) + if ((__tls_modules.size() > tuple_module) && + (__tls_modules[tuple_module].sect_addr != nullptr)) { - return &__tls_modules[tuple->module]; + return &__tls_modules[tuple_module]; } // We plan to insert a new module, so make sure we can contain it. - if (__tls_modules.size() <= tuple->module) + if (__tls_modules.size() <= tuple_module) { - __tls_modules.resize(tuple->module+1); + __tls_modules.resize(tuple_module+1); } // This is the first time we've seen this module. Need to look up in // pending. - // The TLS sections are at the beginning of the .rodata section and the - // linker tuples are somewhere in .data. Therefore sect_addr < tuple. - // Search __tls_pending_modules for the highest address section that is - // less than the tuple address. - auto best = __tls_pending_modules.begin(); - auto curr = best; - while(curr != __tls_pending_modules.end()) - { - if ((curr->sect_addr > best->sect_addr) && - (curr->sect_addr < tuple)) + // The module should have pre-registered its module ID in association + // with its starting address and size; look for a module ID match. + auto moduleItr = std::find_if( + __tls_pending_modules.begin(), + __tls_pending_modules.end(), + [&tuple_module](const __tls_module& i_module) { - best = curr; - } - ++curr; - } - assert(best != __tls_pending_modules.end()); + return (tuple_module == i_module.module); + }); + assert(moduleItr != __tls_pending_modules.end()); // Copy it into the __tls_modules and remove it from the pending list. - __tls_modules[tuple->module] = *best; - __tls_pending_modules.erase(best); + __tls_modules[tuple_module] = *moduleItr; + __tls_pending_modules.erase(moduleItr); - return &__tls_modules[tuple->module]; + return &__tls_modules[tuple_module]; } /* Since Hostboot runtime only has a single thread, we'll just create a * single global TLS area. */ #ifdef __HOSTBOOT_RUNTIME -task_t __tls_task_struct; +task_t tls_task_struct; #endif /** Get a TLS variable address @@ -168,6 +208,8 @@ task_t __tls_task_struct; extern "C" void* __tls_get_addr(const __tls_linker_tuple* tuple) { + size_t tuple_module = tuple->module & TLS_MODULE_MASK; + task_t* task = nullptr; #ifdef __HOSTBOOT_RUNTIME task = &tls_task_struct; @@ -184,36 +226,36 @@ void* __tls_get_addr(const __tls_linker_tuple* tuple) // - tls[module] is nullptr // Then: module blob needs to be allocated. if ((tls_info == nullptr) || - (tls_info->count <= tuple->module) || - (tls_info->blobs[tuple->module] == nullptr)) + (tls_info->count <= tuple_module) || + (tls_info->blobs[tuple_module] == nullptr)) { // If there isn't room for the module's blob, we need to allocate it. - if ((tls_info == nullptr) || (tls_info->count <= tuple->module)) + if ((tls_info == nullptr) || (tls_info->count <= tuple_module)) { - decltype(__tls_thread_info::count) old_size = 0; + decltype(__tls_thread_info::count) old_count = 0; auto new_size = sizeof(__tls_thread_info) + - sizeof(void*)*(tuple->module+1); + sizeof(void*)*(tuple_module+1); // Allocate or reallocate the tls info. if (tls_info == nullptr) { - old_size = 0; + old_count = 0; tls_info = reinterpret_cast<decltype(tls_info)>( malloc(new_size)); memset(&tls_info->dtors, '\0', sizeof(tls_info->dtors)); } else { - old_size = tls_info->count; + old_count = tls_info->count; tls_info = reinterpret_cast<decltype(tls_info)>( realloc(tls_info, new_size)); } // Clear the newly allocated area and update the count. - memset(&tls_info->blobs[old_size], '\0', new_size - - (sizeof(__tls_thread_info) + sizeof(void*)*old_size)); - tls_info->count = tuple->module+1; + memset(&tls_info->blobs[old_count], '\0', new_size - + (sizeof(__tls_thread_info) + sizeof(void*)*old_count)); + tls_info->count = tuple_module+1; // save into task struct. task->tls_context = tls_info; @@ -224,7 +266,7 @@ void* __tls_get_addr(const __tls_linker_tuple* tuple) mutex_lock(&__tls_mutex); { auto module = __tls_get_module(tuple); - auto blob = tls_info->blobs[tuple->module] = malloc(module->size); + auto blob = tls_info->blobs[tuple_module] = malloc(module->size); memcpy(blob, module->sect_addr, module->size); } mutex_unlock(&__tls_mutex); @@ -232,7 +274,7 @@ void* __tls_get_addr(const __tls_linker_tuple* tuple) } // Return the offset of the TLS variable from this module's blob. - return &reinterpret_cast<uint8_t*>(tls_info->blobs[tuple->module]) + return &reinterpret_cast<uint8_t*>(tls_info->blobs[tuple_module]) [tuple->offset+VFS_PPC64_DTPREL_OFFSET]; } @@ -240,13 +282,12 @@ void* __tls_get_addr(const __tls_linker_tuple* tuple) * * Called by init() in module_init. */ -void __tls_register(void* s, void* e) +void __tls_register(void* s, void* e, const size_t i_module) { if (s == e) return; - __tls_module m = { s, ((size_t)e) - ((size_t)s) }; - + __tls_module m(s, ((size_t)e) - ((size_t)s), i_module ); mutex_lock(&__tls_mutex); { __tls_pending_modules.push_back(m); diff --git a/src/lib/tlsrt.C b/src/lib/tlsrt.C new file mode 100644 index 000000000..100299d16 --- /dev/null +++ b/src/lib/tlsrt.C @@ -0,0 +1,31 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/lib/tlsrt.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2019 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +// There are no good ways to apply the runtime condition to a non-module +// object, so this facilitates creating two different verisions of the +// same object +#define __HOSTBOOT_RUNTIME 1 +#include "tls.C" + |