How to add the Idle task to Ada runtime
Joel Sherrill
joel.sherrill at oarcorp.com
Sat Aug 15 17:14:52 UTC 2015
On 08/15/2015 11:09 AM, Jan Sommer wrote:
> Top Post:
>
> Ok. I finally manage to build a toolchain with only small optimization enabled and learned how to read assembler.
> I think I found the problem (or at least one of them) now.
>
> In s-taprop.ad : 967ff
> procedure Create_Task
> (T : Task_Id;
> Wrapper : System.Address;
> Stack_Size : System.Parameters.Size_Type;
> Priority : System.Any_Priority;
> Succeeded : out Boolean)
>
> This procedure is supposed to create the pthread which the ada runtime can then use for its task.
> I am still new to assembler, but that's what I get from looking at it:
>
> Dump of assembler code for function system__task_primitives__operations__create_task:
> 0x00009ec4<+0>: push {r4, r5, r6, r7, r8, lr} /* create a copy of registers to restore later */
> 0x00009ec8<+4>: sub sp, sp, #56 ; 0x38 /* reserver 56 bytes on the stack (for the pthread_attr_t)
> 0x00009ecc<+8>: mov r5, r0 /* some initial reorderering .... */
> 0x00009ed0<+12>: mov r7, r1
> 0x00009ed4<+16>: mov r4, r2
> 0x00009ed8<+20>: mov r8, r3
> 0x00009edc<+24>: bl 0x35fbc<getpagesize>
> 0x00009ee0<+28>: mov r6, r0
> 0x00009ee4<+32>: mov r0, sp /* store address of stack pointer to r0 as the argument for pthread_attr_init */
> 0x00009ee8<+36>: bl 0x3c1f0<pthread_attr_init> /* Call pthread_attr_init to initialize the pthread_attr_t */
>
> Dump of assembler code for function pthread_attr_init:
> => 0x0003c1f0<+0>: cmp r0, #0 /* NULL-pointer check; memcpy 1st parameter: dest address */
> 0x0003c1f4<+4>: beq 0x3c214<pthread_attr_init+36>
> 0x0003c1f8<+8>: push {r3, lr}
> 0x0003c1fc<+12>: ldr r1, [pc, #24] ; 0x3c21c<pthread_attr_init+44> /* memcpy 2nd parameter: source address: pointer to default pthread_attr_t */
> 0x0003c200<+16>: mov r2, #76 ; 0x4c /* !!!!! memcpy 3rd parameter SIZE == 76 BYTES */
> 0x0003c204<+20>: bl 0x49b00<memcpy> /* !!!!! OVERWRITE STACK of calling function */
> 0x0003c208<+24>: mov r0, #0
> 0x0003c20c<+28>: pop {r3, lr}
> 0x0003c210<+32>: bx lr
> 0x0003c214<+36>: mov r0, #22
> 0x0003c218<+40>: bx lr
> 0x0003c21c<+44>: andseq r8, r0, r0, lsr #27
> End of assembler dump.
>
> If I take a look at the stack of create task after the call to pthread_attr_init:
> Saved registers:
> r4 at 0x13eff8, r5 at 0x13effc, r6 at 0x13f000, r7 at 0x13f004, r8 at 0x13f008, lr at 0x13f00c
> 0x13eff8: 0x00000001
> 0x13effc: 0x00000001
> 0x13f000: 0x00000000
> 0x13f004: 0x00000000
> 0x13f008: 0x00000000
> 0x13f00c: 0x0000ecc0
>
> In these registers were, among others, the address pointers to the main task and the hello task which are continued to be used by the function which called Create_Task. It seems quite a lucky that the lr-register is the only one not overwritten.
>
> Now is the question why the runtime only reserves memory for56 bytes and why it is 76 bytes large in rtems?
> I made a quick grep of the header files, but couldn't find the typedef of pthread_attr_t. Where can I find it?
>
The C definition is in newlib. It is in newlib/libc/include/sys/types.h.
The Ada definition is in gcc/ada/s-osinte-rtems.ads.
They must match and they likely don't. A review of all *_attr_t would be
recommended. My quick reading is that the Ada pthread_attr_t doesn't
account or guardsize or the SMP affinity support.
I had another thought which I don't recall if I posted or not. I vaguely
recall
that the Ada init task is supposed to be the lowest Ada priority and
preemptible. When elaboration creates an Ada task, that new task
should preempt the Ada task. I suspect the Ada init task is running through
the Ada code before the created Ada tasks even get a chance to run and
register their existence with the run-time.
The Ada run-time wraps the user's Ada task body so it gets a chance to
do some setup and tear down before and after the user task runs. This
is similar to how RTEMS has _Thread_Handler which invokes the actual
user thread body. Anyway, if the Ada run-time wrapper never runs, then
it is likely missing some bookkeeping.
> Best regards,
>
> Jan
>
> Am Sonntag, 2. August 2015, 19:25:40 schrieb Jan Sommer:
>> Am Samstag, 1. August 2015, 12:48:09 schrieb Joel Sherrill:
>>> On 08/01/2015 12:39 PM, Jan Sommer wrote:
>>>> I managed to get most of the Ada examples running for the raspberry pi.
>>>> However, there seem to be no default idle task.
>>>> If you have
>>>>
>>>> with Text_IO; use Text_IO;
>>>>
>>>> procedure Hello is
>>>>
>>>> task Hello_Task;
>>>>
>>>> task body Hello_Task is
>>>> begin
>>>> delay 5.0;
>>>> end Hello_Task;
>>>>
>>>> begin
>>>> [1]
>>>> null;
>>>> end Hello;
>>>>
>>>> The runtime will be terminated after the body of the procedure [1] is executed.
>>>> I think the usual behaviour for Ada would be that instead an idle task is running while the Hello_Task waits.
>>>> At least it works like this if I compile the file for my desktop-PC.
>>>>
>> [...]
>>> None of that is going to help. This is Ada run-time specific. So it is
>>> some behavior that needs to be accounted for.
>>>
>>> Ada tasks are pthreads on both Linux and RTEMS. One simple thing
>>> to do would be to check that the pthread attributes are the same on
>>> the call to pthread_create. I would expect the run-time to be rigorous
>>> in setting all attributes explicitly but if they don't, then we might be
>>> missing the attribute that makes a thread joinable.
>>>
>> The thread creation seems to be basically the same on Linux and Rtems.
>> The thread is created as detached.
>>
>>> Otherwise, we need to figure out where this is in the run-time and
>>> see what is going on.
>>>
>> After reading about the threading implementation of gnat here: http://www.iuma.ulpgc.es/users/jmiranda/gnat-rts/node18.htm#task_steps
>> I looked at the "Complete Master" part. I could find a difference in runtime behaviour in the file /opt/rtems-4.11-pi/lib/gcc/arm-rtems4.11/4.9.3/adainclude/s-tassta.adb
>> From line 1704 - 1746 the master is supposed to count the number of active tasks and afterwards in the loop between l. 1755 - 1777 it is supposed to go to sleep (l. 1775) until the number of active tasks is 0.
>> In Linux this works properly. In Rtems it exits the loop immediately ( exit when Self_ID.Common.Wait_Count = 0; ) and never goes to sleep.
>> So it appears to me that counting the active tasks fails (i.e. it counts 0 ) somehow. Unfortunately I wasn't able to go deeper.
>> Most of the temporary variables are optimized out (according to gdb/ddd). I compiled the toolchain with rsb with --targetcflags and targetcxxflags set to "-O0 -g", but still can't print many variables. Is there another trick to have all these variables accessible as well (performance is not an issue)?
>>
>>> Asking for advice on gcc at gcc.gnu.org might be useful at this point.
>>> Please cc' me if you do that.
>>>> Could someone point me in the right direction?
>>>>
>>>> Cheers,
>>>>
>>>> Jan
>>>>
>>>> _______________________________________________
>>>> users mailing list
>>>> users at rtems.org
>>>> http://lists.rtems.org/mailman/listinfo/users
>>>
>>>
>> _______________________________________________
>> users mailing list
>> users at rtems.org
>> http://lists.rtems.org/mailman/listinfo/users
--
-- Joel Sherrill
Ask me about RTEMS: a free RTOS
Support and Training Available
More information about the users
mailing list