搜索
bottom↓
回复: 4

有那位高人用过setjmp,与longjmp啊??

[复制链接]

出0入0汤圆

发表于 2011-2-11 12:49:26 | 显示全部楼层 |阅读模式
今天想了很久都想不明白,程序是怎么样用 setjump longjup 的

//
//
//      task_create(...)里面有一个setjmp();而在schedule()有一对setjmp()
//                                                      longjmp()
//
//     谁能告诉我一下,,,以上setjmp(),longjmp()之间的程序流走向
//
//     schedule()中的longjmp是返回到,task_create()中setjmp呢还是返
//
//          回到 sechedule()中的setjmp中的???????
//
//
#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>

#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]; // 定义TCB 任务控制块   
static task_t current = 0;         

int task_struct_init(void)
{
        int i;

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

        
        tasks[0].used = 1;// 创建第一个任务,在主函数中运行.

        return 0;
}

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

// 获得处理ID    pid
task_t gettid(void)
{
        return current;
}


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

                                                        // 遍历任务,找未用的
        for(i = 0; i < TASK_NUM; i ++){
                if(!tasks.used){
                        break;
                }
        }
                                        // found none
        if(i == TASK_NUM) return -1;

        setjmp(tasks.buf);  //任务的返回点  与longjmp结合吗??  
        tasks.stack[STACK_SIZE - 1] = (ulong)args;
        tasks.ESP = (ulong)(tasks.stack + STACK_SIZE - 2);
        PTR_MANGLE(tasks.ESP);
        tasks.EIP = (ulong)func;
        PTR_MANGLE(tasks.EIP);
        tasks.used = 1;
        if(pid != NULL){
                *pid = i;
        }

        return 0;
}


// 选一个任务
// 运行到最后一个任务时,返回1
int schedule(void)
{
        // 保存任务运行时间信息
        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 = '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);
                // 可加入新的任务;
                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;
}

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2011-2-11 13:38:30 | 显示全部楼层
setjmp和longjmp与操作系统的任务切换大体是一致的,setjmp主要是用在异常处理方面,可以跨函数跳转,用作任务却换是可以的, 但得处理好堆栈,不然堆栈会被覆盖的,到google搜一下它的用法吧!

    粗略看了一下:
    第一次schedule()中的longjmp是返回到task_create()中setjmp ,后面当任务有sechedule()时(即换出时),重新更新任务执行的断点,longjmp是返回到sechedule()中的setjmp。

出0入0汤圆

 楼主| 发表于 2011-2-11 23:23:03 | 显示全部楼层
回复【1楼】charlie2008
-----------------------------------------------------------------------

// 运行到最后一个任务时,返回1
int schedule(void)
{
        // 保存任务运行时间信息
        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;
}

这里我不是很明白!  不是setjmp返回是0的吗? longjmp返回非0的,  程序流是怎么样进去"return  1 "里面的?

出0入0汤圆

发表于 2011-2-11 23:31:35 | 显示全部楼层
回复【2楼】studyplacefor  
-----------------------------------------------------------------------

这里的流程是这样的:
schedule
setjmp 返回0
执行while(1) ....
执行longjmp
跳转到setjmp处, 由于从longjmp()跳转, 返回1
执行return 1

出0入0汤圆

 楼主| 发表于 2011-2-24 17:18:21 | 显示全部楼层
【3楼】 theophilus

多谢你,,
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-16 01:48

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表