Differences between revisions 1 and 12 (spanning 11 versions)
Revision 1 as of 2014-07-01 04:32:25
Size: 2941
Editor: HungTa
Comment:
Revision 12 as of 2014-07-22 14:00:44
Size: 3115
Editor: AndrewStone
Comment:
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
SAFplus provides library initialization infrastructure: log, utils, osal, timer... They're the basic libraries that most application should use. However, not all of them would be used.
Furthermore, it's necessary to be able to explicitly link individual libs for highly embedded users.
SAFplus provides library initialization infrastructure: log, utils, osal, timer... They're the basic libraries that most applications should use. However, not all of them would be used.
Furthermore, it's necessary to be able to explicitly link individual libraries for highly embedded users.
Line 8: Line 8:
The Thread Pool is a client library that is linked with every component that uses it. SAFplus initialization can be implemented in 2 methods:
Line 10: Line 10:
The thread pool contains APIs to add a "Poolable" or "Wakeable" object into an internal job list. When a thread in the pool frees up, it grabs a "Poolable" or "Wakeable" object off the job list and executes it within the thread. === Method 1: using weak link ===
According to GNU weak attribute declaration, we can declare initialization functions as the weak linked functions. Therefore, their definitions can be omitted (in case they're not used), or replaced by different libraries (in case they're used). The linker will fill in NULL for undefined weak symbols.
Line 12: Line 13:
To preserve resources, if there are many idle threads they will slowly exit down to a configured minimum number. But if the job list exceeds a configured threshold, a new thread will be created up to a configured maximum. SAFplus services rely on other SAFplus services, but the application is not required to understand these dependencies. Instead, services will define what they rely upon in an enum names LibDep. During initialization a service will create a bitmap of all the services it uses in the form LibDep::LOG | LibDep::CKPT. This will automatically create the full bitmap of all required services because LibDep::CKPT (for example) is a bitmap of CKPT and all service CKPT requires.
Line 14: Line 15:
== Header ==
#include <clThreadPool.hxx>
== APIs ==
==== Header ====
#include <clGlobals.hxx>
==== APIs ====
Line 22: Line 23:
  // Definition of user task
  typedef void (*CallbackT) (void* invocation);
  typedef uint32_t (*UserCallbackT) (void* invocation);
  extern void utilsInitialize() __attribute__((weak));
  extern void logInitialize() __attribute__((weak));
  // TODO: other initialization functions declaration here
Line 26: Line 27:
  class Poolable: public Wakeable   enum class LibSet
Line 28: Line 29:
  public:
    struct timespec m_startTime;
    struct timespec m_endTime;
    uint32_t m_executionTimeLimit;
    bool deleteWhenComplete; /** Flag that indicates this object should be deleted when it is finished running */

    Poolable(uint_t timeLimit=30000); /** by default allow a 30 second execution time */
    virtual void wake(int amt,void* cookie=NULL); /** Implement this virtual function to do the job */
    virtual ~Poolable();
    RPC=1,
    CKPT=2,
    IOC=4,
    UTILS=8,
    OSAL=0x10,
    LOG=0x20,
    GRP=0x40
 
Line 39: Line 39:
  class ThreadPool
    {
  protected:
    void createTask();
    void startNewTask();
    void taskEntry();
  enum class LibDep
  {
    LOG = LibSet::LOG | LibSet::OSAL | LibSet::UTILS,
    OSAL = LibSet::OSAL | LibSet::LOG | LibSet::UTILS,
    UTILS = LibSet::UTILS | LibSet::OSAL,
    CKPT = LibSet::CKPT | LibSet::IOC | LibSet::UTILS | LibSet::GRP,
    GRP = LibSet::GRP | LibSet::CKPT | LibSet::IOC,
  };
Line 46: Line 48:
  protected:
    short m_minThread;
    short m_maxThread;
    short m_numIdleTasks;
    short m_flags;
    Mutex m_mutex;
    Wakeable preIdleFn;
    void* m_preIdleCookie;
    Wakeable onDeckFn;
    void* m_onDeckCookie;
    ThreadCondition m_cond;
    uint32_t m_pendingJobs;

  public:
    ThreadPool(uint_t minThreads, uint_t maxThreads); /* Initialize pool */

    /** Starts the thread pool running */
    void start();
    /** Stops the thread pool. All currently running threads complete their job and then exit */
    void stop();
  void safplusInitialize(LibDep svc)
  {
    if(svc&LOG)
      if(logInitialize) logInitialize();
    if(svc&UTILS)
      if(utilsInitialize) utilsInitialize();
    // TODO: other ones here
  }
Line 67: Line 57:
    /** Adds a job into the thread pool. Poolable is NOT COPIED; do not delete or let it fall out of scope.
        A Poolable object is more sophisticated than a Wakeable; it measures how long it was run for, can track
        whether it should be deleted, and will ASSERT if it is running for longer than a configured limit (deadlock detector)
     */
    void run(Poolable* p,void* arg);

    /** Adds a job into the thread pool. Wakeable is NOT COPIED; do not delete or let it fall out of scope */
    void run(Wakeable* p,void* arg);

    ~ThreadPool(); /* Finalize pool */
    
  };
Line 82: Line 60:

=== Method 2: configuring the app with options ===
Somehow, an app can be configured with options so-called use_services as 'log', 'utils', 'ioc'... or 'all' and pass it to an environment variable. Then, following its values, the preface.mk will define services accordingly:
==== Makefile ====
include preface.mk

{{{#!highlight bash
$DSVCS:=
ifeq ($(SVCS),log)
       $DSVCS += -DLOG
ifeq ($(SVCS),utils)
       $DSVCS += -DUTILS
#...
LINK_EXE = g++ $DSVCS -g -O0 -fPIC $(LINK_FLAGS) -o
}}}

==== Header ====
#include <clGlobals.hxx>
==== APIs ====

{{{#!highlight cpp

namespace SAFplus
{

  enum
  {
    RPC=1,
    CKPT=2,
    IOC=4,
    UTILS=8,
    OSAL=16,
    LOG=32
  };

  void safplusInitialize(uint16_t svc)
  {
    if(svc&LOG)
#ifdef LOG
      logInitialize();
#endif
    if(svc&UTILS)
#ifdef UTILS
      utilsInitialize();
#endif
    // TODO: other ones here
  }
    
}

}}}

SAFplus initialization

SAFplus provides library initialization infrastructure: log, utils, osal, timer... They're the basic libraries that most applications should use. However, not all of them would be used. Furthermore, it's necessary to be able to explicitly link individual libraries for highly embedded users.

Implementation

SAFplus initialization can be implemented in 2 methods:

According to GNU weak attribute declaration, we can declare initialization functions as the weak linked functions. Therefore, their definitions can be omitted (in case they're not used), or replaced by different libraries (in case they're used). The linker will fill in NULL for undefined weak symbols.

SAFplus services rely on other SAFplus services, but the application is not required to understand these dependencies. Instead, services will define what they rely upon in an enum names LibDep. During initialization a service will create a bitmap of all the services it uses in the form LibDep::LOG | LibDep::CKPT. This will automatically create the full bitmap of all required services because LibDep::CKPT (for example) is a bitmap of CKPT and all service CKPT requires.

#include <clGlobals.hxx>

APIs

   1 namespace SAFplus
   2 {
   3   extern void utilsInitialize() __attribute__((weak));
   4   extern void logInitialize() __attribute__((weak));
   5   // TODO: other initialization functions declaration here
   6 
   7   enum class LibSet
   8   {
   9     RPC=1,
  10     CKPT=2,
  11     IOC=4,
  12     UTILS=8,
  13     OSAL=0x10,
  14     LOG=0x20,
  15     GRP=0x40
  16  
  17   };
  18 
  19   enum class LibDep
  20   {
  21     LOG = LibSet::LOG | LibSet::OSAL | LibSet::UTILS,
  22     OSAL = LibSet::OSAL | LibSet::LOG | LibSet::UTILS,
  23     UTILS = LibSet::UTILS | LibSet::OSAL,
  24     CKPT = LibSet::CKPT | LibSet::IOC | LibSet::UTILS | LibSet::GRP,
  25     GRP = LibSet::GRP | LibSet::CKPT | LibSet::IOC,
  26   }; 
  27 
  28   void safplusInitialize(LibDep svc)
  29   {
  30     if(svc&LOG)
  31       if(logInitialize) logInitialize();
  32     if(svc&UTILS)
  33       if(utilsInitialize) utilsInitialize();
  34     // TODO: other ones here
  35   }
  36     
  37 }

Method 2: configuring the app with options

Somehow, an app can be configured with options so-called use_services as 'log', 'utils', 'ioc'... or 'all' and pass it to an environment variable. Then, following its values, the preface.mk will define services accordingly:

Makefile

include preface.mk

   1 $DSVCS:=
   2 ifeq ($(SVCS),log)
   3        $DSVCS += -DLOG
   4 ifeq ($(SVCS),utils)
   5        $DSVCS += -DUTILS
   6 #...
   7 LINK_EXE    = g++ $DSVCS -g -O0 -fPIC $(LINK_FLAGS) -o

Header

#include <clGlobals.hxx>

APIs

   1 namespace SAFplus
   2 {
   3 
   4   enum
   5   {
   6     RPC=1,
   7     CKPT=2,
   8     IOC=4,
   9     UTILS=8,
  10     OSAL=16,
  11     LOG=32
  12   };
  13 
  14   void safplusInitialize(uint16_t svc)
  15   {
  16     if(svc&LOG)
  17 #ifdef LOG
  18       logInitialize();
  19 #endif
  20     if(svc&UTILS)
  21 #ifdef UTILS
  22       utilsInitialize();
  23 #endif
  24     // TODO: other ones here
  25   }
  26     
  27 }

SAFplus: SAFplus-initialization (last edited 2014-07-22 14:00:44 by AndrewStone)