Fix the driver_manager static initialization order hack to use less
authorbruceperens <bruceperens@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 7 Mar 2014 01:40:32 +0000 (01:40 +0000)
committerbruceperens <bruceperens@01035d8c-6547-0410-b346-abe4f91aad63>
Fri, 7 Mar 2014 01:40:32 +0000 (01:40 +0000)
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

14 files changed:
freedv-server/source/audio_sink.cpp
freedv-server/source/big_main.cpp
freedv-server/source/blank_panel.cpp
freedv-server/source/codec_noop.cpp
freedv-server/source/driver_manager.cpp
freedv-server/source/drivers.h
freedv-server/source/framer.cpp [new file with mode: 0644]
freedv-server/source/framer_noop.cpp [new file with mode: 0644]
freedv-server/source/keying_sink.cpp
freedv-server/source/libevent.cpp
freedv-server/source/modem_noop.cpp
freedv-server/source/ptt_constant.cpp
freedv-server/source/text_constant.cpp
freedv-server/source/tone.cpp

index 82c43a43d440052e20def3932aa71332e1e50a5b..7d29b99cddd092e12948394b9d7f8e1f09b3faf1 100644 (file)
@@ -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();
index 94c71a6216795cef4794ad65d971ada545eb1cb2..89bc225e0ec66f2ebd5d2052a98332f83b9ec81a 100644 (file)
@@ -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();
index 01eaecd221fa7fbe1677e1645f50d3074576f245..f45a2f5fd4d4456588b4ac8d3e5ed015c2ace264 100644 (file)
@@ -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();
index 891b039e736601bbd63ca2240a8e91f50b32e3d7..ac8315c68365794dd438c2fa504e1709301e3462 100644 (file)
@@ -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();
index 28db8fa4146755f235a150ed6cc8f6c88c6cf8bb..b7e92df2f4ccca9eada87cd81d4a5c446f8175c6 100644 (file)
@@ -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();
 }
index 62ed5e14321acb3005a1c81bdd89e45935465325..f5f5f78b8effcd304c1f75ad73ca5d5ac9d04a55 100644 (file)
@@ -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 (file)
index 0000000..d83e9e2
--- /dev/null
@@ -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 (file)
index 0000000..6bb3d95
--- /dev/null
@@ -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 <string.h>
+
+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
+}
index 54007ef059984b60b3a9c424727f5002c2024468..dee32c5e9d5138b9117fdd0a535d016c9a9568ef 100644 (file)
@@ -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();
index 20cd344cf49fd4421f9232bf73e762031ca8756c..846b8a2e6d02498dad67a135279b750187ea5541 100644 (file)
@@ -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();
index 93745ee403ddd28ed27f43a8c8013a51aaff426f..edba20e684b20758a044e0d7efd825789939ba2d 100644 (file)
@@ -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();
index 43d21f9d6c2c2cbde7d67985468a88e2ef809ce6..f04527a8ddda74766ee788dd330d15fd377c72b5 100644 (file)
@@ -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();
index 4de3c8f6d681a016500531a82459cc4a052c6163..1185b304bc4ae4aa1c80045ff208cfcb566f591e 100644 (file)
@@ -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();
index 5b96b5b52771b42315ab94ef407c25cb9df53620..edcf43def811d17d1881d8af81bdc49d07a494a8 100644 (file)
@@ -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();