0

Today I have a little proble and I think that the origin is about the stack.

This is my problem :

I declare three user task like this :

void task1Function(void) {
    print_uart0("-usertask : First task is started...\r\n");
    while(1){
        //syscall(1);
    }
}

void task2Function(void) {
        print_uart0("-usertask : Second task is running...\r\n");
        //syscall(); /* To return in the kernel's mode */
        while(1){

        }
}

 void task3Function(void) {
            print_uart0("-usertask : Third task is running...\r\n");
            //syscall(); /* To return in the kernel's mode */
            while(1){

            }
    }

I have an array of three task whose the strucure is below :

typedef struct
{

    unsigned int *sp;
    unsigned int registers[12];
    unsigned int lr;
    unsigned int pc;
    unsigned int cpsr;
    unsigned int mode;
    unsigned int num;
    void *stack;
    int stacksize;

    int priority;
    int state;                    /* Running, Ready, Waiting, Suspended */

    /* Next and previous task in the queue */
    struct taskstruct *qnext, *qprev;
}taskstruct;

Here the inialisation of my tasks :

void init_task(taskstruct * task, void (*function)(void) ){
    task->sp = (unsigned int*)&function;
    task->registers[0] = 0; // r0
    task->registers[1] = 0; // r1
    task->registers[2] = 0; // r2
    task->registers[3] = 0; // r3
    task->registers[4] = 0; // r4
    task->registers[5] = 0; // r5
    task->registers[6] = 0; // r6
    task->registers[7] = 0; // r7
    task->registers[8] = 0; // r8
    task->registers[9] = 0; // r9
    task->registers[10] = 0; // r10
    task->registers[11] = 0; // r11
    task->registers[12] = 0; // r12
    task->lr = 0;
    task->pc = 0;
    task->cpsr = 0;
    task->mode = 0x10;
}

init_task(&task[0],&task1Function);
init_task(&task[1],&task2Function);
init_task(&task[2],&task3Function);

But when I passed the task[0].sp to my activate function, it's always the last declared task that is launched (i.e the third):

.global activate
activate:

LDR r12, [r0]
/*STMFD sp!,{r1-r11,lr}*/
NOP

msr CPSR_c, #0x10 /* User mode with IRQ enabled and FIQ disabled*/
mov pc, r12

So I guess that I have a problem with my user stack and that I have to setup a different stack for each of them, am I right ? In this case, can somebody tell me how I have to proceed ?

Regards, Vincent

Aki Suihkonen
  • 19,144
  • 1
  • 36
  • 57
deletMe
  • 65
  • 2
  • 9
  • 1
    `task->sp = (unsigned int*)&function;` is confusing. Shouldn't that be `pc` instead of `sp`? Also, it should probably be `(unsigned int*)function`. I don't think it's a good idea to rely on how the C compiler generates code to set up the stack frame and allocate space for local variables. The code that manipulates the stack pointer should be written in assembly and have all the info necessary to do said manipulations correctly, irrespective of what compiler is in use or what optimization options are in effect. – Alexey Frunze Feb 26 '13 at 14:05
  • &function will point to the stack of caller of init_task(); I'd suggest that caller of init_task allocates the stack for each task and separates them from task context (Stack Overflow would corrupt the registers of other tasks as well). – Aki Suihkonen Feb 26 '13 at 14:15
  • Ok but how I can allocate the stack task ? – deletMe Feb 26 '13 at 16:27

2 Answers2

2

Yes, you are right.

You must have separate stacks for each task, since the state of the stack is part of the task's total state.

You could add something like

uint32_t stack[512];

to your taskstruct, and then set/restore the task pointer accordingly when switching tasks, of course. It's hard to provide enough detail in this context.

unwind
  • 391,730
  • 64
  • 469
  • 606
0

'Ok but how I can allocate the stack task ? ' - malloc it.

You can economize on mallocs by adding the stack space on the end of the taskstruct - all your current members are fixed-size, so calculating the total size to malloc is easy.

The hard bit with these taskers is getting the interrupt entry correct, ie. when an interrupt handler needs to change a task state and so has to exit via the scheduler. This is especially good fun with nested interrupts. Good luck with that!

Martin James
  • 24,453
  • 3
  • 36
  • 60
  • Ok, I've added a stack in my structure like this : char stack[256]. I make my task[x].sp point to this stack. I make my task[x].pc point to my user function. But I think I'm wrong cause it doesn't work. Is the function's address has to be in the stack and then make my task[x].pc point on it ? More, I've already set a stack for my user mode and I don't understand why I have to divide it for my user task. – deletMe Mar 01 '13 at 16:17