【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

在操作系统中,线程切换是很重要的一个环节。如果没有线程的切换,我们如何才能实现多线程的并发运行呢?既然要实现切换,那么一方面,我们需要对原来的寄存器进行保存,另外一方面我们还要压入新堆栈的寄存器,这样才能实现线程切换的效果。在x86下面,因为切换线程的ip地址是固定的,所以切换所需要的寄存器也是固定的,一般来说保存eax、ebx、ecx、edx、esi、edi、ebp和esp即可。比如说,像这样,

void swap(UINT32* prev, UINT32* next)
{__asm("push %%eax\n\t""push %%ebx\n\t""push %%ecx\n\t""push %%edx\n\t""push %%esi\n\t""push %%edi\n\t""push %%ebp\n\t""push %%esp\n\t""lea 0x8(%%ebp), %%eax\n\t""mov (%%eax), %%eax\n\t""mov %%esp, (%%eax)\n\t""lea 0xc(%%ebp), %%eax\n\t""mov (%%eax), %%eax\n\t""mov (%%eax), %%esp\n\t""pop %%esp\n\t""pop %%ebp\n\t""pop %%edi\n\t""pop %%esi\n\t""pop %%edx\n\t""pop %%ecx\n\t""pop %%ebx\n\t""pop %%eax\n\t"::);
}

上面说的都是对已经运行的线程进行切换。那么刚刚创建的线程怎么进行切换呢?一个不错的方法就是仿真出栈的处理流程。把初始状态的寄存器放在堆栈里面,模仿线程的出栈过程,设置好线程的初始寄存器数值即可。比如说,像这样,

void signal_handler(int m)
{UINT32* data;UINT32 unit;if(count != 0){printf("count = %d\n", count++);return;}printf("count = %d\n", count++);data = (UINT32*)malloc(STACK_LENGTH);unit = STACK_LENGTH >> 2;if(NULL == data)return;memset(data, 0, STACK_LENGTH);data[unit -1] = (UINT32) hello;data[unit -2] = 0;data[unit -3] = 0;data[unit -4] = 0;data[unit -5] = 0;data[unit -6] = 0;data[unit -7] = 0;data[unit -8] = 0;data[unit -9] = 0;data[unit -10] = (UINT32) &data[unit - 9];new = (UINT32) &data[unit -10];swap(&old, &new);free(data);
}

最后,我们给出一份完整的代码。在程序收到第一个signal的时候,我们发现代码不仅申请了内存,还初始化成了堆栈的格式,完美地解决了堆栈切换的问题。当然在hello处理结束后,代码又恢复成了原来的格式,而且内存正常释放,一切就像没有发生过一样。试想,如果每一次处理的都是一个function和stack,那基本上就可以模仿线程的运行过程了。

#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>#define UINT32 unsigned int
#define STACK_LENGTH 1024static struct itimerval oldtv;
UINT32 old = 0;
UINT32 new = 0;
UINT32 count = 0;void set_timer()
{struct itimerval itv;itv.it_interval.tv_sec = 1;itv.it_interval.tv_usec = 0;itv.it_value.tv_sec = 1;itv.it_value.tv_usec = 0;setitimer(ITIMER_REAL, &itv, &oldtv);
}void swap(UINT32* prev, UINT32* next)
{__asm("push %%eax\n\t""push %%ebx\n\t""push %%ecx\n\t""push %%edx\n\t""push %%esi\n\t""push %%edi\n\t""push %%ebp\n\t""push %%esp\n\t""lea 0x8(%%ebp), %%eax\n\t""mov (%%eax), %%eax\n\t""mov %%esp, (%%eax)\n\t""lea 0xc(%%ebp), %%eax\n\t""mov (%%eax), %%eax\n\t""mov (%%eax), %%esp\n\t""pop %%esp\n\t""pop %%ebp\n\t""pop %%edi\n\t""pop %%esi\n\t""pop %%edx\n\t""pop %%ecx\n\t""pop %%ebx\n\t""pop %%eax\n\t"::);
}void hello()
{printf("hello!\n");swap(&new, &old);
}void signal_handler(int m)
{UINT32* data;UINT32 unit;if(count != 0){printf("count = %d\n", count++);return;}printf("count = %d\n", count++);data = (UINT32*)malloc(STACK_LENGTH);unit = STACK_LENGTH >> 2;if(NULL == data)return;memset(data, 0, STACK_LENGTH);data[unit -1] = (UINT32) hello;data[unit -2] = 0;data[unit -3] = 0;data[unit -4] = 0;data[unit -5] = 0;data[unit -6] = 0;data[unit -7] = 0;data[unit -8] = 0;data[unit -9] = 0;data[unit -10] = (UINT32) &data[unit - 9];new = (UINT32) &data[unit -10];swap(&old, &new);free(data);
}int main()
{set_timer();signal(SIGALRM, signal_handler);while(count < 10);exit(0);return 1;
}

嵌入式操作系统内核原理和开发(线程切换)相关推荐

  1. 嵌入式操作系统内核原理和开发

    嵌入式操作系统内核原理和开发(开篇) 操作系统是很多人每天必须打交道的东西,因为在你打开电脑的一刹那,随着bios自检结束,你的windows系统已经开始运行了.如果问大家操作系统是什么?可能有的人会 ...

  2. 嵌入式操作系统内核原理和开发(总结篇)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 很多朋友都喜欢嵌入式操作系统的内容,但是如何实现和仿真这样一个系统一直是困扰我们的难题.现在郑 ...

  3. 嵌入式操作系统内核原理和开发(cpu的那些事)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] cpu是数字处理系统中的一个重要环节.在我看来,单片机.微处理器.dsp都可以称作是cpu,只 ...

  4. 嵌入式操作系统内核原理和开发(地址空间)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 不管是什么样的嵌入式cpu,它必然有自己的访问地址空间.至于这个具体的访问空间是什么,那cpu ...

  5. 嵌入式操作系统内核原理和开发(线程状态)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com]        从第一篇的os博客以来,谈了很多内容,有中断.切换.调度.内存.互斥和延时等等, ...

  6. 嵌入式操作系统内核原理和开发(消息队列)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 消息队列是线程交互的一种方法,任务可以通过消息队列来实现数据的沟通和交换.在嵌入式系统上,这可 ...

  7. 嵌入式操作系统内核原理和开发(信号量)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 之前因为工作的原因,操作系统这块一直没有继续写下去.一方面是自己没有这方面的经历,另外一方面就 ...

  8. 嵌入式操作系统内核原理和开发(基础)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在编写我们的操作系统之前,我们需要明确一些事情.比如说,这个系统的运行环境是什么?怎么编译?基 ...

  9. 嵌入式操作系统内核原理和开发(开篇)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 操作系统是很多人每天必须打交道的东西,因为在你打开电脑的一刹那,随着bios自检结束,你的wi ...

最新文章

  1. 分享一个Go按行读取命令行输入的例子
  2. java resources目录 编码_关于Java项目读取resources资源文件路径
  3. Linux服务器网卡驱动安装及故障排除(转)
  4. 计算机操作系统指导书,《计算机操作系统》实验指导书-2015
  5. TikZ学习笔记番外篇: 使用tikzcd包绘制交换图
  6. 台风怎么看内存颗粒_【无趣】使用300多元的D4 16G内存是种什么体验
  7. java MAVEN下载的代码仓库位置 mac
  8. Python 中Python 为什么要继承 object 类
  9. AngularJS 控制器 ng-controller
  10. 小车|PID算法 闭环控制 带有 霍尔编码器 的电机
  11. SAP SD销售订单保存提示 定价错误: 必要条件 MWSI 丢失解决方法
  12. mt6771(Helio P60)套片开发资料下载,mt6771处理器性能
  13. 【三石jQuery视频教程】01.图片循环展示_重发
  14. Maven –如何跳过单元测试
  15. 五大常用算法一(回溯,随机化,动态规划)
  16. 从零开始学习VIO笔记 --- 第一讲:基础知识(四元数,李代数)
  17. 安卓设置keychain_简单实现KeyChain实例
  18. 华强北再也没法生产散装 iPhone 了
  19. 谈B2B电商平台与大数据
  20. html 按键检测,js如何检测键盘按键的ascii码?

热门文章

  1. Uniform Distribution均匀分布
  2. javaweb男的gulp入手实践
  3. 开启事务处理插入多条数据 速度也可以
  4. 【转】Android用NDK和整套源码下编译JNI的不同
  5. 使用Monitor调试Unity3D Android程序日志输出(非DDMS和ADB)
  6. h3c s5500-28c-si操作
  7. [转]调整 VirtualBox 虚拟机的磁盘大小
  8. [NOIP2016]换教室(概率期望$DP$)
  9. 通过SecureCRT访问亚马逊Amazon EC2主机
  10. LeetCode85 Maximal Rectangle