mirror of
https://github.com/reactos/wine.git
synced 2024-11-29 22:50:43 +00:00
965 lines
38 KiB
Plaintext
965 lines
38 KiB
Plaintext
<chapter>
|
|
<title>Kernel modules</title>
|
|
<para>
|
|
This section cover the kernel modules. As already stated, Wine
|
|
implements the NT architecture, hence provides NTDLL for the
|
|
core kernel functions, and KERNEL32, which is the
|
|
implementation of the basis of the Win32 subsystem, on top of
|
|
NTDLL.
|
|
</para>
|
|
<sect1 id="ntdll">
|
|
<title>NTDLL</title>
|
|
<para>
|
|
NTDLL provides most of the services you'd expect from a
|
|
kernel.
|
|
</para>
|
|
<para>
|
|
Process and thread management are part of them (even if
|
|
process management is still mainly done in KERNEL32, unlike
|
|
NT). A Windows process runs as a Unix process, and a Windows
|
|
thread runs as a Unix thread.
|
|
</para>
|
|
<para>
|
|
Wine also provide fibers (which is the Windows name of
|
|
co-routines).
|
|
</para>
|
|
<para>
|
|
Most of the Windows memory handling (Heap, Global and Local
|
|
functions, virtual memory...) are easily mapped upon their
|
|
Unix equivalents. Note the NTDLL doesn't know about 16 bit
|
|
memory, which is only handled in KERNEL32/KRNL386.EXE (and
|
|
also the DOS routines).
|
|
</para>
|
|
|
|
<sect2>
|
|
<title>File management</title>
|
|
<para>
|
|
Wine uses some configuration in order to map Windows
|
|
filenames (either defined with drive letters, or as UNC
|
|
names) to the unix filenames. Wine also uses some
|
|
incantation so that most of file related APIs can also
|
|
take full unix names. This is handy when passing filenames
|
|
on the command line.
|
|
</para>
|
|
<para>
|
|
File handles can be waitable objects, as Windows define
|
|
them.
|
|
</para>
|
|
<para>
|
|
Asynchronous I/O is implemented on file handles by
|
|
queueing pseudo APC. They are not real APC in the sense
|
|
that they have the same priority as the threads in the
|
|
considered process (while APCs on NT have normally a
|
|
higher priority). These APCs get called when invoking
|
|
Wine server (which should lead to correct behavior when the
|
|
program ends up waiting on some object - waiting always
|
|
implies calling Wine server).
|
|
</para>
|
|
<para>
|
|
FIXME: this should be enhanced and updated to latest work
|
|
on FS.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Synchronization</title>
|
|
<para>
|
|
Most of the synchronization (between threads or processes)
|
|
is done in Wine server, which handles both the waiting
|
|
operation (on a single object or a set of objects) and the
|
|
signaling of objects.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Module (DLL) loading</title>
|
|
<para>
|
|
Wine is able to load any NE and PE module. In all cases,
|
|
the module's binary code is directly executed by the
|
|
processor.
|
|
</para>
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title>Device management</title>
|
|
<para>
|
|
Wine allows usage a wide variety of devices:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
Communication ports are mapped to Unix
|
|
communication ports (if they have sufficient
|
|
permissions).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Parallel ports are mapped to Unix parallel ports (if
|
|
they have sufficient permissions).
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
CDROM: the Windows device I/O control calls are
|
|
mapped onto Unix <function>ioctl()</function>.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
Some Win9x VxDs are supported, by rewriting some of
|
|
their internal behavior. But this support is
|
|
limited. Portable programs to Windows NT shouldn't
|
|
need them.
|
|
</para>
|
|
<para>
|
|
Wine will not support native VxD.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
</sect2>
|
|
<sect2 id="threading">
|
|
<title>Multi-threading in Wine</title>
|
|
|
|
<para>
|
|
This section will assume you understand the basics of
|
|
multithreading. If not there are plenty of good tutorials
|
|
available on the net to get you started.
|
|
</para>
|
|
|
|
<para>
|
|
Threading in Wine is somewhat complex due to several
|
|
factors. The first is the advanced level of multithreading
|
|
support provided by Windows - there are far more threading
|
|
related constructs available in Win32 than the Linux
|
|
equivalent (pthreads). The second is the need to be able to
|
|
map Win32 threads to native Linux threads which provides us
|
|
with benefits like having the kernel schedule them without
|
|
our intervention. While it's possible to implement threading
|
|
entirely without kernel support, doing so is not desirable
|
|
on most platforms that Wine runs on.
|
|
</para>
|
|
|
|
<sect3>
|
|
<title> Threading support in Win32 </title>
|
|
|
|
<para>
|
|
Win32 is an unusually thread friendly API. Not only is it
|
|
entirely thread safe, but it provides many different
|
|
facilities for working with threads. These range from the
|
|
basics such as starting and stopping threads, to the
|
|
extremely complex such as injecting threads into other
|
|
processes and COM inter-thread marshalling.
|
|
</para>
|
|
|
|
<para>
|
|
One of the primary challenges of writing Wine code
|
|
therefore is ensuring that all our DLLs are thread safe,
|
|
free of race conditions and so on. This isn't simple -
|
|
don't be afraid to ask if you aren't sure whether a piece
|
|
of code is thread safe or not!
|
|
</para>
|
|
|
|
<para>
|
|
Win32 provides many different ways you can make your code
|
|
thread safe however the most common are <emphasis>critical
|
|
section</emphasis> and the <emphasis>interlocked
|
|
functions</emphasis>. Critical sections are a type of
|
|
mutex designed to protect a geographic area of code. If
|
|
you don't want multiple threads running in a piece of code
|
|
at once, you can protect them with calls to
|
|
<function>EnterCriticalSection</function> and
|
|
<function>LeaveCriticalSection</function>. The first call
|
|
to <function>EnterCriticalSection</function> by a thread
|
|
will lock the section and continue without stopping. If
|
|
another thread calls it then it will block until the
|
|
original thread calls
|
|
<function>LeaveCriticalSection</function> again.
|
|
</para>
|
|
|
|
<para>
|
|
It is therefore vitally important that if you use critical
|
|
sections to make some code thread-safe, that you check
|
|
every possible codepath out of the code to ensure that any
|
|
held sections are left. Code like this:
|
|
</para>
|
|
|
|
<programlisting>
|
|
if (res != ERROR_SUCCESS) return res;
|
|
</programlisting>
|
|
|
|
<para>
|
|
is extremely suspect in a function that also contains a
|
|
call to <function>EnterCriticalSection</function>. Be
|
|
careful.
|
|
</para>
|
|
|
|
<para>
|
|
If a thread blocks while waiting for another thread to
|
|
leave a critical section, you will see an error from the
|
|
<function>RtlpWaitForCriticalSection</function> function,
|
|
along with a note of which thread is holding the
|
|
lock. This only appears after a certain timeout, normally
|
|
a few seconds. It's possible the thread holding the lock
|
|
is just being really slow which is why Wine won't
|
|
terminate the app like a non-checked build of Windows
|
|
would, but the most common cause is that for some reason a
|
|
thread forgot to call
|
|
<function>LeaveCriticalSection</function>, or died while
|
|
holding the lock (perhaps because it was in turn waiting
|
|
for another lock). This doesn't just happen in Wine code:
|
|
a deadlock while waiting for a critical section could be
|
|
due to a bug in the app triggered by a slight difference
|
|
in the emulation.
|
|
</para>
|
|
|
|
<para>
|
|
Another popular mechanism available is the use of
|
|
functions like <function>InterlockedIncrement</function>
|
|
and <function>InterlockedExchange</function>. These make
|
|
use of native CPU abilities to execute a single
|
|
instruction while ensuring any other processors on the
|
|
system cannot access memory, and allow you to do common
|
|
operations like add/remove/check a variable in thread-safe
|
|
code without holding a mutex. These are useful for
|
|
reference counting especially in free-threaded (thread
|
|
safe) COM objects.
|
|
</para>
|
|
|
|
<para>
|
|
Finally, the usage of TLS slots are also popular. TLS
|
|
stands for thread-local storage, and is a set of slots
|
|
scoped local to a thread which you can store pointers
|
|
in. Look on MSDN for the <function>TlsAlloc</function>
|
|
function to learn more about the Win32 implementation of
|
|
this. Essentially, the contents of a given slot will be
|
|
different in each thread, so you can use this to store
|
|
data that is only meaningful in the context of a single
|
|
thread. On recent versions of Linux the __thread keyword
|
|
provides a convenient interface to this functionality - a
|
|
more portable API is exposed in the pthread
|
|
library. However, these facilities is not used by Wine,
|
|
rather, we implement Win32 TLS entirely ourselves.
|
|
</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title> SysLevels </title>
|
|
|
|
<para>
|
|
SysLevels are an undocumented Windows-internal
|
|
thread-safety system. They are basically critical sections
|
|
which must be taken in a particular order. The mechanism
|
|
is generic but there are always three syslevels: level 1
|
|
is the Win16 mutex, level 2 is the USER mutex and level 3
|
|
is the GDI mutex.
|
|
</para>
|
|
|
|
<para>
|
|
When entering a syslevel, the code (in
|
|
<filename>dlls/kernel/syslevel.c</filename>) will check
|
|
that a higher syslevel is not already held and produce an
|
|
error if so. This is because it's not legal to enter level
|
|
2 while holding level 3 - first, you must leave level 3.
|
|
</para>
|
|
|
|
<para>
|
|
Throughout the code you may see calls to
|
|
<function>_ConfirmSysLevel()</function> and
|
|
<function>_CheckNotSysLevel()</function>. These functions
|
|
are essentially assertions about the syslevel states and
|
|
can be used to check that the rules have not been
|
|
accidentally violated. In particular,
|
|
<function>_CheckNotSysLevel()</function> will break
|
|
(probably into the debugger) if the check fails. If this
|
|
happens the solution is to get a backtrace and find out,
|
|
by reading the source of the wine functions called along
|
|
the way, how Wine got into the invalid state.
|
|
</para>
|
|
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title> POSIX threading vs kernel threading </title>
|
|
|
|
<para>
|
|
Wine runs in one of two modes: either pthreads (posix
|
|
threading) or kthreads (kernel threading). This section
|
|
explains the differences between them. The one that is
|
|
used is automatically selected on startup by a small test
|
|
program which then execs the correct binary, either
|
|
wine-kthread or wine-pthread. On NPTL-enabled systems
|
|
pthreads will be used, and on older non-NPTL systems
|
|
kthreads is selected.
|
|
</para>
|
|
|
|
<para>
|
|
Let's start with a bit of history. Back in the dark ages
|
|
when Wines threading support was first implemented a
|
|
problem was faced - Windows had much more capable
|
|
threading APIs than Linux did. This presented a problem -
|
|
Wine works either by reimplementing an API entirely or by
|
|
mapping it onto the underlying systems equivalent. How
|
|
could Win32 threading be implemented using a library which
|
|
did not have all the neeed features? The answer, of
|
|
course, was that it couldn't be.
|
|
</para>
|
|
|
|
<para>
|
|
On Linux the pthreads interface is used to start, stop and
|
|
control threads. The pthreads library in turn is based on
|
|
top of so-called "kernel threads" which are created using
|
|
the <function>clone(2)</function> syscall. Pthreads
|
|
provides a nicer (more portable) interface to this
|
|
functionality and also provides APIs for controlling
|
|
mutexes. There is a <ulink
|
|
url="http://www.llnl.gov/computing/tutorials/pthreads/">
|
|
good tutorial on pthreads </ulink> available if you want
|
|
to learn more.
|
|
</para>
|
|
|
|
<para>
|
|
As pthreads did not provide the necessary semantics to
|
|
implement Win32 threading, the decision was made to
|
|
implement Win32 threading on top of the underlying kernel
|
|
threads by using syscalls like <function>clone</function>
|
|
directly. This provided maximum flexibility and allowed a
|
|
correct implementation but caused some bad side
|
|
effects. Most notably, all the userland Linux APIs assumed
|
|
that the user was utilising the pthreads library. Some
|
|
only enabled thread safety when they detected that
|
|
pthreads was in use - this is true of glibc, for
|
|
instance. Worse, pthreads and pure kernel threads had
|
|
strange interactions when run in the same process yet some
|
|
libraries used by Wine used pthreads internally. Throw in
|
|
source code porting using WineLib - where you have both
|
|
UNIX and Win32 code in the same process - and chaos was
|
|
the result.
|
|
</para>
|
|
|
|
<para>
|
|
The solution was simple yet ingenius: Wine would provide
|
|
its own implementation of the pthread library
|
|
<emphasis>inside</emphasis> its own binary. Due to the
|
|
semantics of ELF symbol scoping, this would cause Wines
|
|
own implementations to override any implementation loaded
|
|
later on (like the real libpthread.so). Therefore, any
|
|
calls to the pthread APIs in external libraries would be
|
|
linked to Wines instead of the systems pthreads library,
|
|
and Wine implemented pthreads by using the standard
|
|
Windows threading APIs it in turn implemented itself.
|
|
</para>
|
|
|
|
<para>
|
|
As a result, libraries that only became thread-safe in the
|
|
presence of a loaded pthreads implementation would now do
|
|
so, and any external code that used pthreads would
|
|
actually end up creating Win32 threads that Wine was aware
|
|
of and controlled. This worked quite nicely for a long
|
|
time, even though it required doing some extremely
|
|
un-kosher things like overriding internal libc structures
|
|
and functions. That is, it worked until NPTL was developed
|
|
at which point the underlying thread implementation on
|
|
Linux changed dramatically.
|
|
</para>
|
|
|
|
<para>
|
|
The fake pthread implementation can be found in
|
|
<filename>loader/kthread.c</filename>, which is used to
|
|
produce to wine-kthread binary. In contrast,
|
|
loader/pthread.c produces the wine-pthread binary which is
|
|
used on newer NPTL systems.
|
|
</para>
|
|
|
|
<para>
|
|
NPTL is a new threading subsystem for Linux that hugely
|
|
improves its performance and flexibility. By allowing
|
|
threads to become much more scalable and adding new
|
|
pthread APIs, NPTL made Linux competitive with Windows in
|
|
the multi-threaded world. Unfortunately it also broke many
|
|
assumptions made by Wine (as well as other applications
|
|
such as the Sun JVM and RealPlayer) in the process.
|
|
</para>
|
|
|
|
<para>
|
|
There was, however, some good news. NPTL made Linux
|
|
threading powerful enough that Win32 threads could now be
|
|
implemented on top of pthreads like any other normal
|
|
application. There would no longer be problems with mixing
|
|
win32-kthreads and pthreads created by external libraries,
|
|
and no need to override glibc internals. As you can see
|
|
from the relative sizes of the
|
|
<filename>loader/kthread.c</filename> and
|
|
<filename>loader/pthread.c</filename> files, the
|
|
difference in code complexity is considerable. NPTL also
|
|
made several other semantic changes to things such as
|
|
signal delivery so changes were required in many different
|
|
places in Wine.
|
|
</para>
|
|
|
|
<para>
|
|
On non-Linux systems the threading interface is typically
|
|
not powerful enough to replicate the semantics Win32
|
|
applications expect and so kthreads with the pthread
|
|
overrides are used.
|
|
</para>
|
|
</sect3>
|
|
|
|
<sect3>
|
|
<title> The Win32 thread environment </title>
|
|
|
|
<para>
|
|
All Win32 code, whether from a native EXE/DLL or in Wine
|
|
itself, expects certain constructs to be present in its
|
|
environment. This section explores what those constructs
|
|
are and how Wine sets them up. The lack of this
|
|
environment is one thing that makes it hard to use Wine
|
|
code directly from standard Linux applications - in order
|
|
to interact with Win32 code a thread must first be
|
|
"adopted" by Wine.
|
|
</para>
|
|
|
|
<para>
|
|
The first thing Win32 code requires is the
|
|
<emphasis>TEB</emphasis> or "Thread Environment
|
|
Block". This is an internal (undocumented) Windows
|
|
structure associated with every thread which stores a
|
|
variety of things such as TLS slots, a pointer to the
|
|
threads message queue, the last error code and so on. You
|
|
can see the definition of the TEB in
|
|
<filename>include/thread.h</filename>, or at least what we
|
|
know of it so far. Being internal and subject to change,
|
|
the layout of the TEB has had to be reverse engineered
|
|
from scratch.
|
|
</para>
|
|
|
|
<para>
|
|
A pointer to the TEB is stored in the %fs register and can
|
|
be accessed using <function>NtCurrentTeb()</function> from
|
|
within Wine code. %fs actually stores a selector, and
|
|
setting it therefore requires modifying the processes
|
|
local descriptor table (LDT) - the code to do this is in
|
|
<filename>lib/wine/ldt.c</filename>.
|
|
</para>
|
|
|
|
<para>
|
|
The TEB is required by nearly all Win32 code run in the
|
|
Wine environment, as any wineserver RPC will use it, which
|
|
in turn implies that any code which could possibly block
|
|
(for instance by using a critical section) needs it. The
|
|
TEB also holds the SEH exception handler chain as the
|
|
first element, so if when disassembling you see code like
|
|
this:
|
|
</para>
|
|
|
|
<programlisting> movl %esp, %fs:0 </programlisting>
|
|
|
|
<para>
|
|
... then you are seeing the program set up an SEH handler
|
|
frame. All threads must have at least one SEH entry, which
|
|
normally points to the backstop handler which is
|
|
ultimately responsible for popping up the all-too-familiar
|
|
"This program has performed an illegal operation and will
|
|
be terminated" message. On Wine we just drop straight into
|
|
the debugger. A full description of SEH is out of the
|
|
scope of this section, however there are some good
|
|
articles in MSJ if you are interested.
|
|
</para>
|
|
|
|
<para>
|
|
All Win32-aware threads must have a wineserver
|
|
connection. Many different APIs require the ability to
|
|
communicate with the wineserver. In turn, the wineserver
|
|
must be aware of Win32 threads in order to be able to
|
|
accurately report information to other parts of the program
|
|
and do things like route inter-thread messages, dispatch
|
|
APCs (asynchronous procedure calls) and so on. Therefore a
|
|
part of thread initialization is initializing the thread
|
|
serverside. The result is not only correct information in
|
|
the server, but a set of file descriptors the thread can use
|
|
to communicate with the server - the request fd, reply fd
|
|
and wait fd (used for blocking).
|
|
</para>
|
|
</sect3>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1>
|
|
<title>KERNEL Module</title>
|
|
|
|
<para>
|
|
FIXME: Needs some content...
|
|
</para>
|
|
<sect2 id="consoles">
|
|
<title>Consoles in Wine</title>
|
|
<para>
|
|
As described in the Wine User Guide's CUI section, Wine
|
|
manipulates three kinds of "consoles" in order to support
|
|
properly the Win32 CUI API.
|
|
</para>
|
|
<para>
|
|
The following table describes the main implementation
|
|
differences between the three approaches.
|
|
<table>
|
|
<title>Function consoles implementation comparison</title>
|
|
<tgroup cols="4" align="left">
|
|
<thead>
|
|
<row>
|
|
<entry>Function</entry>
|
|
<entry>Bare streams</entry>
|
|
<entry>Wineconsole & user backend</entry>
|
|
<entry>Wineconsole & curses backend</entry>
|
|
</row>
|
|
</thead>
|
|
<tbody>
|
|
<row>
|
|
<entry>
|
|
Console as a Win32 Object (and associated
|
|
handles)
|
|
</entry>
|
|
<entry>
|
|
No specific Win32 object is used in this
|
|
case. The handles manipulated for the standard
|
|
Win32 streams are in fact "bare handles" to
|
|
their corresponding Unix streams. The mode
|
|
manipulation functions
|
|
(<function>GetConsoleMode</function> /
|
|
<function>SetConsoleMode</function>) are not
|
|
supported.
|
|
</entry>
|
|
<entry>
|
|
Implemented in server, and a specific Winelib
|
|
program (wineconsole) is in charge of the
|
|
rendering and user input. The mode manipulation
|
|
functions behave as expected.
|
|
</entry>
|
|
<entry>
|
|
Implemented in server, and a specific Winelib
|
|
program (wineconsole) is in charge of the
|
|
rendering and user input. The mode manipulation
|
|
functions behave as expected.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
Inheritance (including handling in
|
|
<function>CreateProcess</function> of
|
|
<constant>CREATE_DETACHED</constant>,
|
|
<constant>CREATE_NEW_CONSOLE</constant> flags).
|
|
</entry>
|
|
<entry>
|
|
Not supported. Every process child of a process
|
|
will inherit the Unix streams, so will also
|
|
inherit the Win32 standard streams.
|
|
</entry>
|
|
<entry>
|
|
Fully supported (each new console creation will
|
|
be handled by the creation of a new USER32
|
|
window)
|
|
</entry>
|
|
<entry>
|
|
Fully supported, except for the creation of a
|
|
new console, which will be rendered on the same
|
|
Unix terminal as the previous one, leading to
|
|
unpredictable results.
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
<function>ReadFile</function> /
|
|
<function>WriteFile</function>
|
|
operations
|
|
</entry>
|
|
<entry>Fully supported</entry>
|
|
<entry>Fully supported</entry>
|
|
<entry>Fully supported</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
Screen-buffer manipulation (creation, deletion,
|
|
resizing...)
|
|
</entry>
|
|
<entry>Not supported</entry>
|
|
<entry>Fully supported</entry>
|
|
<entry>
|
|
Partly supported (this won't work too well as we
|
|
don't control (so far) the size of underlying
|
|
Unix terminal
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
APIs for reading/writing screen-buffer content,
|
|
cursor position
|
|
</entry>
|
|
<entry>Not supported</entry>
|
|
<entry>Fully supported</entry>
|
|
<entry>Fully supported</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
APIs for manipulating the rendering window size
|
|
</entry>
|
|
<entry>Not supported</entry>
|
|
<entry>Fully supported</entry>
|
|
<entry>
|
|
Partly supported (this won't work too well as we
|
|
don't control (so far) the size of underlying
|
|
Unix terminal
|
|
</entry>
|
|
</row>
|
|
<row>
|
|
<entry>
|
|
Signaling (in particular, Ctrl-C handling)
|
|
</entry>
|
|
<entry>
|
|
Nothing is done, which means that Ctrl-C will
|
|
generate (as usual) a
|
|
<constant>SIGINT</constant> which will terminate
|
|
the program.
|
|
</entry>
|
|
<entry>
|
|
Partly supported (Ctrl-C behaves as expected,
|
|
however the other Win32 CUI signaling isn't
|
|
properly implemented).
|
|
</entry>
|
|
<entry>
|
|
Partly supported (Ctrl-C behaves as expected,
|
|
however the other Win32 CUI signaling isn't
|
|
properly implemented).
|
|
</entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</para>
|
|
|
|
<para>
|
|
The Win32 objects behind a console can be created in
|
|
several occasions:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
When the program is started from wineconsole, a new
|
|
console object is created and will be used
|
|
(inherited) by the process launched from
|
|
wineconsole.
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
When a program, which isn't attached to a console,
|
|
calls <function>AllocConsole</function>, Wine then
|
|
launches wineconsole, and attaches the current
|
|
program to this console. In this mode, the USER32
|
|
mode is always selected as Wine cannot tell the
|
|
current state of the Unix console.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
<para>
|
|
Please also note, that starting a child process with the
|
|
<constant>CREATE_NEW_CONSOLE</constant> flag, will end-up
|
|
calling <function>AllocConsole</function> in the child
|
|
process, hence creating a wineconsole with the USER32
|
|
backend.
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="initialization">
|
|
|
|
<title> The Wine initialization process </title>
|
|
|
|
<para>
|
|
Wine has a rather complex startup procedure, so unlike many
|
|
programs the best place to begin exploring the code-base is
|
|
<emphasis>not</emphasis> in fact at the
|
|
<function>main()</function> function but instead at some of the
|
|
more straightforward DLLs that exist on the periphery such as
|
|
MSI, the widget library (in USER and COMCTL32) etc. The purpose
|
|
of this section is to document and explain how Wine starts up
|
|
from the moment the user runs "wine myprogram.exe" to the point
|
|
at which myprogram gets control.
|
|
</para>
|
|
|
|
<sect2>
|
|
<title> First Steps </title>
|
|
|
|
<para>
|
|
The actual wine binary that the user runs does not do very much, in fact it is only
|
|
responsible for checking the threading model in use (NPTL vs LinuxThreads) and then invoking
|
|
a new binary which performs the next stage in the startup sequence. See the threading chapter
|
|
for more information on this check and why it's necessary. You can find this code in
|
|
<filename>loader/glibc.c</filename>. The result of this check is an exec of either
|
|
wine-pthread or wine-kthread, potentially (on Linux) via
|
|
the <emphasis>preloader</emphasis>. We need to use separate binaries here because overriding
|
|
the native pthreads library requires us to exploit a property of ELF symbol fixup semantics:
|
|
it's not possible to do this without starting a new process.
|
|
</para>
|
|
|
|
<para>
|
|
The Wine preloader is found in <filename>loader/preloader.c</filename>, and is required in
|
|
order to impose a Win32 style address space layout upon the newly created Win32 process. The
|
|
details of what this does is covered in the address space layout chapter. The preloader is a
|
|
statically linked ELF binary which is passed the name of the actual Wine binary to run (either
|
|
wine-kthread or wine-pthread) along with the arguments the user passed in from the command
|
|
line. The preloader is an unusual program: it does not have a main() function. In standard ELF
|
|
applications, the entry point is actually at a symbol named _start: this is provided by the
|
|
standard gcc infrastructure and normally jumps to <function>__libc_start_main</function> which
|
|
initializes glibc before passing control to the main function as defined by the programmer.
|
|
</para>
|
|
|
|
<para>
|
|
The preloader takes control direct from the entry point for a few reasons. Firstly, it is
|
|
required that glibc is not initialized twice: the result of such behaviour is undefined and
|
|
subject to change without notice. Secondly, it's possible that as part of initializing glibc,
|
|
the address space layout could be changed - for instance, any call to malloc will initialize a
|
|
heap arena which modifies the VM mappings. Finally, glibc does not return to _start at any
|
|
point, so by reusing it we avoid the need to recreate the ELF bootstrap stack (env, argv,
|
|
auxiliary array etc).
|
|
</para>
|
|
|
|
<para>
|
|
The preloader is responsible for two things: protecting important regions of the address
|
|
space so the dynamic linker does not map shared libraries into them, and once that is done
|
|
loading the real Wine binary off disk, linking it and starting it up. Normally all this is
|
|
done automatically by glibc and the kernel but as we intercepted this process by using a
|
|
static binary it's up to us to restart the process. The bulk of the code in the preloader is
|
|
about loading wine-[pk]thread and ld-linux.so.2 off disk, linking them together, then
|
|
starting the dynamic linking process.
|
|
</para>
|
|
|
|
<para>
|
|
One of the last things the preloader does before jumping into the dynamic linker is scan the
|
|
symbol table of the loaded Wine binary and set the value of a global variable directly: this
|
|
is a more efficient way of passing information to the main Wine program than flattening the
|
|
data structures into an environment variable or command line parameter then unpacking it on
|
|
the other side, but it achieves pretty much the same thing. The global variable set points to
|
|
the preload descriptor table, which contains the VMA regions protected by the preloader. This
|
|
allows Wine to unmap them once the dynamic linker has been run, so leaving gaps we can
|
|
initialize properly later on.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title> Starting the emulator </title>
|
|
|
|
<para>
|
|
The process of starting up the emulator itself is mostly one of chaining through various
|
|
initializer functions defined in the core libraries and DLLs: libwine, then NTDLL, then kernel32.
|
|
</para>
|
|
|
|
<para>
|
|
Both the wine-pthread and wine-kthread binaries share a common <function>main</function>
|
|
function, defined in <filename>loader/main.c</filename>, so no matter which binary is selected
|
|
after the preloader has run we start here. This passes the information provided by the
|
|
preloader into libwine and then calls wine_init, defined
|
|
in <filename>libs/wine/loader.c</filename>. This is where the emulation really starts:
|
|
<function>wine_init</function> can, with the correct preparation,
|
|
be called from programs other than the wine loader itself.
|
|
</para>
|
|
|
|
<para>
|
|
<function>wine_init</function> does some very basic setup tasks such as initializing the
|
|
debugging infrastructure, yet more address space manipulation (see the information on the
|
|
4G/4G VM split in the address space chapter), before loading NTDLL - the core of both Wine and
|
|
the Windows NT series - and jumping to the <function>__wine_process_init</function> function defined
|
|
in <filename>dlls/ntdll/loader.c</filename>
|
|
</para>
|
|
|
|
<para>
|
|
This function is responsible for initializing the primary Win32 environment. In thread_init(),
|
|
it sets up the TEB, the wineserver connection for the main thread and the process heap. See
|
|
the threading chapter for more information on this.
|
|
</para>
|
|
|
|
<para>
|
|
Finally, it loads and jumps to <function>__wine_kernel_init</function> in kernel32.dll: this
|
|
is defined in <filename>dlls/kernel32/process.c</filename>. This is where the bulk of the work
|
|
is done. The kernel32 initialization code retrieves the startup info for the process from the
|
|
server, initializes the registry, sets up the drive mapping system and locale data, then
|
|
begins loading the requested application itself. Each process has a STARTUPINFO block that can
|
|
be passed into <function>CreateProcess</function> specifying various things like how the first
|
|
window should be displayed: this is sent to the new process via the wineserver.
|
|
</para>
|
|
|
|
<para>
|
|
After determining the type of file given to Wine by the user (a Win32 EXE file, a Win16 EXE, a
|
|
Winelib app etc), the program is loaded into memory (which may involve loading and
|
|
initializing other DLLs, the bulk of Wines startup code), before control reaches the end of
|
|
<function>__wine_kernel_init</function>. This function ends with the new process stack being
|
|
initialized, and start_process being called on the new stack. Nearly there!
|
|
</para>
|
|
|
|
<para>
|
|
The final element of initializing Wine is starting the newly loaded program
|
|
itself. <function>start_process</function> sets up the SEH backstop handler, calls
|
|
<function>LdrInitializeThunk</function> which performs the last part of the process
|
|
initialization (such as performing relocations and calling the DllMains with PROCESS_ATTACH),
|
|
grabs the entry point of the executable and then on this line:
|
|
</para>
|
|
|
|
<programlisting>
|
|
ExitProcess( entry( peb ) );
|
|
</programlisting>
|
|
|
|
<para>
|
|
... jumps to the entry point of the program. At this point the users program is running and
|
|
the API provided by Wine is ready to be used. When entry returns,
|
|
the <function>ExitProcess</function> API will be used to initialize a graceful shutdown.
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 id="seh">
|
|
<title>Structured Exception Handling</title>
|
|
|
|
<para>
|
|
Structured Exception Handling (or SEH) is an implementation of
|
|
exceptions inside the Windows core. It allows code written in
|
|
different languages to throw exceptions across DLL boundaries, and
|
|
Windows reports various errors like access violations by throwing
|
|
them. This section looks at how it works, and how it's implemented
|
|
in Wine.
|
|
</para>
|
|
|
|
<sect2>
|
|
<title> How SEH works </title>
|
|
|
|
<para>
|
|
SEH is based on embedding EXCEPTION_REGISTRATION_RECORD
|
|
structures in the stack. Together they form a linked list rooted
|
|
at offset zero in the TEB (see the threading section if you
|
|
don't know what this is). A registration record points to a
|
|
handler function, and when an exception is thrown the handlers
|
|
are executed in turn. Each handler returns a code, and they can
|
|
elect to either continue through the handler chain or it can
|
|
handle the exception and then restart the program. This is
|
|
referred to as unwinding the stack. After each handler is called
|
|
it's popped off the chain.
|
|
</para>
|
|
|
|
<para>
|
|
Before the system begins unwinding the stack, it runs vectored
|
|
handlers. This is an extension to SEH available in Windows XP,
|
|
and allows registered functions to get a first chance to watch
|
|
or deal with any exceptions thrown in the entire program, from
|
|
any thread.
|
|
</para>
|
|
|
|
<para>
|
|
A thrown exception is represented by an EXCEPTION_RECORD
|
|
structure. It consists of a code, flags, an address and an
|
|
arbitrary number of DWORD parameters. Language runtimes can use
|
|
these parameters to associate language-specific information with
|
|
the exception.
|
|
</para>
|
|
|
|
<para>
|
|
Exceptions can be triggered by many things. They can be thrown
|
|
explicitly by using the RaiseException API, or they can be
|
|
triggered by a crash (ie, translated from a signal). They may be
|
|
used internally by a language runtime to implement
|
|
language-specific exceptions. They can also be thrown across
|
|
DCOM connections.
|
|
</para>
|
|
|
|
<para>
|
|
Visual C++ has various extensions to SEH which it uses to
|
|
implement, eg, object destruction on stack unwind as well as the
|
|
ability to throw arbitrary types. The code for this is in dlls/msvcrt/except.c
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2>
|
|
<title> Translating signals to exceptions </title>
|
|
|
|
<para>
|
|
In Windows, compilers are expected to use the system exception
|
|
interface, and the kernel itself uses the same interface to
|
|
dynamically insert exceptions into a running program. By contrast
|
|
on Linux the exception ABI is implemented at the compiler level
|
|
(inside GCC and the linker) and the kernel tells a thread of
|
|
exceptional events by sending <emphasis>signals</emphasis>. The
|
|
language runtime may or may not translate these signals into
|
|
native exceptions, but whatever happens the kernel does not care.
|
|
</para>
|
|
|
|
<para>
|
|
You may think that if an app crashes, it's game over and it
|
|
really shouldn't matter how Wine handles this. It's what you might
|
|
intuitively guess, but you'd be wrong. In fact some Windows
|
|
programs expect to be able to crash themselves and recover later
|
|
without the user noticing, some contain buggy binary-only
|
|
components from third parties and use SEH to swallow crashes, and
|
|
still others execute priviledged (kernel-level) instructions and
|
|
expect it to work. In fact, at least one set of APIs (the
|
|
IsBad*Ptr series) can only be implemented by performing an
|
|
operation that may crash and returning TRUE if it does, and FALSE
|
|
if it doesn't! So, Wine needs to not only implement the SEH
|
|
infrastructure but also translate Unix signals into SEH
|
|
exceptions.
|
|
</para>
|
|
|
|
<para>
|
|
The code to translate signals into exceptions is a part of NTDLL,
|
|
and can be found in dlls/ntdll/signal_i386.c. This file sets up
|
|
handlers for various signals during Wine startup, and for the ones
|
|
that indicate exceptional conditions translates them into
|
|
exceptions. Some signals are used by Wine internally and have
|
|
nothing to do with SEH.
|
|
</para>
|
|
|
|
<para>
|
|
Signal handlers in Wine run on their own stack. Each thread has
|
|
its own signal stack which resides 4k after the TEB. This is
|
|
important for a couple of reasons. Firstly, because there's no
|
|
guarantee that the app thread which triggered the signal has
|
|
enough stack space for the Wine signal handling code. In
|
|
Windows, if a thread hits the limits of its stack it triggers a
|
|
fault on the stack guard page. The language runtime can use this
|
|
to grow the stack if it wants to.
|
|
|
|
<!-- fixme: is it really the language runtime that does this? i
|
|
can't find any code in Wine to reallocate the stack on
|
|
STATUS_GUARD_PAGE_VIOLATION -->
|
|
|
|
However, because a guard page violation is just a regular
|
|
segfault to the kernel, that would lead to a nested signal
|
|
handler and that gets messy really quick so we disallow that in
|
|
Wine. Secondly, setting up the exception to throw requires
|
|
modifying the stack of the thread which triggered it, which is
|
|
quite hard to do when you're still running on it.
|
|
</para>
|
|
|
|
<para>
|
|
Windows exceptions typically contain more information than the
|
|
Unix standard APIs provide. For instance, a
|
|
STATUS_ACCESS_VIOLATION exception (0xC0000005) structure
|
|
contains the faulting address, whereas a standard Unix SIGSEGV
|
|
just tells the app that it crashed. Usually this information is
|
|
passed as an extra parameter to the signal handler, however its
|
|
location and contents vary between kernels (BSD, Solaris,
|
|
etc). This data is provided in a SIGCONTEXT structure, and on
|
|
entry to the signal handler it contains the register state of
|
|
the CPU before the signal was sent. Modifying it will cause the
|
|
kernel to adjust the context before restarting the thread.
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
</sect1>
|
|
|
|
</chapter>
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-parent-document:("wine-devel.sgml" "set" "book" "part" "chapter" "")
|
|
End:
|
|
-->
|