Mac内核XNU的Mach子系统的一个完整过程的代码跟踪

一个完整的mach子系统

mach子系统包括了很多内核功能的实现,比如VM子系统(内存管理)、host子系统(主机硬件信息的处理)、thread子系统(thread相关实现)、exc子系统(异常处理相关);现在拿thread_act为例来跟踪一下代码,希望能够简单地了解vm子系统的概况。

(1)thread_act子系统的实现分为两部分:

thread_actServer.c和thread_actUser.c,分别实现了内核中mach msg消息接收和发送的各个API。

基本逻辑是:调用thread_actUser.c实现的API,接收到消息后thread_actServer.c的对应函数被调用,真正完成一些事情。

说明一下,所有子系统的***Server.c和***User.c代码都是通过MIG由***.defs生成。

(2)mach msg消息发送:

下面是一个“类似系统调用”的函数(或者某个系统调用会间接调用这个函数),用于向thread_act子系统发送mach msg消息请求某个服务(可以当作RPC)。

------ xnu/osfmk/mach/thread_actUser.c ------

/* Routine act_get_state */

mig_external kern_return_t act_get_state

(

         thread_act_t target_act,

         int flavor,

         thread_state_t old_state,

         mach_msg_type_number_t *old_stateCnt

)

{

 

#ifdef  __MigPackStructs

#pragma pack(4)

#endif

         typedef struct {

                  mach_msg_header_t Head;

                  NDR_record_t NDR;

                  int flavor;

                  mach_msg_type_number_t old_stateCnt;

         } Request;

#ifdef  __MigPackStructs

#pragma pack()

#endif

 

#ifdef  __MigPackStructs

#pragma pack(4)

#endif

         typedef struct {

                  mach_msg_header_t Head;

                  NDR_record_t NDR;

                  kern_return_t RetCode;

                  mach_msg_type_number_t old_stateCnt;

                  natural_t old_state[224];

                  mach_msg_trailer_t trailer;

         } Reply;

#ifdef  __MigPackStructs

#pragma pack()

#endif

 

#ifdef  __MigPackStructs

#pragma pack(4)

#endif

         typedef struct {

                  mach_msg_header_t Head;

                  NDR_record_t NDR;

                  kern_return_t RetCode;

                  mach_msg_type_number_t old_stateCnt;

                  natural_t old_state[224];

         } __Reply;

#ifdef  __MigPackStructs

#pragma pack()

#endif

         /*

          * typedef struct {

          *     mach_msg_header_t Head;

          *     NDR_record_t NDR;

          *     kern_return_t RetCode;

          * } mig_reply_error_t;

          */

 

         union {

                  Request In;

                  Reply Out;

         } Mess;

 

         Request *InP = &Mess.In;

         Reply *Out0P = &Mess.Out;

 

         mach_msg_return_t msg_result;

 

#ifdef         __MIG_check__Reply__act_get_state_t__defined

         kern_return_t check_result;

#endif        /* __MIG_check__Reply__act_get_state_t__defined */

 

         __DeclareSendRpc(3601, "act_get_state")

 

         InP->NDR = NDR_record;

 

         InP->flavor = flavor;

 

         if (*old_stateCnt < 224)

                  InP->old_stateCnt = *old_stateCnt;

         else

                  InP->old_stateCnt = 224;

 

         InP->Head.msgh_bits =

                  MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE);

         /* msgh_size passed as argument */

         InP->Head.msgh_request_port = target_act;

         InP->Head.msgh_reply_port = mig_get_reply_port();

         InP->Head.msgh_id = 3601;

 

         __BeforeSendRpc(3601, "act_get_state")

         msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, (mach_msg_size_t)sizeof(Request), (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);

         __AfterSendRpc(3601, "act_get_state")

         if (msg_result != MACH_MSG_SUCCESS) {

                  __MachMsgErrorWithoutTimeout(msg_result);

                  { return msg_result; }

         }

(3)thread_actServer.c中的mach msg消息接收:

------ xnu/osfmk/mach/thread_actServer.c ------

/* Description of this subsystem, for use in direct RPC */

const struct thread_act_subsystem {

mig_server_routine_t         server;      /* Server routine */

mach_msg_id_t start; /* Min routine number */

mach_msg_id_t end;  /* Max routine number + 1 */

unsigned int       maxsize;   /* Max msg size */

vm_address_t   reserved;  /* Reserved */

struct routine_descriptor    /*Array of routine descriptors */

routine[25];

} thread_act_subsystem = {

thread_act_server_routine,

3600,

3625,

(mach_msg_size_t)sizeof(union __ReplyUnion__thread_act_subsystem),

(vm_address_t)0,

{

{ (mig_impl_routine_t) 0,

(mig_stub_routine_t) _Xthread_terminate, 1, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__thread_terminate_t)},

{ (mig_impl_routine_t) 0,

(mig_stub_routine_t) _Xact_get_state, 4, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__act_get_state_t)},

{ (mig_impl_routine_t) 0,

(mig_stub_routine_t) _Xact_set_state, 4, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__act_set_state_t)},

{ (mig_impl_routine_t) 0,

(mig_stub_routine_t) _Xthread_get_state, 4, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__thread_get_state_t)},

{ (mig_impl_routine_t) 0,

(mig_stub_routine_t) _Xthread_set_state, 4, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__thread_set_state_t)},

{ (mig_impl_routine_t) 0,

(mig_stub_routine_t) _Xthre

解释一下上面的代码,声明并且实现了数据结构thread_act_subsystem,其中第6个成员是一个数组,数组的元素是一个结构 ---routine_descriptor;routine_descriptor声明如下:

------ xnu/osfmk/mach/mig.h ------

struct routine_descriptor {

mig_impl_routine_t     impl_routine;      /* Server work func pointer   */

mig_stub_routine_t    stub_routine;     /* Unmarshalling func pointer */

unsigned int                argc;                  /* Number of argument words   */

unsigned int                descr_count;     /* Number complex descriptors */

routine_arg_descriptor_t

arg_descr;                  /* pointer to descriptor array*/

unsigned int                max_reply_msg;        /* Max size for reply msg     */

};

typedef struct routine_descriptor *routine_descriptor_t;

typedef struct routine_descriptor mig_routine_descriptor;

typedef mig_routine_descriptor *mig_routine_descriptor_t;

(4)跟踪thread_act_subsystem中_Xthread_get_state的实现

------ xnu/osfmk/mach/thread_actServer.c ------

/* Routine act_get_state */

mig_internal novalue _Xact_get_state

(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)

{

#ifdef  __MigPackStructs

#pragma pack(4)

#endif

typedef struct {

mach_msg_header_t Head;

NDR_record_t NDR;

int flavor;

mach_msg_type_number_t old_stateCnt;

mach_msg_trailer_t trailer;

} Request;

#ifdef  __MigPackStructs

#pragma pack()

#endif

typedef __Request__act_get_state_t __Request;

typedef __Reply__act_get_state_t Reply;

/*

* typedef struct {

*     mach_msg_header_t Head;

*     NDR_record_t NDR;

*     kern_return_t RetCode;

* } mig_reply_error_t;

*/

Request *In0P = (Request *) InHeadP;

Reply *OutP = (Reply *) OutHeadP;

#ifdef         __MIG_check__Request__act_get_state_t__defined

kern_return_t check_result;

#endif        /* __MIG_check__Request__act_get_state_t__defined */

__DeclareRcvRpc(3601, "act_get_state")

__BeforeRcvRpc(3601, "act_get_state")

#if     defined(__MIG_check__Request__act_get_state_t__defined)

check_result = __MIG_check__Request__act_get_state_t((__Request *)In0P);

if (check_result != MACH_MSG_SUCCESS)

{ MIG_RETURN_ERROR(OutP, check_result); }

#endif        /* defined(__MIG_check__Request__act_get_state_t__defined) */

OutP->old_stateCnt = 224;

if (In0P->old_stateCnt < OutP->old_stateCnt)

OutP->old_stateCnt = In0P->old_stateCnt;

OutP->RetCode = act_get_state(In0P->Head.msgh_request_port, In0P->flavor, OutP->old_state, &OutP->old_stateCnt);

if (OutP->RetCode != KERN_SUCCESS) {

MIG_RETURN_ERROR(OutP, OutP->RetCode);

}

OutP->NDR = NDR_record;

OutP->Head.msgh_size = (mach_msg_size_t)(sizeof(Reply) - 896) + (((4 * OutP->old_stateCnt)));

__AfterRcvRpc(3601, "act_get_state")

}

为什么以thread_act为例呢?因为其他子系统比如vm,其中没有类似调用,感觉走到这里就是死胡同,没下文了。

麻雀虽小,五脏俱全;thread_act虽然简单,但是结构很完整。注意上面有对函数act_get_state的调用,继续跟踪这个函数。

(5)最终实现在这里

------ xnu/osfmk/kern/thread_act.c ------

kern_return_t

act_get_state(

thread_t                               thread,

int                                                 flavor,

thread_state_t                     state,

mach_msg_type_number_t        *count)

{

if (thread == current_thread())

return (KERN_INVALID_ARGUMENT);

return (thread_get_state(thread, flavor, state, count));

}

其中调用的函数thread_get_state也有实现如下,可以函数调用到了最终的那个:

------ xnu/osfmk/kern/thread_act.c ------

kern_return_t

thread_get_state(

register thread_t                 thread,

int                                                 flavor,

thread_state_t                     state,                          /* pointer to OUT array */

mach_msg_type_number_t        *state_count)     /*IN/OUT*/

{

kern_return_t             result = KERN_SUCCESS;

if (thread == THREAD_NULL)

return (KERN_INVALID_ARGUMENT);

thread_mtx_lock(thread);

if (thread->active) {

if (thread != current_thread()) {

thread_hold(thread);

thread_mtx_unlock(thread);

if (thread_stop(thread, FALSE)) {

thread_mtx_lock(thread);

result = machine_thread_get_state(

thread, flavor, state, state_count);

thread_unstop(thread);

}

else {

thread_mtx_lock(thread);

result = KERN_ABORTED;

}

thread_release(thread);

}

else

result = machine_thread_get_state(

thread, flavor, state, state_count);

}

else

result = KERN_TERMINATED;

thread_mtx_unlock(thread);

return (result);

				
时间: 2024-08-02 14:42:34

Mac内核XNU的Mach子系统的一个完整过程的代码跟踪的相关文章

Mac内核XNU的mach_vm子系统某个函数的代码逻辑

Mac内核XNU的mach_vm子系统某个函数的代码逻辑 mach子系统包括了很多内核功能的实现,比如VM子系统(内存管理).host子系统(主机硬件信息的处理).thread子系统(thread相关实现).exc子系统(异常处理相关),下面跟踪一下mach_vm子系统的mach_vm_allocate函数. (1)最顶层函数mach_vm_allocate: 它的实现,调用了两个函数(要么这个,要么另一个): ------ xnu/libsyscall/mach/mach_vm.c -----

Linux内核设计第三周——构造一个简单的Linux系统

Linux内核设计第三周 ——构造一个简单的Linux系统 一.知识点总结 计算机三个法宝: 存储程序计算机 函数调用堆栈 中断 操作系统两把宝剑: 中断上下文的切换 进程上下文的切换 linux内核源代码分析 arch/目录保存支持多种CPU类型的源代码 其中的关键目录包括:Documentation.drivers.firewall.fs(文件系统).include init目录:含有main.c,内核启动相关的代码基本都在init目录下 start_kernal()函数为启动函数,初始化内

20135327郭皓--Linux内核分析第三周 构造一个简单的Linux系统MenuOS

Linux内核分析第三周  构造一个简单的Linux系统MenuOS 前提回顾 1.计算机是如何工作的三个法宝 1.存储程序计算机 2.函数调用堆栈 3.中断 2.操作系统的两把宝剑 中断上下文的切换 进程上下文的切换 第一讲  Linux内核源代码介绍 arch目录包括了所有和体系结构相关的核心代码.它下面的每一个子目录都代表一种Linux支持的体系结构,例如i386就是Intel CPU及与之相兼容体系结构的子目录.PC机一般都基于此目录. init目录包含核心的初始化代码(不是系统的引导代

mac下cp命令的妙用(一个小技巧)

在项目开发中遇到了这样一种情况: 需要用一个干净的工程(export出来的,没有svn信息)去覆盖一个主干的工程(含有svn信息),然后提交代码:我们在mac系统中拷贝->粘贴到目标文件夹,只有2个选项:停止和全部替换:选择全部替换后,svn信息全部丢失了. 这时我们可以使用cp -r dir1 rootdir 来进行覆盖,dir1是那个干净工程的文件夹路径,和主干工程同名:rootdir是主干工程的上级目录,如此一来我们就实现了保留svn信息前提下覆盖文件夹的目的. mac下cp命令的妙用(一

Linux时间子系统(十七) ARM generic timer驱动代码分析

一.前言 关注ARM平台上timer driver(clocksource chip driver和clockevent chip driver)的驱动工程师应该会注意到timer硬件的演化过程.在单核时代,各个SOC vendor厂商购买ARM core的IP,然后自己设计SOC上的peripherals,这里面就包括了timer的硬件.由于没有统一的标准,各个厂商的设计各不相同,这给驱动工程师带来了工作量.然而,如果仅仅是工作量的话就还好,实际上,不仅仅如此.linux的时间子系统要求硬件t

【如何快速的开发一个完整的iOS直播app】(播放篇)

前言 在看这篇之前,如果您还不了解直播原理,请查看上篇文章如何快速的开发一个完整的iOS直播app(原理篇) 开发一款直播app,集成ijkplayer成功后,就算完成直播功能一半的工程了,只要有拉流url,就能播放直播啦 本篇主要讲解的是直播app中,需要用到的一个很重要的开源框架ijkplayer,然后集成这个框架可能对大多数初学者还是比较有难度的,所以本篇主要教你解决集成[ijkplayer]遇见的各种坑. 很多文章,可能讲解的是如何做,我比较注重讲解为什么这样做,大家有什么不明白,还可以

Linux内核编译完整过程

Linux内核编译完整过程 通过网上的资料我自己的实际内核编译,我把对Linux内核编译的过程写在这里,也许对其他的Linux爱好者的编译学习有些帮助,其中很大部分是网上的资料,另外就是我在实际编译过程中的一些实际经验. 内核简介 内核,是一个操作系统的核心.它负责管理系统的进程.内存.设备驱动程序.文件和网络系统,决定着系统的性能和稳定性. Linux的一个重要的特点就是其源代码的公开性,所有的内核源程序都可以在/usr/src/linux下找到,大部分应用软件也都是遵循GPL而设计的,你都可

一个主进程卡死的跟踪

原因:一开始想查找由于ipc初始化顺序的问题导致tray卡死的原因,但恰好遇到主进程弹出退出确认框后也卡死了,于是开始查找原因. 首先是跟踪代码,发现消息循环是活着的,但整个消息循环只能取到timer和paint消息,使用消息工具抓窗口,可以看到也可以取到GetItemText等消息. (一般来讲这时已经可以定位是由于attachthreadinput的原因了,但这时候我还不知道); 仔细想,最可能的情况就是当前线程所有窗口都已经被disable掉了,于是仔细检查进程的所有窗口,没有发现问题.

一个女大学生的代码学习之路(二)

首先说一下,写这种文章是由于我在四月四日晚上,在手动搭建自己的第一个ssh项目的时候,遇到了一个配置的问题,怎么解决也弄不好,当时是四号晚上九点,我看了一眼表,我就想两个小时之内,我要是能搞定就算行了,但是其实,我搞到三点才OK(凌晨),那时候已经是五号了,转天是一家子去扫墓的时候,结果我居然以这种一个理由没有去,理由是我太累了么?我只是就是搭了一个架子,就是由于我的包太混乱了,导致不兼容,所以tomcat总也不启动,你可能认为好笑,这么简单一个问题怎么就费这多多时间呢,但是作为一个刚接触三框架