// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <cassert>
+#include <cstdlib>
#include <log/message_dictionary.h>
#include <log/message_initializer.h>
+
+// As explained in the header file, initialization of the message dictionary
+// is a two-stage process:
+// 1) In the MessageInitializer constructor, the a pointer to the array of
+// messages is stored in a pre-defined array. Since the MessageInitializers
+// are declared external to a program unit, this takes place before main()
+// is called. As no heap storage is allocated in this process, we should
+// avoid the static initialization fiasco in cases where initialization
+// of system libraries is also carried out at the same time.
+// 2) After main() starts executing, loadDictionary() is called.
+//
+//
+
+namespace {
+
+// Declare the array of pointers to value arrays. At the time of writing
+// (end of BIND 10's third year of development), only 25 such arrays have
+// been defined, so a value of 64 should allow for significant expansion.
+// (Besides, an assertion will be triggered if the array overflows.)
+const int MAX_LOGGERS = 64;
+const char** logger_values[MAX_LOGGERS];
+
+// Declare the index used to access the array. As this needs to be initialized
+// at first used, it is accessed it via a function.
+size_t& getIndex() {
+ static size_t index = 0;
+ return (index);
+}
+
+}
+
+
namespace isc {
namespace log {
-// Constructor. Just retrieve the global dictionary and load the IDs and
-// associated text into it.
+// Constructor. Add the pointer to the message array to the global array.
+// This method will trigger an assertion failure if the array overflows.
MessageInitializer::MessageInitializer(const char* values[]) {
+ assert(getIndex() < MAX_LOGGERS);
+ logger_values[getIndex()++] = values;
+}
+
+// Load the messages in the arrays registered in the logger_values array
+// into the global dictionary.
+
+void
+MessageInitializer::loadDictionary() {
MessageDictionary& global = MessageDictionary::globalDictionary();
- std::vector<std::string> repeats = global.load(values);
- // Append the IDs in the list just loaded (the "repeats") to the global list
- // of duplicate IDs.
- if (!repeats.empty()) {
- std::vector<std::string>& duplicates = getDuplicates();
- duplicates.insert(duplicates.end(), repeats.begin(), repeats.end());
+ for (size_t i = 0; i < getIndex(); ++i) {
+ std::vector<std::string> repeats = global.load(logger_values[i]);
+
+ // Append the IDs in the list just loaded (the "repeats") to the
+ // global list of duplicate IDs.
+ if (!repeats.empty()) {
+ std::vector<std::string>& duplicates = getDuplicates();
+ duplicates.insert(duplicates.end(), repeats.begin(), repeats.end());
+ }
}
+
+ // ... and mark that the messages have been loaded. (This avoids a lot
+ // of "duplicate message ID" messages in some of the unit tests where the
+ // logging initialization code may be called multiple times.)
+ getIndex() = 0;
}
// Return reference to duplicate array
/// :
/// NULL
/// };
-/// MessageDictionaryHelper xyz(values);
+/// MessageInitializer xyz(values);
///
-/// This will automatically add the message ID/text pairs to the global
-/// dictionary during initialization - all that is required is that the module
-/// containing the definition is included into the final executable.
+/// All that needed is for the module containing the definitions to be
+/// included in the execution unit.
///
-/// Messages are added via the MessageDictionary::add() method, so any
-/// duplicates are stored in the the global dictionary's overflow vector whence
-/// they can be retrieved at run-time.
+/// To avoid static initialization fiasco problems, the initialization is
+/// carried out in two stages:
+/// -# The constructor a pointer to the values array to a pre-defined array
+/// of pointers.
+/// -# During the run-time initialization of the logging system, the static
+/// method loadDictionary() is called to load the message dictionary.
+/// This way, no heap storage is allocated during the static initialization,
+/// something that may give problems on some operating systems.
+///
+/// When messages are added to the dictionary, the are added via the
+/// MessageDictionary::add() method, so any duplicates are stored in the the
+/// global dictionary's overflow vector whence they can be retrieved at
+/// run-time.
class MessageInitializer {
public:
/// \brief Constructor
///
- /// Adds the array of values to the global dictionary, and notes any
- /// duplicates.
+ /// Adds a pointer to the array of messages to the global array of
+ /// pointers to message arrays.
///
/// \param values NULL-terminated array of alternating identifier strings
/// and associated message text.
MessageInitializer(const char* values[]);
+ /// \brief Run-Time Initialization
+ ///
+ /// Loops through the internal array of pointers to message arrays
+ /// and adds the messages to the internal dictionary. This is called
+ /// during run-time initialization.
+ static void loadDictionary();
+
/// \brief Return Duplicates
///
/// When messages are added to the global dictionary, any duplicates are