使用ucontext&;信号

使用ucontext&;信号,c,osx-yosemite,scheduler,ucontext,user-thread,C,Osx Yosemite,Scheduler,Ucontext,User Thread,我正在设计一种调度算法,它具有以下特性: 在一个进程中有2个用户线程(上下文)(我本应该做3个线程,但这在osx上还不起作用,所以我决定现在做2个) 使用SIGALRM信号进行抢占,该信号每1秒关闭一次,并将控件从一个上下文更改为另一个上下文,并保存切换前正在运行的上下文的当前状态(寄存器和当前位置) 我注意到的是: ucontext.h库在mac osx上的行为很奇怪,而当它应用于Linux时,它的行为与预期的完全相同(这个man链接中的示例:在Linux上它的工作方式与预期的一样完美,

我正在设计一种调度算法,它具有以下特性:

  • 在一个进程中有2个用户线程(上下文)(我本应该做3个线程,但这在osx上还不起作用,所以我决定现在做2个)
  • 使用SIGALRM信号进行抢占,该信号每1秒关闭一次,并将控件从一个上下文更改为另一个上下文,并保存切换前正在运行的上下文的当前状态(寄存器和当前位置)
我注意到的是:

  • ucontext.h库在mac osx上的行为很奇怪,而当它应用于Linux时,它的行为与预期的完全相同(这个man链接中的示例:在Linux上它的工作方式与预期的一样完美,而在mac上,它在进行任何交换之前会出现分段错误)。不幸的是,我必须让它在osx上运行,而不是在linux上运行
  • 通过使用getcontext()&然后使用setcontext()来交换上下文,我成功地解决了osx上的swapcontext错误
  • 在我的信号处理函数中,我使用了sa_sigaction(int sig,siginfo_t*s,void*cntxt),因为第三个变量作为ucontext重新浇铸后,它是关于被中断的上下文的信息(在Linux上测试后,它是正确的)但在mac上,它并没有指向正确的位置,因为当我使用它时,我再次遇到了分割错误
我已经为每个上下文设计了测试函数,以便在while循环中循环,因为我想中断它们,并确保它们返回到该函数中的正确位置执行。我定义了一个静态全局计数变量,它可以帮助我查看我是否处于正确的用户线程中

最后一个注意事项是,我发现在测试函数中调用while循环中的getcontext()会不断更新当前上下文的位置,因为它是空的while循环,因此在该上下文出现时调用setcontext()会使它从正确的位置执行。此解决方案是冗余的,因为这些函数将从API外部提供

    #include <stdio.h>
    #include <sys/ucontext.h>
    #include <string.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include <errno.h>

    /*****************************************************************************/
    /*                            time-utility                                   */
    /*****************************************************************************/

    #include <sys/time.h> // struct timeval

    void timeval_add_s( struct timeval *tv, uint64_t s ) {
        tv->tv_sec += s;
    }

    void timeval_diff( struct timeval *c, struct timeval *a, struct timeval *b ) {

        // use signed variables
        long aa;
        long bb;
        long cc;

        aa = a->tv_sec;
        bb = b->tv_sec;
        cc = aa - bb;
        cc = cc < 0 ? -cc : cc;
        c->tv_sec = cc;

        aa = a->tv_usec;
        bb = b->tv_usec;
        cc = aa - bb;
        cc = cc < 0 ? -cc : cc;
        c->tv_usec = cc;

    out:
        return;
    }

    /******************************************************************************/
    /*                              Variables                                    */
    /*****************************************************************************/
    static int count;

    /* For now only the T1 & T2 are used */
    static ucontext_t T1, T2, T3, Main, Main_2;
    ucontext_t *ready_queue[ 4 ] = { &T1, &T2, &T3, &Main_2 };

    static int thread_count;
    static int current_thread;

    /* timer struct */
    static struct itimerval a;
    static struct timeval now, then;

    /* SIGALRM struct */
    static struct sigaction sa;

    #define USER_THREAD_SWICTH_TIME 1

    static int check;

    /******************************************************************************/
    /*                                 signals                                    */
    /*****************************************************************************/

    void handle_schedule( int sig, siginfo_t *s, void * cntxt ) {
        ucontext_t * temp_current = (ucontext_t *) cntxt;

        if( check == 0 ) {
            check = 1;
            printf("We were in main context user-thread\n");
        } else {
            ready_queue[ current_thread - 1 ] = temp_current;
            printf("We were in User-Thread # %d\n", count );
        }

        if( current_thread == thread_count ) {
            current_thread = 0;
        }
        printf("---------------------------X---------------------------\n");

        setcontext( ready_queue[ current_thread++ ] );

    out:
        return;
    }

    /* initializes the signal handler for SIGALARM, sets all the values for the alarm */
    static void start_init( void ) {
        int r;

        sa.sa_sigaction = handle_schedule;
        sigemptyset( &sa.sa_mask );
        sa.sa_flags = SA_SIGINFO;

        r = sigaction( SIGALRM, &sa, NULL );
        if( r == -1 ) {
            printf("Error: cannot handle SIGALARM\n");
            goto out;
        }

        gettimeofday( &now, NULL );
        timeval_diff( &( a.it_value ), &now, &then );

        timeval_add_s( &( a.it_interval ), USER_THREAD_SWICTH_TIME );
        setitimer( ITIMER_REAL, &a, NULL );

    out:
        return;
    }

    /******************************************************************************/
    /*                      Thread Init                                           */
    /*****************************************************************************/

    static void thread_create( void * task_func(void), int arg_num, int task_arg ) {
        ucontext_t* thread_temp = ready_queue[ thread_count ];

        getcontext( thread_temp );

        thread_temp->uc_link = NULL;
        thread_temp->uc_stack.ss_size = SIGSTKSZ;
        thread_temp->uc_stack.ss_sp = malloc( SIGSTKSZ );
        thread_temp->uc_stack.ss_flags = 0;

        if( arg_num == 0 ) {
            makecontext( thread_temp, task_func, arg_num );
        } else {
            makecontext( thread_temp, task_func, arg_num, task_arg );
        }

        thread_count++;

    out:
        return;
    }

    /******************************************************************************/
    /*                            Testing Functions                               */
    /*****************************************************************************/

    void thread_funct( int i ) {

        printf( "---------------------------------This is User-Thread #%d--------------------------------\n", i );
        while(1) { count = i;} //getcontext( ready_queue[ 0 ] );}

    out:
        return;
    }

    void thread_funct_2( int i ) {
        printf( "---------------------------------This is User-Thread #%d--------------------------------\n", i );
        while(1) { count = i;} //getcontext( ready_queue[ 1 ] ); }

    out:
        return;
    }

    /******************************************************************************/
    /*                               Main Functions                               */
    /*****************************************************************************/

    int main( void ) {
        int r;
        gettimeofday( &then, NULL );

        thread_create( (void *)thread_funct, 1, 1);
        thread_create( (void *)thread_funct_2, 1, 2);

        start_init();

        while(1);

        printf( "completed\n" );

    out:
        return 0;
    }
#包括
#包括
#包括
#包括
#包括
#包括
#包括
/*****************************************************************************/
/*时间效用*/
/*****************************************************************************/
#include//struct timeval
无效时间值添加(结构时间值*电视,uint64){
电视->电视秒+=s;
}
void timeval_diff(struct timeval*c、struct timeval*a、struct timeval*b){
//使用有符号变量
长aa;
长bb;
长cc;
aa=a->tv_秒;
bb=b->tv_秒;
cc=aa-bb;
cc=cc<0?-cc:cc;
c->tv_sec=cc;
aa=a->tv\U usec;
bb=b->tv\U usec;
cc=aa-bb;
cc=cc<0?-cc:cc;
c->tv_usec=cc;
输出:
返回;
}
/******************************************************************************/
/*变数*/
/*****************************************************************************/
静态整数计数;
/*目前仅使用T1和T2*/
静态ucontext_t T1、T2、T3、Main、Main_2;
ucontext_t*ready_queue[4]={&T1、&T2、&T3、&Main_2};
静态int线程计数;
静态int电流_线程;
/*计时器结构*/
静态结构itimerval a;
静态结构timeval现在,然后;
/*SIGALRM结构*/
静态结构;
#定义用户线程开关时间1
静态整数检查;
/******************************************************************************/
/*信号*/
/*****************************************************************************/
无效句柄计划(int sig、siginfo t*s、void*cntxt){
ucontext_t*温度_电流=(ucontext_t*)cntxt;
如果(检查==0){
检查=1;
printf(“我们在主上下文用户线程中\n”);
}否则{
就绪队列[当前线程-1]=临时线程当前;
printf(“我们在用户线程中#%d\n”,计数);
}
if(当前线程==线程计数){
当前线程=0;
}
printf(“------------------------------------X-----------------\n”);
setcontext(ready_queue[current_thread++]);
输出:
返回;
}
/*初始化SIGALARM的信号处理程序,设置报警的所有值*/
静态void start_init(void){
INTR;
sa.sa_sigaction=处理计划;
sigemptyset(和sa.sa_面具);
sa.sa_flags=sa_SIGINFO;
r=sigaAction(SIGALRM,&sa,NULL);
如果(r==-1){
printf(“错误:无法处理SIGALARM\n”);
出去;
}
gettimeofday(&now,NULL);
timeval_diff(&(a.it_值)、&now和then);
timeval_add_s(&(a.it_interval),USER_THREAD_swith_TIME);
setitimer(ITIMER_REAL,&a,NULL);
输出:
返回;
}
/******************************************************************************/
/*线程初始化*/
/*****************************************************************************/
静态void线程创建(void*task\u func(void)、int arg\u num、int task\u arg){
ucontext_t*thread_temp=ready_queue[thread_count];
getcontext(线程温度);
线程温度->uc链接=NULL;
螺纹温度->uc_stack.ss_尺寸=SIGSTKSZ;
线程温度->uc_stack.ss_sp=malloc(SIGSTKSZ);
线程温度->uc_stack.ss_标志=0;
如果(arg_num==0){