From: bruceperens Date: Fri, 7 Mar 2014 01:40:32 +0000 (+0000) Subject: Fix the driver_manager static initialization order hack to use less X-Git-Url: http://git.whiteaudio.com/gitweb/?a=commitdiff_plain;h=9fc5e856c1cef5e13d086d4baac8372b5abbd078;p=freetel-svn-tracking.git Fix the driver_manager static initialization order hack to use less demand-fill-zero space. We prefer to reduce copy-on-write pages to a bare minimum for memory use efficiency with shared libraries and embedded systems. git-svn-id: https://svn.code.sf.net/p/freetel/code@1412 01035d8c-6547-0410-b346-abe4f91aad63 --- diff --git a/freedv-server/source/audio_sink.cpp b/freedv-server/source/audio_sink.cpp index 82c43a43..7d29b99c 100644 --- a/freedv-server/source/audio_sink.cpp +++ b/freedv-server/source/audio_sink.cpp @@ -55,7 +55,7 @@ namespace FreeDV { static bool initializer() { - init_driver_manager().register_audio_output("sink", Driver::AudioSink); + driver_manager()->register_audio_output("sink", Driver::AudioSink); return true; } static const bool initialized = initializer(); diff --git a/freedv-server/source/big_main.cpp b/freedv-server/source/big_main.cpp index 94c71a62..89bc225e 100644 --- a/freedv-server/source/big_main.cpp +++ b/freedv-server/source/big_main.cpp @@ -28,7 +28,7 @@ using namespace FreeDV; static void drivers() { - driver_manager.print(cout); + driver_manager()->print(cout); } static void help(const char * name) @@ -98,6 +98,7 @@ main(int argc, char * * argv) Interfaces i; const char * driver; const char * parameter; + const DriverManager * const m = driver_manager(); if ( argc > 1 ) { while ((command = getopt_long(argc, argv, "c:dhi:k:l:m:M:n:p:r:t:x:", options, NULL)) != -1) { @@ -127,7 +128,7 @@ main(int argc, char * * argv) switch (command) { case 'c': - i.codec = driver_manager.codec(driver, parameter); + i.codec = m->codec(driver, parameter); break; case 'd': drivers(); @@ -137,10 +138,10 @@ main(int argc, char * * argv) i.fill_in(); break; case 'f': - i.framer = driver_manager.framer(driver, parameter); + i.framer = m->framer(driver, parameter); break; case 'g': - i.user_interface = driver_manager.user_interface(driver, parameter, &i); + i.user_interface = m->user_interface(driver, parameter, &i); break; default: case 'h': @@ -148,31 +149,31 @@ main(int argc, char * * argv) exit(1); break; case 'k': - i.keying_output = driver_manager.keying_output(driver, parameter); + i.keying_output = m->keying_output(driver, parameter); break; case 'l': - i.loudspeaker = driver_manager.audio_output(driver, parameter); + i.loudspeaker = m->audio_output(driver, parameter); break; case 'm': - i.microphone = driver_manager.audio_input(driver, parameter); + i.microphone = m->audio_input(driver, parameter); break; case 'M': - i.modem = driver_manager.modem(driver, parameter); + i.modem = m->modem(driver, parameter); break; case 'p': - i.ptt_input_digital = driver_manager.ptt_input(driver, parameter); + i.ptt_input_digital = m->ptt_input(driver, parameter); break; case 'P': - i.ptt_input_ssb = driver_manager.ptt_input(driver, parameter); + i.ptt_input_ssb = m->ptt_input(driver, parameter); break; case 'r': - i.receiver = driver_manager.audio_input(driver, parameter); + i.receiver = m->audio_input(driver, parameter); break; case 't': - i.transmitter = driver_manager.audio_output(driver, parameter); + i.transmitter = m->audio_output(driver, parameter); break; case 'x': - i.text_input = driver_manager.text_input(driver, parameter); + i.text_input = m->text_input(driver, parameter); break; case 'C': i.fill_in(); diff --git a/freedv-server/source/blank_panel.cpp b/freedv-server/source/blank_panel.cpp index 01eaecd2..f45a2f5f 100644 --- a/freedv-server/source/blank_panel.cpp +++ b/freedv-server/source/blank_panel.cpp @@ -41,7 +41,7 @@ namespace FreeDV { static bool initializer() { - init_driver_manager().register_user_interface("blank-panel", Driver::BlankPanel); + driver_manager()->register_user_interface("blank-panel", Driver::BlankPanel); return true; } static const bool initialized = initializer(); diff --git a/freedv-server/source/codec_noop.cpp b/freedv-server/source/codec_noop.cpp index 891b039e..ac8315c6 100644 --- a/freedv-server/source/codec_noop.cpp +++ b/freedv-server/source/codec_noop.cpp @@ -112,7 +112,7 @@ namespace FreeDV { static bool initializer() { - init_driver_manager().register_codec("no-op", Driver::CodecNoOp); + driver_manager()->register_codec("no-op", Driver::CodecNoOp); return true; } static const bool initialized = initializer(); diff --git a/freedv-server/source/driver_manager.cpp b/freedv-server/source/driver_manager.cpp index 28db8fa4..b7e92df2 100644 --- a/freedv-server/source/driver_manager.cpp +++ b/freedv-server/source/driver_manager.cpp @@ -16,6 +16,9 @@ namespace FreeDV { static std::ostream & enumerate(std::ostream & stream, const DriverList * list) { + if ( list == 0 ) + return stream; + while ( list->key ) { stream << list->key << ' '; list++; @@ -40,7 +43,7 @@ namespace FreeDV { { DriverList * next; - if ( list ) { + if ( *list ) { next = *list; while ( next->key ) next++; @@ -104,55 +107,55 @@ namespace FreeDV { } AudioInput * - DriverManager::audio_input(const char * driver, const char * parameter) + DriverManager::audio_input(const char * driver, const char * parameter) const { return (AudioInput *)pick(driver, parameter, audio_input_drivers); } AudioOutput * - DriverManager::audio_output(const char * driver, const char * parameter) + DriverManager::audio_output(const char * driver, const char * parameter) const { return (AudioOutput *)pick(driver, parameter, audio_output_drivers); } Codec * - DriverManager::codec(const char * driver, const char * parameter) + DriverManager::codec(const char * driver, const char * parameter) const { return (Codec *)pick(driver, parameter, codecs); } Framer * - DriverManager::framer(const char * driver, const char * parameter) + DriverManager::framer(const char * driver, const char * parameter) const { return (Framer *)pick(driver, parameter, framers); } KeyingOutput * - DriverManager::keying_output(const char * driver, const char * parameter) + DriverManager::keying_output(const char * driver, const char * parameter) const { return (KeyingOutput *)pick(driver, parameter, keying_output_drivers); } Modem * - DriverManager::modem(const char * driver, const char * parameter) + DriverManager::modem(const char * driver, const char * parameter) const { return (Modem *)pick(driver, parameter, modems); } PTTInput * - DriverManager::ptt_input(const char * driver, const char * parameter) + DriverManager::ptt_input(const char * driver, const char * parameter) const { return (PTTInput *)pick(driver, parameter, ptt_input_drivers); } TextInput * - DriverManager::text_input(const char * driver, const char * parameter) + DriverManager::text_input(const char * driver, const char * parameter) const { return (TextInput *)pick(driver, parameter, text_input_drivers); } UserInterface * - DriverManager::user_interface(const char * driver, const char * parameter, Interfaces * interfaces) + DriverManager::user_interface(const char * driver, const char * parameter, Interfaces * interfaces) const { return (UserInterface *)pick(driver, parameter, user_interface_drivers); } @@ -212,16 +215,10 @@ namespace FreeDV { place(driver, (base_creator)creator, &user_interface_drivers); } - /// Automatic initializer for the driver manager. - /// This has to be a function to get around the static initalization order - /// problem. - DriverManager & - init_driver_manager() + DriverManager * const + driver_manager() { - static DriverManager manager; - return manager; + static DriverManager * const d(new DriverManager()); + return d; } - - /// Global reference to the driver manager instance. - DriverManager & driver_manager = init_driver_manager(); } diff --git a/freedv-server/source/drivers.h b/freedv-server/source/drivers.h index 62ed5e14..f5f5f78b 100644 --- a/freedv-server/source/drivers.h +++ b/freedv-server/source/drivers.h @@ -754,45 +754,45 @@ namespace FreeDV { /// Instantiate an AudioInput driver. /// \param driver The name of the driver. /// \param parameters Driver-specific configuration parameters. - AudioInput * audio_input(const char * driver, const char * parameters); + AudioInput * audio_input(const char * driver, const char * parameters) const; /// Instantiate an AudioOutput driver. /// \param driver The name of the driver. /// \param parameters Driver-specific configuration parameters. - AudioOutput * audio_output(const char * driver, const char * parameters); + AudioOutput * audio_output(const char * driver, const char * parameters) const; /// Instantiate a Codec. /// \param driver The name of the driver. /// \param parameters Driver-specific configuration parameters. - Codec * codec(const char * driver, const char * parameters); + Codec * codec(const char * driver, const char * parameters) const; /// Instantiate a Framer. /// \param driver The name of the driver. /// \param parameters Driver-specific configuration parameters. - Framer * framer(const char * driver, const char * parameters); + Framer * framer(const char * driver, const char * parameters) const; /// Instantiate a Keying driver. /// \param driver The name of the driver. /// \param parameters Driver-specific configuration parameters. - KeyingOutput * keying_output(const char * driver, const char * parameters); + KeyingOutput * keying_output(const char * driver, const char * parameters) const; /// Instantiate a softmodem. /// \param driver The name of the driver. /// \param parameters Driver-specific configuration parameters. - Modem * modem(const char * driver, const char * parameters); + Modem * modem(const char * driver, const char * parameters) const; /// Instantiate a PTT input driver. /// \param driver The name of the driver. /// \param parameters Driver-specific configuration parameters. - PTTInput * ptt_input(const char * driver, const char * parameters); + PTTInput * ptt_input(const char * driver, const char * parameters) const; /// Instantiate a text input driver. /// \param driver The name of the driver. /// \param parameters Driver-specific configuration parameters. - TextInput * text_input(const char * driver, const char * parameters); + TextInput * text_input(const char * driver, const char * parameters) const; /// Instantiate a user interface driver. /// \param driver The name of the driver. /// \param parameters Driver-specific configuration parameters. /// \param interfaces Interfaces object used to hold all of the /// current device driver instances. - UserInterface * user_interface(const char * driver, const char * parameters, Interfaces * interfaces); + UserInterface * user_interface(const char * driver, const char * parameters, Interfaces * interfaces) const; /// Register an audio input driver. /// \param driver The name of the driver. @@ -852,11 +852,6 @@ namespace FreeDV { return d.print(stream); } - /// Global reference to the driver manager. - extern DriverManager & driver_manager; - - /// Return a reference to the driver manager instance. - /// This is a function because it is called in static initializers. - extern DriverManager & init_driver_manager(); + extern DriverManager * const driver_manager(); } diff --git a/freedv-server/source/framer.cpp b/freedv-server/source/framer.cpp new file mode 100644 index 00000000..d83e9e22 --- /dev/null +++ b/freedv-server/source/framer.cpp @@ -0,0 +1,14 @@ +/// The Protocol Framer base class. + +#include "drivers.h" + +namespace FreeDV { + Framer::Framer(const char * name, const char * parameters) + : Base(name, parameters) + { + } + + Framer::~Framer() + { + } +} diff --git a/freedv-server/source/framer_noop.cpp b/freedv-server/source/framer_noop.cpp new file mode 100644 index 00000000..6bb3d951 --- /dev/null +++ b/freedv-server/source/framer_noop.cpp @@ -0,0 +1,161 @@ +/// The No-Op Framer, for digital voice that is not framed in a protocol. +/// FreeDV would be the obvious example. + +#include "drivers.h" +#include + +namespace FreeDV { + /// Framer "no-op", just copies its input to its output. + class FramerNoOp : public ::FreeDV::Framer { + public: + /// Create a framer instance. + /// \param name Name of the driver. This is expected to be a single + /// constant static string per driver class. + /// \param parameters Driver-specific configuration parameters. + FramerNoOp(const char * parameters); + + /// Destroy a framer instance. + virtual ~FramerNoOp(); + + /// Return the maximum number of data bytes expected to store a wrapped + /// protocol frame. The result is invariant for a particular configuration + /// which may include such things as length of addresses and protocol + /// options. + /// \return The maximum number of data bytes expected to store a wrapped + /// protocol frame. + /// frame. + virtual std::size_t const + max_wrapped_bytes_per_frame() const; + + /// Return the maximum number of data bytes expected to store the unwrapped + /// codec data. The result is invariant for a particular configuration. + /// \return The maximum number of data bytes expected to store the unwrapped + /// codec data. + /// frame. + virtual std::size_t const + max_unwrapped_bytes_per_frame() const; + + /// Return the minimum number of data bytes expected to store the unwrapped + /// codec data. The result is invariant for a particular configuration. + /// \return The minimum number of data bytes expected to store the unwrapped + /// codec data. + /// frame. + virtual std::size_t const + min_unwrapped_bytes_per_frame() const; + + /// Return the minimum number of data bytes expected to store a wrapped + /// protocol frame. The result is invariant for a particular configuration + /// which may include such things as length of addresses and protocol + /// options. + /// \return The minimum number of data bytes expected to store a wrapped + /// protocol frame. + /// frame. + virtual std::size_t const + min_wrapped_bytes_per_frame() const; + + /// Decode from modem data to codec frames, removing the wrapping protocol. + /// \param i The encoded data, in an array of unsigned 8-bit integers. + /// \param o The array of codec data after decoding, in an array + /// of unsigned 8-bit integers. + /// \param input_length When called: The number of bytes of data that are + /// available to be unwrap. On return: the number of bytes of data + /// that were consumed. + /// \param output_length The number of codec data bytes that can be + /// unwrapped. + /// \return The number of data bytes that were actually decoded. + virtual std::size_t + unwrap(const std::uint8_t * i, + std::uint8_t * o, + std::size_t * input_length, + std::size_t output_length); + + /// Wrap codec data bytes in a protocol for transmission through the modem. + /// \param i The array of data bytes to be encoded, in an array + /// of unsigned 8-bit integers. + /// \param o The encoded data, in an array of unsigned 8-bit integers. + /// \param input_length The number of data bytes to be wrapped. + /// \param output_length The number of data bytes available to store the + /// wrapped data. + /// \return The number of std::uint8_t elements in the wrapped array. + virtual std::size_t + wrap( + const std::uint8_t * i, + std::uint8_t * o, + std::size_t * input_length, + std::size_t output_length); + }; + + FramerNoOp::FramerNoOp(const char * parameters) + : Framer("no-op", parameters) + { + } + + FramerNoOp::~FramerNoOp() + { + } + + std::size_t const + FramerNoOp::max_wrapped_bytes_per_frame() const + { + return 1; + } + + std::size_t const + FramerNoOp::max_unwrapped_bytes_per_frame() const + { + return 1; + } + + std::size_t const + FramerNoOp::min_unwrapped_bytes_per_frame() const + { + return 1; + } + + std::size_t const + FramerNoOp::min_wrapped_bytes_per_frame() const + { + return 1; + } + + std::size_t + FramerNoOp::unwrap(const std::uint8_t * i, + std::uint8_t * o, + std::size_t * input_length, + std::size_t output_length) + { + const std::size_t length = std::min(*input_length, output_length); + memcpy(o, i, length); + *input_length = length; + return length; + } + + std::size_t + FramerNoOp::wrap( + const std::uint8_t * i, + std::uint8_t * o, + std::size_t * input_length, + std::size_t output_length) + { + const std::size_t length = std::min(*input_length, output_length); + memcpy(o, i, length); + *input_length = length; + return length; + } + + Framer * + Driver::FramerNoOp(const char * parameter) + { + return new ::FreeDV::FramerNoOp(parameter); + } + +#ifndef NO_INITIALIZERS + static bool + initializer() + { + driver_manager()->register_framer("no-op", Driver::FramerNoOp); + return true; + } + static const bool initialized = initializer(); +#endif +} diff --git a/freedv-server/source/keying_sink.cpp b/freedv-server/source/keying_sink.cpp index 54007ef0..dee32c5e 100644 --- a/freedv-server/source/keying_sink.cpp +++ b/freedv-server/source/keying_sink.cpp @@ -54,7 +54,7 @@ namespace FreeDV { static bool initializer() { - init_driver_manager().register_keying_output("sink", Driver::KeyingSink); + driver_manager()->register_keying_output("sink", Driver::KeyingSink); return true; } static const bool initialized = initializer(); diff --git a/freedv-server/source/libevent.cpp b/freedv-server/source/libevent.cpp index 20cd344c..846b8a2e 100644 --- a/freedv-server/source/libevent.cpp +++ b/freedv-server/source/libevent.cpp @@ -73,7 +73,7 @@ namespace FreeDV { static bool initializer() { - init_driver_manager().register_codec("no-op", Driver::CodecNoOp); + driver_manager()->register_codec("no-op", Driver::CodecNoOp); return true; } static const bool initialized = initializer(); diff --git a/freedv-server/source/modem_noop.cpp b/freedv-server/source/modem_noop.cpp index 93745ee4..edba20e6 100644 --- a/freedv-server/source/modem_noop.cpp +++ b/freedv-server/source/modem_noop.cpp @@ -120,7 +120,7 @@ namespace FreeDV { static bool initializer() { - init_driver_manager().register_modem("no-op", Driver::ModemNoOp); + driver_manager()->register_modem("no-op", Driver::ModemNoOp); return true; } static const bool initialized = initializer(); diff --git a/freedv-server/source/ptt_constant.cpp b/freedv-server/source/ptt_constant.cpp index 43d21f9d..f04527a8 100644 --- a/freedv-server/source/ptt_constant.cpp +++ b/freedv-server/source/ptt_constant.cpp @@ -73,7 +73,7 @@ namespace FreeDV { static bool initializer() { - init_driver_manager().register_ptt_input("constant", Driver::PTTConstant); + driver_manager()->register_ptt_input("constant", Driver::PTTConstant); return true; } static const bool initialized = initializer(); diff --git a/freedv-server/source/text_constant.cpp b/freedv-server/source/text_constant.cpp index 4de3c8f6..1185b304 100644 --- a/freedv-server/source/text_constant.cpp +++ b/freedv-server/source/text_constant.cpp @@ -68,7 +68,7 @@ namespace FreeDV { static bool initializer() { - init_driver_manager().register_text_input("constant", Driver::TextConstant); + driver_manager()->register_text_input("constant", Driver::TextConstant); return true; } static const bool initialized = initializer(); diff --git a/freedv-server/source/tone.cpp b/freedv-server/source/tone.cpp index 5b96b5b5..edcf43de 100644 --- a/freedv-server/source/tone.cpp +++ b/freedv-server/source/tone.cpp @@ -156,7 +156,7 @@ namespace FreeDV { static bool initializer() { - init_driver_manager().register_audio_input("tone", Driver::Tone); + driver_manager()->register_audio_input("tone", Driver::Tone); return true; } static const bool initialized = initializer();