95 lines
3.8 KiB
Text
95 lines
3.8 KiB
Text
|
fhandler tutorial
|
||
|
|
||
|
This document will show how to add a new "fhandler" to cygwin, by
|
||
|
showing an example of /dev/zero.
|
||
|
|
||
|
Files to note:
|
||
|
|
||
|
fhandler.h - must define a new derived class here and FH_*
|
||
|
devices.in - to notice "/dev/zero" and mark it
|
||
|
fhandler_zero.cc - new
|
||
|
dtable.cc - to create the fhandler instance
|
||
|
|
||
|
OK, first we have to define what this new fhandler will do. In our
|
||
|
example case, we're going to implement the unix "/dev/zero" device,
|
||
|
which has the following characteristics:
|
||
|
|
||
|
* writes to /dev/zero are silently discarded
|
||
|
* reads from /dev/zero return all zero bytes
|
||
|
* mmap()ing /dev/zero maps a chunk of zero'd out memory.
|
||
|
|
||
|
Since windows doesn't have a device that acts like this, we'll be
|
||
|
simulating everything. Thus:
|
||
|
|
||
|
* writes simply return a success status
|
||
|
* reads memset() the buffer and return success
|
||
|
* we take advantage of the fact that CreateFileMapping can take a
|
||
|
handle of -1, which (1) maps swap memory, and (2) zeros it out for
|
||
|
us (at least, on NT).
|
||
|
|
||
|
OK, let's start with devices.h.
|
||
|
|
||
|
We have to create a new entry in the enum fh_devices. The new
|
||
|
devices must get a major and a minor ID. As a rule of thumb, just
|
||
|
copy the ones that are used on a linux system.
|
||
|
|
||
|
Now, let's continue with fhandler.h.
|
||
|
|
||
|
First, update the fhandler_union near the end of the file with a
|
||
|
line for the new device. Use existing members, in this case __dev_null
|
||
|
as a template. This union is sorted alphabetically.
|
||
|
|
||
|
Earlier in that file, we'll copy fhandler_dev_null and edit it to be
|
||
|
fhandler_dev_zero. I chose that one because it's small, but we'll add
|
||
|
more members as we go (since we're simulating the whole thing). In
|
||
|
fact, let's copy the I/O methods from fhandler_windows since we'll
|
||
|
need all those anyway, even though we'll go through the full list
|
||
|
later.
|
||
|
|
||
|
OK, next we need to edit devices.in. There is a section where each device
|
||
|
is listed with its cygwin path, its structure and its windows path.
|
||
|
"/dev/zero", FH_ZERO, "\\dev\\zero"
|
||
|
This is needed to recognize when the user is trying to open "/dev/zero".
|
||
|
You have to build devices.cc from devices.in now.
|
||
|
There is a script 'gendevices' in the winsup/cygwin directory which may
|
||
|
be called at some time in the future if you use 'make' to build the DLL.
|
||
|
This should rebuild the devices.cc file. You have to have shilka
|
||
|
available to do that; this is part of the cygwin cocom package.
|
||
|
|
||
|
To go along with that change, we'll need to change dtable.cc. Look for
|
||
|
FH_NULL and add a case for FH_ZERO as well.
|
||
|
|
||
|
Now we get to fhandler_zero.cc itself. Create the empty file and copy
|
||
|
the "usual" header/copyright/includes from some other fhandler_*.cc
|
||
|
source file. Also, edit Makefile.in to build this new file. Add one
|
||
|
new entry to DLL_OFILES, and a new line for the winsup.h dependencies.
|
||
|
|
||
|
Since we changed fhandler.h, when you type "make" it will rebuild
|
||
|
everything. Go ahead and do that when you get a chance to let it run,
|
||
|
since we're not changing the headers any more. Note that you won't be
|
||
|
able to link the new dll, as we haven't added all the methods for the
|
||
|
new fhandler class yet, but at least you'll get a lot of compilation
|
||
|
out of the way.
|
||
|
|
||
|
Next we start adding in the fhandler methods themselves.
|
||
|
|
||
|
Constructor: This takes a name, and all we do is pass that name back
|
||
|
to the base class, along with the FH_ZERO value. We call set_cb
|
||
|
because all fhandlers call this (it's for exec to copy the fd).
|
||
|
|
||
|
open: we override the one that takes a name because there are no real
|
||
|
windows devices like /dev/zero, but we ignore the name. We call
|
||
|
set_flags to save the flags.
|
||
|
|
||
|
write: writes are discarded; we return success.
|
||
|
|
||
|
read: reads read NUL bytes, so fill the buffer with NULs and return
|
||
|
success.
|
||
|
|
||
|
lseek/close: just return success.
|
||
|
|
||
|
dump: this is just for debugging, so we just print something.
|
||
|
|
||
|
select_*: we don't support this yet, see the myriad examples in
|
||
|
select.cc for examples. The base fhandler's methods will do for now.
|