程序员人生 网站导航

用户态实现线程调度(任务调度)

栏目:php教程时间:2015-03-16 11:02:20

代码适用于X86与X86_64架构。

不支持抢占,任务只能自己让出CPU。

下面是代码,将代码全部复制到1个.c文件中,便可编译运行。

/* * 本软件为免费、开源软件。 * 本软件的版权(包括源码及2进制发布版本)归1切公众所有。 * 您可以自由使用、传播本软件。 * 您也能够以任何情势、任何目的使用本软件(包括源码及2进制发布版本),而不受任何版权限制。 * ===================== * 作者: 孙明保 * 邮箱: sunmingbao@126.com */ /* * 本程序实现了用户态的任务调度。 * 适用于X86及X86_64架构。 * 编译运行方法: * [root@localhost ~]# gcc sched.c * [root@localhost ~]# ./a.out */ #include <stdio.h> #include <string.h> #define MAX_TASK_NUM (10) #define TASK_STACK_SIZE (4096) #define DBG_PRINT(fmt, args...) do { printf("DBG:%s(%d)-%s: "fmt" ", __FILE__,__LINE__,__FUNCTION__,##args); } while (0) typedef void * (*task_entry_ptr) (void *); typedef struct { char name[64]; unsigned long state; task_entry_ptr entry; unsigned long ret; unsigned long sp; unsigned long pc; unsigned long stack[TASK_STACK_SIZE/sizeof(unsigned long)]; } __attribute__((packed)) t_task; #define STATE_INVALID (0) #define STATE_SLEEPING (1) #define STATE_RUNNING (2) #define STATE_FINISHED (3) t_task g_at_tasks[MAX_TASK_NUM]; int g_task_cnt = 0; #define task_ptr2idx(ptr) ((t_task *)(ptr)-g_at_tasks) unsigned long process_main_thread_sp; t_task *pt_cur_running_task; unsigned long prev_task_sp, prev_task_pc; unsigned long next_task_sp, next_task_pc; #if defined( __i386) #define save_context(mem_var_to_save_sp) do { asm volatile("pushfl " /* save flags */ "pushl %%eax " "pushl %%edi " "pushl %%esi " "pushl %%edx " "pushl %%ecx " "pushl %%ebx " "pushl %%ebp " "movl %%esp,%[mem_var_to_store_sp] " : [mem_var_to_store_sp] "=m" (mem_var_to_save_sp) ); } while (0) #define restore_context(mem_var_saved_sp) do { asm volatile("movl %[mem_var_contain_sp],%%esp " "popl %%ebp " "popl %%ebx " "popl %%ecx " "popl %%edx " "popl %%esi " "popl %%edi " "popl %%eax " "popfl " :: [mem_var_contain_sp] "m" (mem_var_saved_sp) ); } while (0) #elif defined( __x86_64) #define save_context(mem_var_to_save_sp) do { asm volatile("pushfq " /* save flags */ "pushq %%rax " "pushq %%rdi " "pushq %%rsi " "pushq %%rdx " "pushq %%rcx " "pushq %%rbx " "pushq %%rbp " "movq %%rsp,%[mem_var_to_store_sp] " : [mem_var_to_store_sp] "=m" (mem_var_to_save_sp) ); } while (0) #define restore_context(mem_var_saved_sp) do { asm volatile("movq %[mem_var_contain_sp],%%rsp " "popq %%rbp " "popq %%rbx " "popq %%rcx " "popq %%rdx " "popq %%rsi " "popq %%rdi " "popq %%rax " "popfq " :: [mem_var_contain_sp] "m" (mem_var_saved_sp) ); } while (0) #endif int i; int task_scheduler() { unsigned long ret; #if defined( __i386) asm volatile("movl %%eax,%[task_ret] " : [task_ret] "=m" (ret) ); #elif defined( __x86_64) asm volatile("movq %%rax,%[task_ret] " : [task_ret] "=m" (ret) ); #endif if (pt_cur_running_task) { pt_cur_running_task->state=STATE_FINISHED; pt_cur_running_task->ret=ret; DBG_PRINT("task %s exit with code %lu", pt_cur_running_task->name, pt_cur_running_task->ret); } for (i=0;i<MAX_TASK_NUM;i++) { pt_cur_running_task = &(g_at_tasks[i]); if (pt_cur_running_task->state==STATE_SLEEPING) { pt_cur_running_task->state=STATE_RUNNING; next_task_sp = pt_cur_running_task->sp; next_task_pc = pt_cur_running_task->pc; /* 准备运行下1个可运行任务 */ restore_context(next_task_sp); asm volatile("jmp *%[next_pc] " :: [next_pc] "m" (next_task_pc) ); } } DBG_PRINT("==no task to run. so we exit"); restore_context(process_main_thread_sp); return 0; } #define push_task_stack(sp, data) do { sp--; *sp = data; } while (0) int create_task(const char *name, void *task_entry, void *para) { unsigned long *sp; t_task *pt_task = &(g_at_tasks[g_task_cnt]); strncpy(pt_task->name, name, sizeof(pt_task->name)); pt_task->entry = task_entry; pt_task->sp = (unsigned long)((void *)(pt_task + 1)); pt_task->state = STATE_SLEEPING; sp = (void *)(pt_task->sp); #if defined( __i386) push_task_stack(sp, (unsigned long)para); #endif push_task_stack(sp, (unsigned long)(void *)&task_scheduler); pt_task->pc = (unsigned long)task_entry; push_task_stack(sp, 0); push_task_stack(sp, 0); #if defined( __i386) push_task_stack(sp, 0); #elif defined( __x86_64) push_task_stack(sp, (unsigned long)para); #endif push_task_stack(sp, 0); push_task_stack(sp, 0); push_task_stack(sp, 0); push_task_stack(sp, 0); push_task_stack(sp, pt_task->sp); /* push bp at last */ pt_task->sp = (unsigned long)(void *)sp; g_task_cnt++; return 0; } #if defined( __i386) #define switch_context(prev, next) do { asm volatile("pushfl " "pushl %%eax " "pushl %%edi " "pushl %%esi " "pushl %%edx " "pushl %%ecx " "pushl %%ebx " "pushl %%ebp " "movl %%esp,%[prev_sp] " "movl $1f,%[prev_pc] " "movl %[next_sp],%%esp " "popl %%ebp " /* restore BP */ "popl %%ebx " "popl %%ecx " "popl %%edx " "popl %%esi " "popl %%edi " "popl %%eax " "popfl " "jmp *%[next_pc] " "1: " "nop " : [prev_sp] "=m" (prev->sp), [prev_pc] "=m" (prev->pc) : [next_sp] "m" (next_task_sp), [next_pc] "m" (next_task_pc) ); }while (0) #elif defined( __x86_64) #define switch_context(prev, next) do { asm volatile("pushfq " "pushq %%rax " "pushq %%rdi " "pushq %%rsi " "pushq %%rdx " "pushq %%rcx " "pushq %%rbx " "pushq %%rbp " "movq %%rsp,%[prev_sp] " "movq $1f,%[prev_pc] " "movq %[next_sp],%%rsp " "popq %%rbp " /* restore BP */ "popq %%rbx " "popq %%rcx " "popq %%rdx " "popq %%rsi " "popq %%rdi " "popq %%rax " "popfq " "jmp *%[next_pc] " "1: " "nop " : [prev_sp] "=m" (prev->sp), [prev_pc] "=m" (prev->pc) : [next_sp] "m" (next_task_sp), [next_pc] "m" (next_task_pc) ); }while (0) #endif void schedule() { t_task *prev=pt_cur_running_task, *next=NULL; int cur_task_idx=task_ptr2idx(prev); for (i=cur_task_idx+1; i!=cur_task_idx; i=(i+1)%MAX_TASK_NUM) { next = &(g_at_tasks[i]); if (next->state==STATE_SLEEPING) { pt_cur_running_task->state=STATE_SLEEPING; prev_task_sp = pt_cur_running_task->sp; prev_task_pc = pt_cur_running_task->pc; pt_cur_running_task = next; pt_cur_running_task->state=STATE_RUNNING; next_task_sp = pt_cur_running_task->sp; next_task_pc = pt_cur_running_task->pc; break; } } if (i==cur_task_idx) return; switch_context(prev, next); } int start_sched() { /* 启动调度,首个运行的任务是 father_of_all_task - g_at_tasks[0] */ save_context(process_main_thread_sp); task_scheduler(); return 0; } /* 以上是调度功能的实现,下面是使用示例 */ int task_1_para=1001; void * usr_task1(void *para) { int i; DBG_PRINT("==enter, para=%d", *(int *)para); for (i=10; i<13; i++) { DBG_PRINT("==%d", i); schedule(); } DBG_PRINT("==exit"); return (void *)100UL; } int task_2_para=2001; void * usr_task2(void *para) { int i; DBG_PRINT("==enter, para=%d", *(int *)para); for (i=20; i<23; i++) { DBG_PRINT("==%d", i); schedule(); } DBG_PRINT("==exit"); return (void *)200UL; } int task_3_para=3001; void * usr_task3(void *para) { int i; DBG_PRINT("==enter, para=%d", *(int *)para); for (i=30; i<33; i++) { DBG_PRINT("==%d", i); schedule(); } DBG_PRINT("==exit"); return (void *)300UL; } int root_task_para=1234; void * father_of_all_task(void *para) { DBG_PRINT("==enter, para=%d", *(int *)para); create_task("usr_task1", usr_task1, &task_1_para); create_task("usr_task2", usr_task2, &task_2_para); create_task("usr_task3", usr_task3, &task_3_para); DBG_PRINT("==exit"); return (void *)2015UL; } int main(int argc, char *argv[]) { DBG_PRINT("hello"); create_task("father_of_all_task", father_of_all_task, &root_task_para); start_sched(); DBG_PRINT("good bye"); return 0; }

软件运行效果:



[root@localhost ~]# gcc sched.c 
[root@localhost ~]# ./a.out 
DBG:sched.c(371)-main:
hello
DBG:sched.c(361)-father_of_all_task:
==enter, para=1234
DBG:sched.c(365)-father_of_all_task:
==exit
DBG:sched.c(145)-task_scheduler:
task father_of_all_task exit with code 2015
DBG:sched.c(320)-usr_task1:
==enter, para=1001
DBG:sched.c(323)-usr_task1:
==10
DBG:sched.c(334)-usr_task2:
==enter, para=2001
DBG:sched.c(337)-usr_task2:
==20
DBG:sched.c(348)-usr_task3:
==enter, para=3001
DBG:sched.c(351)-usr_task3:
==30
DBG:sched.c(323)-usr_task1:
==11
DBG:sched.c(337)-usr_task2:
==21
DBG:sched.c(351)-usr_task3:
==31
DBG:sched.c(323)-usr_task1:
==12
DBG:sched.c(337)-usr_task2:
==22
DBG:sched.c(351)-usr_task3:
==32
DBG:sched.c(326)-usr_task1:
==exit
DBG:sched.c(145)-task_scheduler:
task usr_task1 exit with code 100
DBG:sched.c(340)-usr_task2:
==exit
DBG:sched.c(145)-task_scheduler:
task usr_task2 exit with code 200
DBG:sched.c(354)-usr_task3:
==exit
DBG:sched.c(145)-task_scheduler:
task usr_task3 exit with code 300
DBG:sched.c(167)-task_scheduler:
==no task to run. so we exit
DBG:sched.c(374)-main:
good bye
[root@localhost ~]# 

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐