Subject: struct kevent udata member type
To: None <current-users@NetBSD.org>
From: Mathias De Belder <mathias@woei.be>
List: current-users
Date: 10/25/2007 21:47:21
Hi all,

When trying to make net/libtorrent, a C++ bittorrent library, with the
--with-kqueue option, I stumbled upon a problem related to the way
struct kevent's udata member is defined in sys/event.h.  In NetBSD, this
structure field is an `intptr_t'[1], an integral type capable of holding
a void *.  C++ has a stricter type system than C and disallows comparing
a pointer to an integer or assigning the former to the latter.  This
makes libtorrent fail to build on NetBSD, because it assumes udata will
be a void pointer[2].

On FreeBSD[3], OpenBSD[4], DragonFlyBSD[5] and Darwin[6], the
kevent.udata field is indeed a void *.  After modifying sys/event.h on a
NetBSD system to follow suit, libtorrent indeed compiles correctly and
programs using it work fine too.  This is expected, as on ILP32
machines, intptr_t gets typedeffed to an int, and on LP64 to a long, the
size of a pointer on these architectures.

However, I don't think one should be changing system header files to
make programs compile.  You could introduce casts in C and
reinterpret_cast<intptr_t> in C++, as is done in the NetBSD source tree
in a few places [7][8].  libevent uses a macro when built on NetBSD to
cast to intptr_t [9]. However, in the case of libtorrent, the udata
member is sometimes accessed as part of the C++ mem_fun() template and
dereferenced in an instantiated template, where it's not possible to
explicitly cast the template argument.

GCC emits a warning when assigning a pointer to kevent's udata member. A
C++ compiler refuses to compile the assignment.  To respectively silence
the warning or make the code compile, one would have to introduce a cast
anyway.  In the case of C++, adding such a cast is not always possible.
All because udata is defined as an intptr_t.  I wonder why this extra
step of indirection was taken in NetBSD.  It saves you a cast in case
udata really is an int and not a pointer.  Might there be another reason
why NetBSD deviates from the API used in the other BSDs ? Facilitating
pointer arithmetic somehow ? A requirement for some weird architecture
only NetBSD runs on ? Something else ?

To make it easier for C++ programs to use the kqueue event system and in
following the principle of least surprise, would it not be better to
change udata to be a void pointer ?


Mathias

[1] <url:http://cvsweb.netbsd.org/bsdweb.cgi/src/sys/sys/event.h>
[2] <url:http://libtorrent.rakshasa.no/browser/trunk/libtorrent/src/torrent/poll_kqueue.cc#L170>
[3] <url:http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/sys/event.h>
[4] <url:http://www.openbsd.org/cgi-bin/cvsweb/src/sys/sys/event.h>
[5] <url:http://www.dragonflybsd.org/cvsweb/src/sys/sys/event.h>
[6] <url:http://developer.apple.com/documentation/Darwin/Reference/ManPages/man2/kqueue.2.html>
[7] <url:http://cvsweb.netbsd.org/bsdweb.cgi/src/usr.sbin/powerd/powerd.c?rev=1.12>
[8] <url:http://cvsweb.netbsd.org/bsdweb.cgi/src/usr.sbin/syslogd/syslogd.c?rev=1.84>
[9] <url:http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libevent/kqueue.c?rev=1.5>