Runtime Layer
The runtime layer (RTL) provides a interface for platform independent functionality. The library implements memory management, handles strings, locales, processes and object lifecycle management, amongst other things.
Bootstrapping
When LibreOffice loads, it must read a config file. RTL contains code that bootstraps the configuration from a config file. This code is found in sal/rtl/bootstrap.cxx The ini file is set via the function rtl_bootstrap_set_InitFileName()
This function must be called before getting individual bootstrap settings.
The location of the bootstrap files is:
%APPDATA%\libreoffice\4\user
(Windows)/home/<user name>/.config/libreoffice/4/user
(Linux)~/Library/Application Support/LibreOffice/4/user
(macOS)/assets/rc
(Android, in the app's .apk archive)
Once the bootstrap filename is set, you must open the file via rtl_bootstrap_args_open()
and to close it you use rtl_bootstrap_args_close()
The open function returns a handle to the bootstrap settings file. To get the ini file you call on rtl_bootstrap_get_iniNamefrom_handle()
To get the value of a setting, you call rtl_bootstrap_get()
and to set a value you call rtl_bootstrap_set().
Note that the bootstrap code allows for macro expansion (in Bootstrap_Impl::expandValue()
and Bootstrap_Impl::expandMacros()
). Basically, the key and/or value can contain a macro that will be expanded - the syntax is ${file:key}
, where file is the ini file, and key is the value to be looked up in the ini file. In fact, it also handles nested macros, so you can have ${file:${file:key}}
or ${${file:key}:${file:key}}
or even (if you are insane) ${${file:${file:key}}:${file:${file:${file:key}}}}
.
When the key is looked up via Bootstrap_Impl::getValue()
, there are some special hardcoded values. They are:
_OS
_ARCH
CPPU_ENV
APP_DATA_DIR
(for both Android and iOS)ORIGIN
(gets the path to the ini file)
There is also a few system defined variables that can be overridden by an environment variable or from the command line via the -env:
switch (the function name is rather confusingly called getAmbienceValue()
...). These are:
SYSUSERCONFIG
SYSUSERHOME
SYSBINDIR
All of these values can be overriden, however, by using the syntax ${.override:file:value}
There is a final macro expansion that falls back to an osl::Profile
lookup - the syntax for this is ${key}
. However, this does not allow for expanding macros, so you can't do something like ${${file:key}}
. A comment in the code actually states that it:
...erroneously does not recursively expand macros in the resulting replacement text (and if it did, it would fail to detect cycles that pass through here)
Finally, if no value can be found, the Bootstrap_Impl::getValue()
allows for a default value to be optionally specified.
Note that the unit tests for this were never converted, and removed in the following commit.
Process and library management
The RTL functions for processes get the process ID and command line arguments. They differ subtly from the OSL functions. rtl_getProcessID()
_gets a UUID that represents the process ID, _but does not use the Ethernet address. rtl_getAppCommandArg()
and rtl_getAppCommandArgCount()
gets the command line arguments, but ignores the ones set by -env:
Object lifecycle management
RTL implements its own shared pointer via the Reference
class. It is largely equivalent to std::shared_ptr
, using reference counting to own a pointer, but is less fully featured. The functions are defined in include/rtl/ref.hxx
rtl::Reference
std::shared_ptr
template <class reference_type> Reference(reference_type*);
shared_ptr <class U> shared_ptr(U*);
Reference<reference_type> operator= &(reference_type*);
shared_ptr& operator= (const shared_ptr&) noexcept;
Reference<reference_type>& set(reference_type*);
shared_ptr& operator= (const shared_ptr&) noexcept;
reference_type* get() const;
element_type* get() const noexcept;
reference_type& operator* () const;
element_type& operator* () const noexcept;
reference_type* operator-> () const;
element_type* operator-> () const noexcept;
Reference<reference_type>& clear();
template<class U> void reset(U*);
same relational operators
same relational operators
bool is() const;
operator bool() const noexcept;
no equivalent swap()
function
void swap(shared_ptr&) noexcept;
no equivalent use_count()
function
long int use_count() const noexcept;
no equivalent unique()
function
bool unique() const noexcept;
For a singleton class that uses double-checked locking, the class rtl::Instance
can be used.
Memory management
RTl handles memory allocation. There are two memory allocators - one that uses the standard malloc-based allocator of the system, and a custom allocator that is based around memory arenas. This, however, has now been disabled (except in the bridges
module, which bridges C++ ABIs, Java JNI and Microsoft .NET to UNO and back).
The standard, malloc-based allocator uses the following functions:
Function name
Allocator
rtl_allocateMemory(sal_Size Bytes)
malloc(size_t bytes)
rtl_reallocateMemory(void *p, sal_Size Bytes)
realloc(void *p, size_t bytes)
rtl_freeMemory(void *p)
free(void *p)
There are a few additional functions that build on these. rtl_allocateZeroMemory
allocates memory, but uses memset
to zero out that memory via memset
. rtl_secureZeroMemory
fills a block of memory with zeroes in a way that is guaranteed to be secure (for Unix it is implemented casting the pointer to a volatile char pointer, then it zeroes out each byte in a loop - the volatile pointer ensures that the compiler will not optimize this away. rtl_secureZeroMemory
and rtl_freeZeroMemory
do similar things.
Byte sequences
TODO: byteseq.h, byteseq.hxx
String handling
TODO: character.hxx, strbuf.h, strbuff.hxx, string.h, string.hxx, stringconcat.hxx, stringutils.hxx, textenc.h, textcvt.h, textenc.h, ustrbuf.h, ustrbuff.hxx, ustring.h, ustring.hxx
Locale handling
TODO: locale.h
URI handling
TODO: uri.h, uri.hxx
UUIDs, Ciphers, digests, CRCs and random generator
TODO: uuid.h, cipher.h, crc.h, digest.h, random.h
Last updated