我正在设计一个具有以下特性的调度算法:
我注意到以下几点:
我已经为每个上下文设计了测试函数,使其循环在while循环中,因为我想中断它们,并确保它们返回到函数中的适当位置执行。我定义了一个静态全局计数变量,它帮助我查看是否处于正确的用户线程中。
最后一个注意事项是,我发现在我的while循环中调用getcontext()和测试函数中的getcontext()会不断更新当前上下文的位置,因为它是空的when循环,因此在上下文出现时调用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;
}发布于 2015-11-16 00:41:00
经过几天的测试和调试,我终于得到了这个结果。我不得不深入研究ucontext.h的实现,发现了2 OS之间的不同之处。结果表明,ucontext.h的OSX实现与Linux的实现不同。例如,mcontext_t结构在ucontext_t结构中,n=usually保存寄存器的值(PI、SP、BP、通用寄存器.)在OSX中,每个上下文都声明为指针,而在Linux上则不是。需要设置的其他两个差异--特别是上下文的堆栈指针(rsp)寄存器、基指针(rbp)寄存器、指令指针(rip)寄存器、目标索引(rdi)寄存器.所有这些都必须在开始/创建每个上下文时以及第一次返回之后正确设置。我还使用了top create mcontext结构来保存这些寄存器,并让我的ucontext_t结构的uc_mcontext指针指向它。在完成所有这些工作之后,我能够使用在sa_sigaction信号处理程序函数中作为参数传递的sa_sigaction指针(在我将它重铸到ucontext_t之后),以便完全恢复上次上下文中断的位置。说到底那是件很麻烦的事情。任何对更多细节感兴趣的人都可以给我发信息。JJ出去。
https://stackoverflow.com/questions/33696913
复制相似问题