28 | | * Change the operating system to use other defaults. This may at first sound odd for users of a closed source system, but VxWorks in its latest versions luckily comes with the source code included and the possibility to compile a new kernel adapted to your needs. So, this has a lot of advantages, but it may interfere with the user's code (e. g. when he's using POSIX-mutexes with default values). Anyway, this should not pose a major problem, obeying the priority inheritance protocol does not break anything, it just puts on some additional burden on the task-scheduler where it wouldn't be neccessary. But if utmost performance and timing accuracy where a mission cirtical point for your application you would prabably not be using the heap and Boost, right?[[BR]] |
| 30 | * Change the operating system to use other defaults. This may at first sound odd for users of a closed source system, but VxWorks in its latest versions luckily comes with the source code included and the possibility to compile a new kernel adapted to your needs. So, this has a lot of advantages, but it may interfere with the user's code (e. g. when he's using POSIX-mutexes with default values). Anyway, this should not pose a major problem, obeying the priority inheritance protocol does not break anything, it just puts on some additional burden on the task-scheduler where it wouldn't be neccessary. But if utmost performance, predictability and timing accuracy were paramount for your application you would probably not be using C++, the heap and Boost, right? |
| 31 | So, solution three - patching the OS - seems to be the best solution. How do we do it?[[BR]][[BR]] |
| 32 | |
| 33 | == Patching the operating system == |
| 34 | |
| 35 | Here's a step by step instruction how to change the default attributes for POSIX-mutexes for RTP's. It's been taken mostly from a Wind River TSR: |
| 36 | * Edit the file {{{/vxworks-6.9/target/usr/src/posix/pthreadLib.c}}} in the root of your Workbench-installation. |
| 37 | * Around line 917 there should be the definition of the default mutex attributes: |
| 38 | {{{ |
| 39 | LOCAL pthread_mutexattr_t defaultMutexAttr = |
| 40 | { |
| 41 | PTHREAD_INITIALIZED_OBJ, PTHREAD_PRIO_NONE, 0, |
| 42 | PTHREAD_MUTEX_DEFAULT |
| 43 | }; |
| 44 | }}} |
| 45 | In the initializer list replace {{{PTHREAD_PRIO_NONE}}} by {{{PTHREAD_PRIO_INHERIT}}}. |
| 46 | * Around line 1236 there should be a definition for the function {{{pthread_mutexattr_init()}}}. A couple of lines below you should find a block of code like this: |
| 47 | {{{ |
| 48 | pAttr->mutexAttrStatus = PTHREAD_INITIALIZED_OBJ; |
| 49 | pAttr->mutexAttrProtocol = PTHREAD_PRIO_NONE; |
| 50 | pAttr->mutexAttrPrioceiling = 0; |
| 51 | pAttr->mutexAttrType = PTHREAD_MUTEX_DEFAULT; |
| 52 | }}} |
| 53 | Here again, replace {{{PTHREAD_PRIO_NONE}}} by {{{PTHREAD_PRIO_INHERIT}}}. |
| 54 | * Finally, rebuild your VSB. This will create a new VxWorks kernel with the changed properties. |
| 55 | That's it! Now, using Boost with this modified kernel should no longer cause any problems with task deadlocks! [[BR]][[BR]] |
| 56 | |
| 57 | |
| 58 | == Conclusions == |
| 59 | |
| 60 | * The default values for POSIX mutexes under VxWorks make RTP's susceptible to the priority inversion problem. |
| 61 | * The best way around this is to patch the operating system accordingly, a step-by-step instruction is provided. |
| 62 | * Other real time OSes (e. g. QNX) ''may'' be prone to the problem as well, depending on the defaults used. Consult your OS' documentation to gain clarity about this. |
| 63 | * Here's another useful piece of information concerning VxWorks' POSIX-functionality in general:[[BR]] At the time a task calls it's first POSIX-function during runtime it is being transformed by VxWorks into a POSIX-thread. This transformation does include a call to {{{malloc()}}} to allocate the memory required for the housekeeping of POSIX-threads. In a high priority RTP this {{{malloc()}}} call may be highly undesirable, as its timing is more or less unpredictable (depending on what your actual heap looks like). You can circumvent this problem by calling the function {{{thread_self()}}} at a well defined point in the code of the task, e.g. shortly after the task spawns up. Thereby you are able to define the time when the task-transformation will take place and you could shift it to an uncritical point where a {{{malloc()}}} call is tolerable. So, if this could pose a problem for your code, remember to call {{{thread_self()}}} from the affected task at an early stage. Calling {{{thread_self()}}} to initiate the transformation is BTW an official recommendation by Wind River. |