📄 漫谈兼容内核之四:kernel-win32的进程管理.txt
字号:
IN LPVOID lpEnvironment,
IN LPCSTR lpCurrentDirectory,
IN LPSTARTUPINFOA lpStartupInfo,
OUT LPPROCESS_INFORMATION lpProcessInformation
);[/code]
这是Win32 API界面上的函数定义,所以是个DLL函数,还不是系统调用。Windows系统调用的界面是不公开的。不过好在我们已经有了ReactOS,从ReactOS的代码中可以看到这个系统调用的函数定义是:
[code]NtCreateProcess(
OUT PHANDLE ProcessHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ParentProcess,
IN BOOLEAN InheritObjectTable,
IN HANDLE SectionHandle OPTIONAL,
IN HANDLE DebugPort OPTIONAL,
IN HANDLE ExceptionPort OPTIONAL
)[/code]
详细说明这些参数的作用是件颇费篇幅的事,读者可以自己阅读“Windows NT/2000 Native API Reference”第六章中关于ZwCreateProcess()的说明(ZwCreateProcess()和NtCreateProcess()是同一个函数的两个名字,有的文献说在用户空间叫ZwCreateProcess()、在内核中叫NtCreateProcess())。我们这里只是长话短说,提一下往往会使Linux程序员感到惊讶的东西。
首先当然是InheritObjectTable。这是个布尔量,表示是否要从父进程继承已经打开的对象,但是即使要继承也不是全盘照收,还要看具体对象在打开时是否允许遗传。
另一个参数ParentProcess是个已打开进程对象的Handle,如果是有效Handle的话就表示新创建的对象应该“过继”给这个进程、作为它的子进程,而不是作为其创建者即“生父”的子进程。或者,换句话说就是包办、替别的进程创建一个子进程。
而DesiredAccess,则有下列选项:
[code]#define PROCESS_TERMINATE 1
#define PROCESS_CREATE_THREAD 2
#define PROCESS_SET_SESSIONID 4
#define PROCESS_VM_OPERATION 8
#define PROCESS_VM_READ 16
#define PROCESS_VM_WRITE 32
#define PROCESS_DUP_HANDLE 64
#define PROCESS_CREATE_PROCESS 128
#define PROCESS_SET_QUOTA 256
#define PROCESS_SET_INFORMATION 512
#define PROCESS_QUERY_INFORMATION 1024
#define PROCESS_ALL_ACCESS \
(STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0xFFF)[/code]
别的就不说了,光是上面这些,读者就可以看出NtCreateProcess()与fork()、execve()等Linux系统调用的差距有多大了。显然,以目前的kernel-win32,要实现与Windows的高度兼容是不可能的。
还要注意,这个系统调用只创建进程、而不包括其第一个线程。这跟Win32 API函数CreateProcess()是不一样的,后者实际上先调用NtCreateProcess(),再调用NtCreateThread()。
那么是否可以通过在用户空间、即在DLL中把CreateProcess()化解成一个kernel-win32和Linux系统调用的序列来解决问题呢?有的可以,有的不行。例如上述把所创建的进程过继给另一个进程就不行,因为过继给另一个进程也意味着从“继父”那里、而不是从“生父”那里、继承已打开对象(如果需要的话)。
再看线程的创建。
[code]CreateThread(
IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
IN DWORD dwStackSize,
IN LPTHREAD_START_ROUTINE lpStartAddress,
IN LPVOID lpParameter,
IN DWORD dwCreationFlags,
OUT LPDWORD lpThreadId
);[/code]
同样,这只是API函数,而相应的系统调用是NtCreateThread(),下列函数定义取自ReactOS的代码:
[code]NtCreateThread(
OUT PHANDLE T hreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
OUT PCLIENT_ID ClientId,
IN PCONTEXT ThreadContext,
IN PINITIAL_TEB InitialTeb,
IN BOOLEAN CreateSuspended
)[/code]
同样,详细的说明请看“Windows NT/2000 Native API Reference”第五章,这里只是简单地提一下。首先是ProcessHandle,这是个已打开进程对象的Handle。这就是说,NtCreateThread()的调用者可以为别的进程创建线程,而不仅仅是为调用者本身所属的进程。再看CreateSuspended,这是个布尔量,表示新创建的线程是否一出生就先被挂起、等到有别的线程对其执行NtResumeThread()后才投入运行,抑或一生下来就立即投入运行。还有ThreadContext,这是个指针,可以指向一个数据结构,里面规定了新线程降生之初各个寄存器的值(真令人难以理解这到底是为什么)。还有参数InitialTeb,在“Native API”一书中说是UserStack,用来指定新线程的用户空间堆栈的位置(这倒有道理)。至于DesiredAccess,则又有下列许多选项:
[code]#define THREAD_TERMINATE (0x0001L)
#define THREAD_SUSPEND_RESUME (0x0002L)
#define THREAD_ALERT (0x0004L)
#define THREAD_GET_CONTEXT (0x0008L)
#define THREAD_SET_CONTEXT (0x0010L)
#define THREAD_SET_INFORMATION (0x0020L)
#define THREAD_QUERY_INFORMATION (0x0040L)
#define THREAD_SET_THREAD_TOKEN (0x0080L)
#define THREAD_IMPERSONATE (0x0100L)
#define THREAD_DIRECT_IMPERSONATION (0x0200L)
#define THREAD_ALL_ACCESS (0x1f03ffL)[/code]
读者不难看出,这与fork()的差距可真够大的了。而且,有些差异是不能在用户空间弥补的,例如为别的进程创建线程,还有让新创建的线程进入“挂起”状态等等就是这样。
这还只是NtCreateProcess()和NtCreateThread()两个系统调用。与进程/线程管理有关的Windows系统调用至少还有下面这些:
[code]NtAlertThread()
NtCreateProcess()
NtCreateThread()
NtDuplecateObject()
NtGetContextThread()
NtImpersonateThread()
NtOpenProcess()
NtOpenThread()
NtQueueApcThread()
NtResumeThread()
NtSetContextThread()
NtSetInformationProcess()
NtSetInformationThread()
NtSetThreadExecutionState()
NtSuspendThread()
NtTerminateProcess()
NtTerminateThread()
NtYieldExecution()[/code]
由此可见,要跟Windows高度兼容,可真是路慢慢其修远。不过也不要被吓倒,还是那句老话:战略上藐视困难,战术上重视困难。再说也确实并非所有特性都必须加以实现,因为绝大多数应用软件都不会去用那些刁钻古怪的功能。
但是有一点是明白无误的,那就是迄今为止的Kernel-win32还只是朝正确的方向走了一小步。而且,其设计方案也有不当之处,想要用fork()加Win32Init()实现进程/线程的创建就是。这也是我认为对于兼容内核而言ReactOS远比Kernel-win32重要的原因。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -