Newsgroup: it.comp.lang.c
Titolo: Per esperti: consiglio su uso di longjump/setjump per scrivere un RTOS

ciao,
 usando le funzioni ANSI C: longjump() and setjump(), ho scritto
 uno scheletro di un sistema opertativo non preemptive che permette
 ai vari task di essere interrotti e poi di ripartire nello
 stesso punto dove questi avevano richiesto la sospensione.
 Quando un task richiede la sospensione uso setjump() e memorizzo
 lo stato dei registri e lo SP, poi con longjump() ritorno nel
 punto dove avevo sospeso il task.
 
 La mia domanda e': c'e' qualche rischio ad usare continuamente
 salti non locali?
 Esempio semplificato:
 void miotask(void) {
     longjump();
     if (pippo > pluto) {
         while (topolino) {
             if (a == 1) {
                 a++;
                 setjump();   
                 return;   /* Prima sospensione */
 
                 b++;     /* Rientro dopo la prima sospensione */
                 a += b;
                 setjump(); /* Seconda sospensione */
                 return;
 
                 c = a + b;           /* Rientro dopo la seconda sospensione */
             }
         } 
     }     
 }
 
 
Qui invece c'e' il codice compilabile su ogni piattaforma ANSI C.
Questo codice gira bene pero' giustamente non permette di memorizzare
lo stato delle variabili locali.
 Enrico
 
#define TASK_SUSPEND(delay)  value = setjmp(taskCB[currentTask].regStack); \
                             if (value == 0) { \
                                 if (delay > 0) { \
                                     taskCB[currentTask].delayTime = delay; \
                                     taskCB[currentTask].suspendTime = sysTime; \
                                     taskCB[currentTask].state = 0x55; \
                                 } \
                                 return; \
                             }
#define TASK_START() if (taskCB[currentTask].firstTime != 0) { \
                       longjmp(taskCB[currentTask].regStack,1); \
                     }\
                     else {\
                         taskCB[currentTask].firstTime = 0x55;\
                     }
 typedef struct TaskCB_s {
  jmp_buf regStack;
  int firstTime;
  int state;      /* 0x00 = READY; Ox55 = SUSPENDED */
  int delayTime;
  int suspendTime;
  void (*function) (void);
} TaskCB;
#define MAX_TASKS 10
TaskCB taskCB[MAX_TASKS];int sysTime;
int currentTask;
int TaskInit(void) {
    int i;
    for (i = 0;i < MAX_TASKS; i++) {
        taskCB[i].function = NULL;
        taskCB[i].state = 0x00;
        taskCB[i].delayTime = 0;
    } return 0;
}
int TaskRegister(void (*function) (void)) {
    int i;
    for (i = 0; (i < MAX_TASKS) && (taskCB[i].function != NULL); i++);
    if (i >= MAX_TASKS) {
        return -1;
    }
    taskCB[i].function = function; /* Store the function pointer */
    return 0;
}
void TaskScheduler(void) {
    int i;
    currentTask = 0;
    for (i = 0; i < MAX_TASKS; i++) {
        if (taskCB[i].state == 0x00) {
            if (taskCB[i].function != NULL) {
                currentTask = i;
                taskCB[i].function();
            }
        }
        else {
            if ( sysTime - taskCB[i].suspendTime > taskCB[i].delayTime) {
                taskCB[i].state = 0x00; /* wake up the task */
            }
        }
    }
}
void Task4(void) {
        int value;
        int prova = 1;
        long aa = 1;
        long bb = 1;
        long cc = 1;
        long dd = 1;
        char buf[100];
        long ee = 1;
        long ff = 1;
        long gg = 1;
        TASK_START();
        prova = 9;
        buf[20] = 'a';
        printf("Task4: prova = %u",prova);
        TASK_SUSPEND(100);
        while (1) {
            while (1) {
                while (1) {
                     TASK_SUSPEND(90000);
                     printf("Task4: Ciao");
                }
            }
        }
        printf("Task5: prova = %u",prova);
        if (2 > 1 ) {
            if ( 3 > 2) {
                TASK_SUSPEND(1000);
                buf[20];
                printf("Task4: prova = %u",prova);
                {
                    TASK_SUSPEND(100);
                    printf("Task4: ee = %i",ee);
                }
            }
        }
}
void Task5(void) {
        int value;
        int prova = 1;
        long aa = 1;
        long bb = 1;
        long cc = 1;
        long dd = 1;
        char buf[100];
        long ee = 1;
        long ff = 1;
        long gg = 1;
        TASK_START();
        prova = 9;
        buf[20] = 'a';
        printf("Task5: prova = %u",prova);
        TASK_SUSPEND(100);
        while (1) {
            while (1) {
                while (1) {
                     TASK_SUSPEND(90000);
                     printf("Task5: Ciao");
                }
            }
        }
        printf("Task5: prova = %u",prova);
        if (2 > 1 ) {
            if ( 3 > 2) {
                buf[20];
                printf("Task5: prova = %u",prova);
                {
                    TASK_SUSPEND(100);
                    printf("Task5: ee = %i",ee);
                }
            }
        }
}
int main(void) {
    sysTime = 0;
    TaskInit();
    TaskRegister(Task4);
    TaskRegister(Task5);
    while(1) {
        sysTime++;
        TaskScheduler();
    } return 0;
}

                     }
Idem.
Quanto al resto del programma io  sposterei tutto le scheduler in una TU
separate, convertirei le macro in funzioni (al limite inline) e metterei
le variabili globali  come static. In questo modo separi i  task dal OS,
elimini possibili collisioni di nomi  ed impedisci una manipolazione non
corretta dei dati dello scheduler.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Software is like sex; it's better when it's free.
Linus Torvalds