2014-09-15 2 views
0

J'essaye d'écrire une bibliothèque pour gérer les threads en utilisant des contextes (getcontext, setcontext, makecontext, swapcontext), sans pthreads.Erreur Seg en revenant à l'exécution de la fonction après avoir réussi swapcontext

Une fonction MyThreadYield(), interrompt le contexte du thread en cours, l'envoie à la fin de la file d'attente prête et commence à exécuter le thread en tête de la file d'attente prête.

Dans MyThreadYield(), je suis capable de récupérer le contexte du thread en pause via swapcontext() mais juste quand il retourne à l'exécution de la fonction, je reçois un segfault. Par exemple: - Supposons que le thread 1 est le thread init, il s'exécute et crée le thread 2. Puis il cède. Maintenant, le thread 2 s'exécute et, à son tour, les appels donnent. Ici, le swapcontext s'exécute et je peux vérifier que l'échange est réussi avec "% p". Mais quand il essaye de retourner de MyThreadYield() pour restaurer la fonction de thread 1, je suis en erreur.

Voici mon code de bibliothèque: -

 typedef void *MyThread; 
     typedef void *MySemaphore; 
     #include <stdio.h> 
     #include <stdlib.h> 
     #include <malloc.h> 
     #include <ucontext.h> 
     #include <string.h> 

     // structure of threads 
     struct tnode { 
      ucontext_t* ctextptr; 
      int tid; // own thread id 
      int pid; // parent thread id 
     } ; 
     struct tnode* cthread = NULL; 

     // linked list for ready queue 
     struct rnode { 
      struct tnode* thread; 
      struct rnode* next; 
     } ; 
     struct rnode* rhead = NULL; 
     struct rnode* rtail; 

     static int tindex; // will generate thread id (tid) for new threads 

     // linked list for blocked queue 
     struct bnode { 
      struct tnode* thread; 
      struct bnode* next; 
      int wid[20]; // tid of threads bthread is waiting on //limit is 20 
     } ; 
     struct bnode* bhead = NULL; 
     struct bnode* btail; 
     int b; // keeps track of size of bacche 
     int bacche[20]; // array to store children of current running thread 

     //Pushes blocked thread into the blocked linked list 
     void AddToBlist (struct tnode* thd , char s[]) 
     { 
      struct bnode* newbie = NULL; 
      newbie = malloc (sizeof(struct bnode)); 
      newbie->thread = thd; 

      int i; 
      for(i=0; i<20; i++) 
        newbie->wid[i] = 0; 

      char * pch; i=0; 
      pch = strtok(s," ");  //Reference : http://stackoverflow.com/questions/4513316/split-string-in-c-every-white-space 
      while (pch!=NULL) 
      { 
       newbie->wid[i] = atoi(pch); 
       i++; 
       pch = strtok (NULL, " "); 
      } 

      printf("\n thread wait array : \t"); //ff 
      for(i=0; i<20; i++) 
        printf("%d\t",newbie->wid[i]); //ff 

      newbie->next = NULL; 
      btail = newbie; 

      if(bhead==NULL) 
      { 
        bhead = newbie; 
      } else { 
        struct bnode* current = bhead; 
        while (current->next != NULL) 
        { 
          current = current->next; 
        } 
        current->next = newbie; 
      } 
     } 

     // Scan blocked queue to find a matching thread as specified by id 
     int scanB (int id) 
     { 
      int retval = 0; 
      struct bnode* current = bhead; 
      while (current != NULL) 
        { 
          if((current->thread)->tid == id) 
          {  
            retval = 1; 
            break; 
          } 
          current = current->next; 
        } 
      return retval; 
     } 

     // Scan blocked queue for parent id listed 
     int scanBP (int id) 
     { 
      int retval = 0; 
      struct bnode* current = bhead; 
      while (current != NULL) 
        { 
          if((current->thread)->pid == id) 
          {  
            bacche[b] = (current->thread)->tid; 
            b++; 
            retval ++; 
          } 
          current = current->next; 
        } 
      return retval; 
     } 

     // Clears a blocked thread and moves it to ready queue 
     // Reference : https://www.cs.bu.edu/teaching/c/linked-list/delete/ 
     void clearB (int id) 
     { 
      if (bhead==NULL) 
      { 
       //return NULL; 
      } 

      struct bnode* bcur = bhead; 
      struct bnode* bpre = bhead; 

      while (bcur!= NULL) 
      { 
       int i; 
       for(i=0; i<20; i++) 
       { 
        if (bcur->wid[i] == id) 
        { 
         bcur->wid[i] = 0; 
         break; 
        } 
       } 
       int k = 0; 
       for(i=0; i<20; i++) 
       { 
        if (bcur->wid[i] == 0) 
         k++; 
       } 
       if (k==20) 
       { 
        printf("\n thread no longer blocked .... moving to ready queue \n"); //ff 
        AddToRlist(bcur->thread); 
        if (bcur == bhead) 
        { 
         struct bnode* temp = bhead; 
         bhead = bhead->next; 
         free(temp); 
         bcur = bhead; 
         bpre = bhead; 
        } else { 
         struct bnode* temp = bcur; 
         bcur = bcur->next; 
         bpre->next = bcur; 
         free(temp); 
        } 
       } else { 
        bpre = bcur; 
        bcur = bcur->next; 
       } 
      } 
     } 

     //Pushes newly created context into the linked list 
     void AddToRlist (struct tnode* thd) 
     { 
      struct rnode* newbie = NULL; 
      newbie = malloc (sizeof(struct rnode)); 
      newbie->thread = thd; 
      newbie->next = NULL; 
      rtail = newbie; 

      if(rhead==NULL) 
      { 
        rhead = newbie; 
      } else { 
        struct rnode* current = rhead; 
        while (current->next != NULL) 
        { 
          current = current->next; 
        } 
        current->next = newbie; 
      } 
     } 

     // Scan ready queue to find a matching thread as specified by id 
     int scanR (int id) 
     { 
      int retval = 0; 
      struct rnode* current = rhead; 
      while (current != NULL) 
        { 
          if((current->thread)->tid == id) 
          {  
            retval = 1; 
            break; 
          } 
          current = current->next; 
        } 
      return retval; 
     } 

     // Checks for parent id among ready queue elements 
     int scanRP (int id) 
     { 
      int retval = 0; 
      struct rnode* current = rhead; 
      while (current != NULL) 
        { 
          if((current->thread)->pid == id) 
          {  
            bacche[b] = (current->thread)->tid; 
            b++; 
            retval++; 
          } 
          current = current->next; 
        } 
      return retval; 
     } 

     // ****** THREAD OPERATIONS ****** 
     // Create a new thread. 
     MyThread MyThreadCreate(void(*start_funct)(void *), void *args) 
     { 
      tindex++; 
      struct tnode* tnew = NULL; 
      tnew = malloc(sizeof (struct tnode)); 
      memset(tnew, 0, sizeof(struct tnode)); 
      tnew->tid = tindex; 
      tnew->pid = cthread->tid; 

      char stc[8192]; 
      tnew->ctextptr = (ucontext_t *) malloc(sizeof(ucontext_t)); 
      getcontext(tnew->ctextptr); 
      tnew->ctextptr->uc_stack.ss_sp = stc; 
      tnew->ctextptr->uc_stack.ss_size = sizeof stc; 
      tnew->ctextptr->uc_stack.ss_flags = 0; 
      tnew->ctextptr->uc_link = NULL; 

      makecontext(tnew->ctextptr, (void (*)(void))start_funct, 1, args); 
      AddToRlist(tnew); 

      return((MyThread)tnew); 
     } 

     // Yield invoking thread 
     void MyThreadYield(void) 
     { 
      if (rhead == NULL) 
      { 
       return; 
      } else { 
       printf("cthread addr :%p\n",cthread); 
       printf("rhead thd addr :%p\n",rhead->thread); 

       AddToRlist(cthread); 
       cthread = rhead->thread; 
       rhead = rhead->next; 
       printf("rtail thd addr :%p\n",rtail->thread); 
       printf("cthread addr :%p\n",cthread); 
       printf("\n before swap\n"); //ff 
       int ty = swapcontext((rtail->thread)->ctextptr, cthread->ctextptr); 
       printf("\n after swap ty = %d, cthread tid :%d\n",ty,cthread->tid); //ff 
      } 
     } 

     // Join with a child thread 
     int MyThreadJoin(MyThread thread) 
     { 
      if (cthread->tid != ((struct tnode*)thread)->pid) 
      { 
       printf("\n Join Thread not a child of invoking thread, returning -1 \n"); 
       return -1; 
      } 

      int check_rlist = scanR(((struct tnode*)thread)->tid); 
      int check_blist = scanB(((struct tnode*)thread)->tid); 

      if (check_rlist == 0 && check_blist == 0) 
      { 
       printf("\n Join Thread seems to have been terminated, returning -1 \n"); 
       return -1; 
      } 

      printf ("\n Join call successful, proceeding with join operation \n"); 
       int wid = ((struct tnode*)thread)->tid; 
       char w[15]; 
       sprintf(w, "%d", wid); 
       AddToBlist(cthread,w); 
       cthread = rhead->thread; 
       rhead = rhead->next; 
       printf("\n before swap inside join\n"); //ff 
       int tj = swapcontext((btail->thread)->ctextptr, cthread->ctextptr); 
       printf("\n after swap tj = %d, cthread tid :%d\n",tj,cthread->tid); //ff 
     } 

     // Join with all children 
     void MyThreadJoinAll(void) 
     { 
      int k; b=0; 
      for(k=0;k<20;k++) 
       bacche[k]=0; 

      int check_rlist = scanRP(cthread->tid); 
      int check_blist = scanBP(cthread->tid); 

      if (check_blist == 0 && check_rlist == 0) 
      { 
       printf("\n can't find any active children, exiting joinall \n"); 
       return; 
      } 

      printf("\n generated bacche array : \t"); //ff 
      for(k=0;k<20;k++)    //ff 
       printf("%d\t",bacche[k]); //ff 

      int len; 
      char s[50]="\0"; 
      for (k=0;k<b;k++) 
      {  
       char dig = (char)(((int)'0')+bacche[k]); 
       len=strlen(s); 
       s[len]=dig; s[len+1]=' '; s[len+2]='\0'; 
      } 

      printf("\n generated wid string : [%s] \n",s); //ff 
      printf("cthread addr :%p\n",cthread); 
      printf("rhead addr :%p\n",rhead->thread); 
      AddToBlist(cthread,s); 
      cthread = rhead->thread; 
      rhead = rhead->next; 
      printf("\n before swap inside join all\n"); //ff 
      printf("btail tid :%d\n",(btail->thread)->tid); 
      printf("cthread tid :%d\n",cthread->tid); 
      printf("btail thd addr :%p\n",btail->thread); 
      printf("cthread addr :%p\n",cthread); 
      int tj = swapcontext((btail->thread)->ctextptr, cthread->ctextptr); 
      printf("\n after swap tj = %d, cthread tid :%d\n",tj,cthread->tid); //ff 
     } 

     // Terminate invoking thread 
     void MyThreadExit(void) 
     { 
      printf("\n In thread exit \n"); //ff 
      clearB(cthread->tid); //Move threads blocked on current thread to ready queue 
      printf("\n clearB done \n"); //ff 

      printf("\n removing parent (invoking) thread's children \n"); //ff 

      if (rhead == NULL) 
      { 
       printf("\n ready queue is empty, exiting \n"); //ff 
       //cthread = NULL; 
       //setcontext (NULL); 
      } else { 
       cthread = rhead->thread; 
       rhead = rhead->next; 
       printf("cthread tid :%d\n",cthread->tid); 
       setcontext (cthread->ctextptr); 
      } 
     } 


     // ****** SEMAPHORE OPERATIONS ****** 
     // Create a semaphore 
     MySemaphore MySemaphoreInit(int initialValue); 

     // Signal a semaphore 
     void MySemaphoreSignal(MySemaphore sem); 

     // Wait on a semaphore 
     void MySemaphoreWait(MySemaphore sem); 

     // Destroy on a semaphore 
     int MySemaphoreDestroy(MySemaphore sem); 

     // ****** CALLS ONLY FOR UNIX PROCESS ****** 
     // Create and run the "main" thread 
     void MyThreadInit(void(*start_funct)(void *), void *args) 
     { 
      tindex = 1; 

      cthread = malloc (sizeof(struct tnode)); 
      memset(cthread, 0, sizeof(struct tnode)); 
      cthread->tid = tindex; 
      cthread->pid = 0; 

      ucontext_t* ctxmain; 
      ctxmain = (ucontext_t *) malloc(sizeof(ucontext_t)); 
      getcontext(ctxmain); 

      char sti[8192]; 
      cthread->ctextptr = (ucontext_t *) malloc(sizeof(ucontext_t)); 
      getcontext(cthread->ctextptr); 
      cthread->ctextptr->uc_stack.ss_sp = sti; 
      cthread->ctextptr->uc_stack.ss_size = sizeof sti; 
      cthread->ctextptr->uc_link = ctxmain; 
      cthread->ctextptr->uc_stack.ss_flags = 0; 
      makecontext(cthread->ctextptr, (void (*)(void))start_funct, 1, args); 

      swapcontext(ctxmain, cthread->ctextptr); 
     } 

Voici le programme qui utilise cette bibliothèque: -

  #include <stdio.h> 
      #include "mythread.h" 

      int n; 

      void t1(void * who) 
      { 
       int i; 
       printf("\n checkpoint 2 \n"); 
       printf("\n who: %d \n",(int)who); 
       //sleep(5); 
       printf("t%d start\n", (int)who); 
       for (i = 0; i < n; i++) { 
       printf("t%d yield\n", (int)who); 
       printf("\n oogaa \n"); 
       MyThreadYield(); 
       printf("\n boogaa \n"); 
       } 
       printf("t%d end\n", (int)who); 
       MyThreadExit(); 
       printf("\n checkpoint 3 \n"); 
      } 

      void t0(void * dummy) 
      { 
       printf("\n dummy: %d \n",(int)dummy); 
       //sleep(5); 
       printf("\n checkpoint 1 \n"); 
       MyThreadCreate(t1, (void *)1); 
       printf(" hello 6\n"); 
       t1(0); 
       printf("\n checkpoint 4 \n"); 
      } 

      int main(int argc, char *argv[]) 
      { 
       if (argc != 2) 
       return -1; 
       n = atoi(argv[1]); 
       MyThreadInit(t0, (void*)7); 
       printf("\n checkpoint 5 \n"); 
      } 

Et voici la sortie du programme avec l'argument n = 2 passé: -

  eos$ ./ping.exe 2 

      dummy: 7 

      checkpoint 1 
      hello 6 

      checkpoint 2 

      who: 0 
      t0 start 
      t0 yield 

      oogaa 
      cthread addr :0x1151010 
      rhead thd addr :0x1151790 
      rtail thd addr :0x1151010 
      cthread addr :0x1151790 

      before swap 

      checkpoint 2 

      who: 1 
      t1 start 
      t1 yield 

      oogaa 
      cthread addr :0x1151790 
      rhead thd addr :0x1151010 
      rtail thd addr :0x1151790 
      cthread addr :0x1151010 

      before swap 

      after swap ty = 0, cthread tid :1 

      boogaa 
      t0 yield 

      oogaa 
      cthread addr :0x1151010 
      rhead thd addr :0x1151790 
      rtail thd addr :0x1151010 
      cthread addr :0x1151790 

      before swap 

      after swap ty = 0, cthread tid :2 
      Segmentation fault (core dumped) 

Comme vous pouvez le voir ci-dessus, mes messages de débogage indiquent que les adresses sont correctement échangées, donc je ne suis pas en mesure de comprendre la raison de segfault. J'ai essayé de le déboguer en utilisant gdb, mais je suis à bout de nerfs et toujours sans aucune idée.

Toute aide serait grandement appréciée!

+0

Trop long code !!. Déboguez-le d'abord vous-même. –

+0

De toute évidence, vous avez un bug lors de l'enregistrement ou du rechargement du contexte 'thread'. GP enregistre des problèmes de pointeurs écrasés ou empilés, peut-être. Il est très, très difficile pour nous de déboguer un tel code en regardant la source. Si seulement nous avions la source, les exécutables, l'environnement et un débogueur, ce serait beaucoup plus facile. Où pouvons-nous trouver quelqu'un avec toutes ces ressources afin de déboguer efficacement le problème? –

+0

merci les gars et désolé pour le long code et tout. J'ai résolu le problème grâce à un débogage plus poussé et à l'aide d'un ami. J'allouais de la mémoire à thread via une pile locale qui causait le problème. –

Répondre

3

J'ai été capable de résoudre ce problème grâce à l'aide d'un ami. Erreur très stupide et trivial par moi. J'essayais d'allouer de la mémoire au contexte via une pile locale qui est probablement tuée et cause des problèmes. Voir ci-dessous des lignes commentées: -

//char sti[8192]; 
//cthread->ctextptr->uc_stack.ss_sp = sti; 
//cthread->ctextptr->uc_stack.ss_size = sizeof sti; 

En changeant les lignes ci-dessus à ce qui suit et en utilisant l'attribution directe, mon code a fonctionné très bien.

cthread->ctextptr->uc_stack.ss_sp = malloc(8192); 
cthread->ctextptr->uc_stack.ss_size = 8192; 
Questions connexes