1. malloc的实现方式

uclibc中,用户空间的malloc提供了三种实现方式:

malloc

malloc-simple

malloc-standard

具体使用何种方式,取决于.config文件定义(project\xxx\config\normal\config.uClibc),文件中分别对应几个配置符:

MALLOC

MALLOC_SIMPLE

MALLOC_STANDARD

malloc-standard :

This is a version (aka dlmalloc) of malloc/free/realloc written byDoug Lea,通过算法在用户空间实现内存管理

malloc-simple:

malloc/free通过简单mmap/munmap实现,代价比较大

malloc:

使用sbrk-->brk 系统调用实现,速度比mmap快

注意:malloc具体实现与其libc版本有关,例如对于glibc,最新版本只有一种实现方式:ptmalloc

2. execve使用方法

execve为系统调用函数,功能为启动新的程序:

函数定义 int execve(const char *filename, char *const argv[ ], char *const envp[ ]);

返回值 函数执行成功时没有返回值,执行失败时的返回值为-1.

函数说明 execve()用来执行参数filename字符串所代表的文件路径,第二个参数是利用数组指针来传递给执行文件,并且需要以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组。

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3
 4 int main(int arg, char **args)
 5 {
 6     //char *argv[]={"ls","-al","/home", NULL};
 7     char *argv[]={"free",NULL};
 8     //char *envp[]={0,NULL}; //传递给执行文件新的环境变量数组
 9
10     execve("/usr/bin/free",argv,NULL);
11     //execve("/bin/ls",argv,envp);
12 }

argv:必须是数组指针,传入NULL或者字符串会出错(例如execve("/usr/bin/free","free",NULL);)

envp:可以设置为NULL

fork()和execve()的区别

fork是分身,execve是变身。

exec系列的系统调用是把当前程序替换成要执行的程序,而fork用来产生一个和当前进程一样的进程(虽然通常执行不同的代码流)。exec系列的系统调用已经是变成别的程序了,已经和本程序无关了。通常运行另一个程序,而同时保留原程序运行的方法是,fork+exec。

fork调clone, clone调do_fork(do_fork是内核函数, 不是系统调用). 当然fork也可以直接调do_fork, 具体怎么做的, 请参看内核代码sys_fork的实现.
pthread_create是调的clone.

简单的说clone就是fork的"泛化"版. 通过clone创建一个新进程时可以指定很多参数, 比如是否共享内存空间等等. Linux内核并没有对线程的实现, 一切都是进程, 线程简单地说不过是共享内存空间的进程而已(当然可能还有点别的细节, 比如是否共享信号处理, 文件描述符之类的).内核中一个task_struct对象代表一个进程/task/调度对象.

 对Linux系统来说, 创建一个新线程和创建一个新进程开销是基本一样的(简单的说内核的眼里只有进程, 或者只有任务). 线程切换的开销和进程切换的开销, 主要是切换时是否刷新页表(MMU TLB), 也就是是否切换虚拟内存空间所对应的物理内存页. 别的几乎一致. 嗯, 线程切换是要快一些.

fork<app>  --> __libc_fork  <libc> -->  pid = ARCH_FORK ()<与处理器架构相关> -->

INLINE_SYSCALL (clone, 5,      \
    CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD, \
    NULL, NULL, NULL, &THREAD_SELF->tid)

< (\linux\uclibc\libpthread\nptl\sysdeps\unix\sysv\linux\arm\fork.c>

execve<app> -->

_syscall3(int, execve, const char *, filename,
    char *const *, argv, char *const *, envp)   <libc>

system<app> --> __libc_system <libc>  ->  vfork+ execl

execl --> execve

系统调用服务例程sys_clone, sys_fork, sys_vfork三者最终都是调用do_fork函数完成:

linux-3.4.x\arch\arm\kernel\sys_arm.c

 1 /* Fork a new task - this creates a new program thread.
 2  * This is called indirectly via a small wrapper
 3  */
 4 asmlinkage int sys_fork(struct pt_regs *regs)
 5 {
 6     return do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
 7
 8 }
 9
10 /* Clone a task - this clones the calling program thread.
11  * This is called indirectly via a small wrapper
12  */
13 asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
14              int __user *parent_tidptr, int tls_val,
15              int __user *child_tidptr, struct pt_regs *regs)
16 {
17     if (!newsp)
18         newsp = regs->ARM_sp;
19
20     return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
21 }
22
23 asmlinkage int sys_vfork(struct pt_regs *regs)
24 {
25     return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
26 }
27
28 /* sys_execve() executes a new program.
29  * This is called indirectly via a small wrapper
30  */
31 asmlinkage int sys_execve(const char __user *filenamei,
32               const char __user *const __user *argv,
33               const char __user *const __user *envp, struct pt_regs *regs)
34 {
35     int error;
36     char * filename;
37
38     filename = getname(filenamei);
39     error = PTR_ERR(filename);
40     if (IS_ERR(filename))
41         goto out;
42     error = do_execve(filename, argv, envp, regs);
43     putname(filename);
44 out:
45     return error;
46 }

clone 和fork,vfork系统调用在实现时都是调用核心函数do_fork:

do_fork(unsigned long clone_flag, unsigned long usp, struct pt_regs);

do_fork的第一个参数是clone_flag,该参数可以是:

CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND,CLONE_PID,CLONE_VFORK等等标志位的组合。任何一位被置1了则表明创建的子进程和父进程共享该位对应的资源。

fork时clone_flag = SIGCHLD;

vfork时clone_flag = CLONE_VM | CLONE_VFORK | SIGCHLD;

而在clone中,clone_flag由用户给出。

在vfork的实现中,cloneflags = CLONE_VFORK | CLONE_VM | SIGCHLD,这表示子进程和父进程共享地址空间,同时

do_fork会检查CLONE_VFORK,如果该位被置1了,子进程会把父进程的地址空间锁住,直到子进程退出或执行exec时才释放该锁。

 pthread_create

__pthread_create_2_1   ->    create_thread   ->  

clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL
       | CLONE_SETTLS | CLONE_PARENT_SETTID
       | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM

do_clone (pd, attr, clone_flags, start_thread,
         STACK_VARIABLES_ARGS, 1);

-->

ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
    pd, &pd->tid, TLS_VALUE, &pd->tid) == -1)

-->

DO_CALL (clone)

3. 线程/进程

0号进程 swapper:  有一个专门的task_struct结构体类型变量init_task,以它为头系统每个线程的task_struct字段都链接在一起形成一个双向循环链表;它是系统创建的第一个进程,也是唯一一个没有通过fork|kernel_thread产生的进程,完成最开始的初始化后最终会转化为Idle进程。

1号进程 init:  进程0最终会通过调用kernel_thread创建一个内核线程去执行init函数,init函数继续完成剩余的内核初始化,并在函数的最后调用execve系统调用装入用户空间的可执行程序/sbin/init,这时进程1就拥有了自己的属性资源,成为一个普通进程,至此,内核初始化和启动过程结束。下面就进入了用户空间的初始化,init也将变为守护进程监视系统其他进程,收集孤立的进程:当一个进程启动了一个子进程并且在子进程之前终止了,这个子进程立刻成为init的子进程。由init进程领养的进程终止时init就会调用一个wait函数取得其终止状态。

2号进程kthreadd:kthreadd进程由idle通过kernel_thread创建,并始终运行在内核空间, 负责所有内核线程的调度和管理

进程 = 一段程序+堆栈空间+任务控制块+独立存储空间

线程 = 一段程序+堆栈空间+任务控制块

对内核空间来说,线程和进程没有任何区别,因为所有内核线程都使用同一块地址空间(3GB--4GB),对应同一个页表(init_mm.pgd);

对用户空间来说,进程拥有独立的页表(task_struct->mm_struct->pgd),而线程没有独立页表,与进程共享同一个mm_struct;

4. 页表与TLB

ARMv6架构有两个协处理器寄存器用来存放一级页表基地址,TTBR0和TTBR1。操作系统把虚拟内存划分为内核空间和用户空间,TTBR0存放用户空间的一级页表基址,TTBR1存放内核空间的一级页表基址。操作系统为用户空间的每个进程分配各自的页表,即每个进程的一级页表基址是不一样的,故当发生进程上下文切换时,TTBR0需要被存放当前进程的一级页表基址;TTBR1中存放的是内核空间的一级页表基址,内核空间的一级页表基址是固定的,故TTBR1中的基址值不需要改变。

TTBR0:c15:0x2

TTBR1:c15:0x102

TTBR0/TTBR1的高20位代表了对应页表地址(TTB0/TTB1),即TTB0-->task_struct->mm_struct->pgd, TTB1-->init_mm.pgd

例如TTBR0 = 0x24C34890,代表当前用户进程的一级页表地址为0x24C34000

转载于:https://www.cnblogs.com/DF11G/p/10115811.html

linux的一些细节记录相关推荐

  1. linux terminal教程,Linux入门教程 - 如何记录和重放Linux终端会话

    原标题:Linux入门教程 - 如何记录和重放Linux终端会话 来自:https://www.linuxmi.com/replay-linux.html 使用命令,我们可以在type文件中记录终端会 ...

  2. 基于全志A33开发板linux系统移植学习记录(Boot0)

    基于全志A33开发板linux系统移植学习记录 第一章 Boot0基于ARMGCC的编译与修改 文章目录 基于全志A33开发板linux系统移植学习记录 前言 一.全志A33简介以及上电引导流程 二. ...

  3. linux 配置tensorflow 全过程记录

    linux 配置tensorflow 全过程记录 前几天刚下一个deepin系统,是基于linux 内核的,界面的设计有些mac的feel 感觉还是挺不错的,之后就赶紧配置了一下tensorflow ...

  4. linux下查看中断请求记录 IRQ

    linux下查看中断请求记录.通过cpu的中断请求的响应,可以看出cpu都在为哪些设备干活,干的活有多少量等信息. [~]$ cat /proc/interrupts CPU0 CPU1 CPU2 C ...

  5. linux kernel 内存相关记录

    本篇文章是学习了<linux内核设计与实现>和<linux设备驱动开发详解>关于linux 内存部分的记录. MMU 内存管理单元,提供虚拟地址和物理地址映射.内存访问权限.c ...

  6. linux文件权限记录,linux文件权限学习记录

    linux文件权限学习记录 1.Linux 的安全性 1.1/etc/passwd 文件 存放用户的登录名以及相关信息#cat  / etc / passwd root: x: 0 : 0 : roo ...

  7. huggingface调用一些细节记录

    huggingface调用一些细节记录 Model Input Model Foward BertModel 写给我自己看的一些小细节,因为不是每天写代码,总是会忘 要多看文档!!! Model In ...

  8. Java实现CRM项目过程中的细节记录(一)

    CRM项目实现过程中的细节记录(一) 文章目录 CRM项目实现过程中的细节记录(一) 一.数据库相关细节 1. 表名 2. 表字段说明 3. 不使用主外键约束 4. 不使用主键自动增长 UUID 5. ...

  9. electron + vue /打包linux应用报错记录

    1. electron + vue 打包linux应用报错记录 >  icon图标导致的报错 ⨯ unknown output format set github.com/develar/app ...

最新文章

  1. Yann LeCun:假如没有深度学习,Facebook就是尘埃
  2. python学习手册笔记——22.模块代码编写基础
  3. 工业级POE交换机技术优势及供电方法详解!
  4. Linux 10分钟让你掌握虚拟地址--写时拷贝技术
  5. python na不显示 占位_Python学习之路—Python基础(一)
  6. linux下jdk1.8搭建笔记
  7. 从小学4年级的数学课开始解释线性回归
  8. 自定义函数 | R语言偏相关分析及绘图
  9. 自学网络结构(一):Neural Architecture Search With Reinforcement Learning
  10. history 路由 vs hash 路由 vs location.href 实现跳转
  11. 安卓日志:拍照、文件读取的问题
  12. UPS不间断电源常见问题及解决办法
  13. remix中错误集合
  14. Retrofit 通过刷新头部Token解决token过期
  15. 如何在macOS Big Sur 的Finder中使用终端锁定文件
  16. 微信小程序糟心开发过程
  17. Bi-directional Cross-Modality Feature Propagation with Separation-and Aggregation Gate_eccv2020
  18. 去除字符串中的空格(C语言)
  19. 关于计算机优点缺点的英语作文,平板电脑的优缺点英语作文
  20. 产销平衡的运输问题上机实验matlab_产销平衡运输问题

热门文章

  1. Java实现Excel批量导入数据
  2. 菜单编写(VC_Win32)
  3. 520表白纪念自适应单页源码
  4. 第六十七章 SQL命令 ROLLBACK
  5. React学习(六)-React中组件的数据-state
  6. 11111111111
  7. APAC Day of Coderetreat 2015
  8. Jacky的のLinux diary
  9. sourcemap功能简介
  10. Android 长时间待机后系统概率性无声