studyplacefor 发表于 2011-2-11 12:49:26

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

今天想了很久都想不明白,程序是怎么样用 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.__jmpbuf
#define ESP buf.__jmpbuf
#else
#define EIP buf;
#define ESP buf;
#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;
} task_struct;                     

static task_struct tasks; // 定义TCB 任务控制块   
static task_t current = 0;         

int task_struct_init(void)
{
      int i;

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

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

      return 0;
}

int task_exit(void)
{
      tasks.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 = (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.buf)){
                return 1;
      }

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

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

      return 0;
}

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

      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;
}

charlie2008 发表于 2011-2-11 13:38:30

setjmp和longjmp与操作系统的任务切换大体是一致的,setjmp主要是用在异常处理方面,可以跨函数跳转,用作任务却换是可以的, 但得处理好堆栈,不然堆栈会被覆盖的,到google搜一下它的用法吧!

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

studyplacefor 发表于 2011-2-11 23:23:03

回复【1楼】charlie2008
-----------------------------------------------------------------------

// 运行到最后一个任务时,返回1
int schedule(void)
{
      // 保存任务运行时间信息
      if(setjmp(tasks.buf)){
                return 1;
      }

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

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

      return 0;
}

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

theophilus 发表于 2011-2-11 23:31:35

回复【2楼】studyplacefor
-----------------------------------------------------------------------

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

studyplacefor 发表于 2011-2-24 17:18:21

【3楼】 theophilus

多谢你,,
页: [1]
查看完整版本: 有那位高人用过setjmp,与longjmp啊??