成功交换上下文后返回函数执行时出现段错误 [英] Seg fault when returning to function execution after successful swapcontext

查看:93
本文介绍了成功交换上下文后返回函数执行时出现段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个库来使用上下文(getcontext,setcontext,makecontext,swapcontext)来管理线程,而没有pthreads.

I'm trying to write a library to manage threads using contexts(getcontext, setcontext, makecontext, swapcontext), without pthreads.

函数MyThreadYield(),暂停当前线程上下文,将其发送到就绪队列的末尾,并在就绪队列的开头开始执行线程.

A function MyThreadYield(), pauses the current thread context, sends it to the end of ready queue and starts executing the thread at the head of ready queue.

在MyThreadYield()中,我可以通过swapcontext()检索暂停的线程的上下文,但是仅当它返回到函数执行时,才出现段错误.

In MyThreadYield(), I am able to retrieve context of paused thread via swapcontext() but just when it is returning to the function execution I get a segfault.

例如:-假设线程1是初始化线程,它运行并创建线程2.然后产生.现在线程2运行,并依次调用yield.交换上下文在这里运行,我可以通过%p"验证交换是否成功.但是,当它尝试从MyThreadYield()返回以恢复线程1的功能运行时,我遇到了段错误.

Eg :- Suppose thread 1 is the init thread, it runs and creates thread 2. Then it yields. Now thread 2 runs and in turn calls yield. Here the swapcontext runs and I can verify that swap is successful through "%p". But when it tries to return from MyThreadYield() to restore function run of thread 1, I'm getting seg fault.

这是我的图书馆代码:-

Here is my library code :-

        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);
        }

这是使用此库的程序:-

Here is the program which uses this library :-

            #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");
            }

这是传递了参数n = 2的程序的输出:-

And here is the output for the program with argument n=2 passed :-

            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)

正如您在上面看到的那样,我的调试消息表明地址已正确交换,因此我无法弄清楚段错误的原因.

As you can see above, my debug messages indicate that addresses are properly exchanged, so I'm not able to figure out the reason for segfault.

尝试使用gdb对其进行调试,但我不知所措,仍然毫无头绪.

Tried debugging it using gdb, but I'm at my wits end and still without any clue.

任何帮助将不胜感激!

推荐答案

我能够通过朋友的帮助解决此问题. 我非常愚蠢和微不足道的错误. 我试图通过本地堆栈将内存分配给上下文,这可能会被杀死并导致问题.参见下面的注释行:-

I was able to solve this through a friend's help. Very stupid and trivial mistake by me. I was trying to allocate memory to context via a local stack which probably gets killed and causes problems. See commented lines below :-

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

在将以上几行更改为以下内容并使用直接分配后,我的代码运行良好.

On changing above lines to the following and using direct allocation, my code ran fine.

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

这篇关于成功交换上下文后返回函数执行时出现段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆