加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

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

发布时间:2020-12-13 20:15:56 所属栏目:PHP教程 来源:网络整理
导读:代码适用于X86与X86_64架构。 不支持抢占,任务只能自己让出CPU。 下面是代码,将代码全部复制到1个.c文件中,便可编译运行。 /* * 本软件为免费、开源软件。 * 本软件的版权(包括源码及2进制发布版本)归1切公众所有。 * 您可以自由使用、传播本软件。 * 您

代码适用于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,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),[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,*(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,*(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,*(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 ~]# 

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读