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