RES: RTEMS with C++

Chris Johns chrisj at rtems.org
Thu Oct 19 23:24:52 UTC 2006


Fabrício de Novaes Kucinskis wrote:
> 
> And how do you do this? Do you pass a method of an object as the entry point
> for a task?
> 

I will try and explain now I handle threads with C++. This is a little 
involved.

Joel is correct about a function being used as the entry point RTEMS 
uses rather than a C++ method. All methods that are part of a class have 
a hidden first argument the 'this' pointer. The RTEMS entry point is a C 
function and does not know about the 'this' pointer. To call a method in 
a class we need the entry to the method AND we need the pointer to the 
specific instance or the 'this' pointer. What we do after this is all 
about object based design, generic programming or what-ever you need.

I use a template to handle the thread in a sort of generic programming 
way. In a namespace I create a base class and use it in the template. 
The base class hides all the detail from the template in a .cpp file. 
You can also link in different .cpp file based on the platform you are 
running on. I pass the 'this' pointer as the RTEMS task argument. I have 
seen people use the notepad registers. Here is the sort of code that 
shows now this is done:

   namespace os
   {
    namespace thread
    {
     void sleep (uint32_t microseconds);

     class base
     {
      // lets the function access this class
      friend void runtime_start_routine (void* instance);
     public:
      base ();
      virtual ~base ();
      void exit ();
      void cancel ();
       [ more methods you need to handle threads ]
     protected:
      // called from the runtime start routine
      virtual void base_start_routine () = 0;
      void create (......);
     private:
      // this can be a platform based type
      rtems_id id;
     };

     template < class C >
     class thread
      : public base
     {
     public:
      typedef void (C:*start_routine) ();

      thread () : c (c), sr (0) {}
      void create (C& _c, start_routine _sr, int stack_size,,,,) {
       c = _c;
       sr = _sr;
       base::create (......);
      }

     private:
      // we come in here and call the class specific start routine.
      virtual void base_start_routine () {
       if (sr)
        (c->*sr) ();
      }

      C* c;
      start_routine sr;
     };
    }
   }

In the .cpp file:

   namespace os
   {
    namespace thread
    {
     void*
     runtime_start_routine (void* instance)
     {
      os::thread::base* t = (os::thread::base*) instance;
      t->base_start_routine ();
      rtems_task_delete (RTEMS_SELF);
     }

     void
     base::create (......)
     {
       [ parameter checks or what ever else you need ]

      rtems_status_code sc;
      sc = rtems_task_create (,,,,, &id);
      if (sc != RTEMS_SUCCESSFUL)
       ......
      sc = rtems_task_start (id, runtime_start_routine,
                             static_cast<void*> (this));
      if (sc != RTEMS_SUCCESSFUL)
       ......

      [ what ever else you need ]
     }
    }
   }

The interesting part is the static_cast of the 'this' pointer as the 
task argument which becomes 'instance' in runtime_start_routine. This is 
the bit that you are after, the rest is all just a specific type of design.

To use this code I do something like:

  class foo
  {
  public:
   typedef os::thread::thread <foo> foo_thread;
   foo ();
   void hello ();
  private:
   foo_thread hello_thread;
  };

  foo::foo ()
  {
    hello_thread.create (*this, &foo::hello, 2048, ...);
    // a function in the thread namespace to sleep a thread
    os::thread::sleep (100000);
  }

  void
  foo::hello ()
  {
    std::cout << "foo says hello" << std::endl;
  }

  int main (int argc, char* argv[])
  {
    foo f;
    return 0;
  }

This approach allow me to have as many threads running in a class as the 
class needs without having to derive and create specific classes for 
each thread. For example you may have tx and rx threads in a class 
involved in data communications. In the example above you see I create a 
foo and do not care how foo says hello.

This is one approach to implementing threads in C++ and may not be the 
best or the definitive design. It is simple, scales and adds little if 
any overhead. To complete this design you need think about exceptions 
and clean up issues.

I hope the detail provided gives you something that can get you going.

Regards
Chris



More information about the users mailing list