Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2038956
  • 博文数量: 369
  • 博客积分: 10093
  • 博客等级: 上将
  • 技术积分: 4271
  • 用 户 组: 普通用户
  • 注册时间: 2005-03-21 00:59
文章分类

全部博文(369)

文章存档

2013年(1)

2011年(2)

2010年(10)

2009年(16)

2008年(33)

2007年(146)

2006年(160)

2005年(1)

分类:

2006-02-21 19:11:09

用ansi c 的setjmp和longjmp实现了协作式多任务,真的没有一句汇编哦!希望能够帮助大家理解进程间切换,和验证各种进程调度算法(只要更改schedule函数和task_struct结构即可)。只是为了学习,实际上可能没有任何可用性。代码如下:

#include
#include
#include

#define STACK_SIZE 1024
#define TASK_NUM 256

#define LINUX

#ifdef LINUX
#if !defined(JB_PC) && !defined(JB_SP)
#define JB_PC 5
#define JB_SP 4
#define PTR_MANGLE(var) asm ("xorl %%gs:0x18, %0" : "=r"(var) : "0" (var))
#else
#define PTR_MANGLE(var)
#endif
#define EIP buf[0].__jmpbuf[JB_PC]
#define ESP buf[0].__jmpbuf[JB_SP]
#else
#define EIP buf[5];
#define ESP buf[4];
#endif

typedef unsigned long ulong;
typedef long task_t;
typedef void (*task_func) (void *args);

typedef struct task_struct{
        jmp_buf buf;
        int             used;
        ulong   stack[STACK_SIZE];
} task_struct;

static task_struct tasks[TASK_NUM];
static task_t current = 0;

int task_struct_init(void)
{
        int i;

        for(i = 0; i < TASK_NUM; i ++)
                tasks[i].used = 0;

        // create the first task, run in the main function.
        tasks[0].used = 1;

        return 0;
}

int task_create(task_t *pid, task_func func, void *args)
{
        static int i;

        // find a unused task_struct
        for(i = 0; i < TASK_NUM; i ++){
                if(!tasks[i].used){
                        break;
                }
        }
        // found none
        if(i == TASK_NUM) return -1;

        setjmp(tasks[i].buf);
        tasks[i].stack[STACK_SIZE - 1] = (ulong)args;
        tasks[i].ESP = (ulong)(tasks[i].stack + STACK_SIZE - 2);
        PTR_MANGLE(tasks[i].ESP);
        tasks[i].EIP = (ulong)func;
        PTR_MANGLE(tasks[i].EIP);
        tasks[i].used = 1;
        if(pid != NULL){
                *pid = i;
        }

        return 0;
}

int task_exit(void)
{
        tasks[current].used = 0;
        schedule();
}

// return the current pid
task_t gettid(void)
{
        return current;
}

// select a task to run
// return 1 when return to the last task
int schedule(void)
{
        // save the task runtime information
        if(setjmp(tasks[current].buf)){
                return 1;
        }

        // select a active task to run
        while(1){
                current = (current + 1) % TASK_NUM;
                if(tasks[current].used){
                        break;
                }
        }

        // run the task
        longjmp(tasks[current].buf, 1);

        return 0;
}

void t1(const char *ptr)
{
        int i;
        char ch[128];

        for(i = 0; i < 128; i ++){
                ch[i] = '0';
                printf("task %d: %s.\n", gettid(), ptr);
                schedule();
        }

        task_exit();
}

void t2(const char *ptr)
{
        while(1){
                printf("task %d: %s.\n", gettid(), ptr);
                // try to add a new task
                task_create(NULL, (task_func)&t1, "one(in two)");
                schedule();
        }
}

void t3(const char *ptr)
{
        char *buf;

        while(1){
                buf = (char*)malloc(256);
                printf("task %d: %s.\n", gettid(), ptr);
//              printf("Please input sth. :");
//              scanf("%s", buf);
//              printf("Your input is : %s\n", buf);
                free(buf);
                schedule();
        }
}

int main(void)
{
        task_struct_init();

        task_create(NULL, (task_func)&t1, "one");
        task_create(NULL, (task_func)&t2, "two");
        task_create(NULL, (task_func)&t3, "three");

        while(1){
                printf("task %d: core.\n", gettid());
                schedule();
        }

        return 0;
}

编译方法:
默认是在Linux平台上可编译的。如果需要在Windows下编译,请注释掉

#define LINUX

注意
因为较新版的glibc不再导出jmp_buf的内部结构,并且用指针重写技术对其内部的BP、SP和IP等进行了保护,所以不再推荐用此方法实现协作多任务。如果是UNIX/Linux系统,可以选择基于setcontext/getcontext来实现。本文中针对此问题的hack方法只对x86(32bit)系统有效。

Have fun with it.

参考资料:

[1]
阅读(2536) | 评论(2) | 转发(1) |
0

上一篇:2006 新年新气象

下一篇:Linux模块编程

给主人留下些什么吧!~~