Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 15 Nov 2010 19:24:43 +0000
From:      Paul LeoNerd Evans <leonerd@leonerd.org.uk>
To:        John Baldwin <jhb@freebsd.org>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: Managing userland data pointers in kqueue/kevent
Message-ID:  <20101115192443.GX11110@cel.leo>
In-Reply-To: <201011151410.46130.jhb@freebsd.org>
References:  <20101112184000.GS11110@cel.leo> <201011151125.42697.jhb@freebsd.org> <20101115181211.GV11110@cel.leo> <201011151410.46130.jhb@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help

--VLyqDKa+9yql3vk0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Mon, Nov 15, 2010 at 02:10:45PM -0500, John Baldwin wrote:
> On Monday, November 15, 2010 1:12:11 pm Paul LeoNerd Evans wrote:
> > On Mon, Nov 15, 2010 at 11:25:42AM -0500, John Baldwin wrote:
> > > I think the assumption is that userland actually maintains a referenc=
e on the=20
> > > specified object (e.g. a file descriptor) and will know to drop the a=
ssociated=20
> > > data when the file descriptor is closed.  That is, think of the keven=
t as a=20
> > > member of an eventable object rather than a separate object that has =
a=20
> > > reference to the eventable object.  When the eventable object's refer=
ence=20
> > > count drops to zero in userland, then the kevent should be deleted, e=
ither via=20
> > > EV_DELETE, or implicitly (e.g. by closing the associated file descrip=
tor).
> >=20
> > Ah. Well, that could be considered a bit more awkward for the use case I
> > wanted to apply. The idea was that the  udata  would refer effectively
> > to a closure, to invoke when the event happens. The idea being you can
> > just add an event watcher by, say:
> >=20
> >   $ev->EV_SET( $pid, EVFILT_PROC, 0, NOTE_EXIT, 0, sub {
> >      print STDERR "The child process $pid has now exited\n";
> >   } );
> >=20
> > So, the kernel's udata pointer effectively holds the only reference to
> > this anonymous closure. It's much more flexible this way, especially for
> > oneshot events like that.
> >=20
> > The beauty is also that the kevents() loop can simply know that the
> > udata is always a code reference so just has to invoke it to do whatever
> > the original caller wanted to do.
> >=20
> > Keep in mind my use-case here; I'm not trying to be one specific
> > application, it's a general-purpose kevent-wrapping library.
>=20
> So is GCD (Apple's libdispatch).  It also implements closures on top of
> kevent.  However, the way it works is that it doesn't expose kevent()
> directly, instead it uses kevent to implement asynchronous I/O on a=20
> socket for example, and since it is logically managing the life cycle
> of a socket, it knows when the socket is closed and cleans up then.

Well, the principle item of work here is a direct API reimplementation
in IO::KQueue on CPAN. I'm trying to simply expose the API of storing an
arbitrary Perl scalar in the  udata  field. It -could- be a closure, but
of course it doesn't have to. Maybe the using code wants to keep a HASH
ref of some pseudo-structure, or whatever...

> For the above case, if you know an event is one shot, you should either
> use EV_ONESHOT, or use a wrapper around the closure that clears the event
> after the closure runs (or possibly before the closure runs?)

I don't see how passing EV_ONESHOT at all helps here. If it's oneshot by
nature (child process exit), it'll be oneshot whatever happens. I've
already observed that the EV_ONESHOT flag does not get re-emitted by the
kernel anyway, so I'd have to track that one separately somehow.

> Your use case is rare.  Almost all consumers of kevent() that I've seen
> use kevent() as one part of a system that maintain the lifecycle of objec=
ts.
> Those objects are only accessed within the system, so the system knows wh=
en
> an object is closed and can release the resources at the same time.

OK. I'm prepared to accept this. It may be that nobody's really tried to
provide a simple kqueue/kevent API wrapping for a high-level language,
that could nicely take advantage of memory management in the language,
rather than at the low C level of explicit malloc+free.


Could we perhaps address the second part of my question for a moment? If
there really isn't a general solution here, could my EV_FREEWATCH flag
be added? It's a single extra flag to export in the API .h file,
completely backward-compatible. Surely quite simple to implement in the
kernel too, because it already knows how to free() its own internal
structures anyway; so just before it does that when it deletes an event
for whatever reason, it could just fire that event back up to userland
to say "I've dropped this, and here have your pointer back". Userland
catches it, SvRECFNT_dec()s or whatever, problem solved.

Is that an API extension anyone would consider accepting? I for one
would use it.

--=20
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk
ICQ# 4135350       |  Registered Linux# 179460
http://www.leonerd.org.uk/

--VLyqDKa+9yql3vk0
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)

iD8DBQFM4Yj7vLS2TC8cBo0RAoI0AKCvJS0Kd/f/+NEcRm39wbLJEA7J3wCbBLjm
dJVDke7vE7mOeDH9LH0znYk=
=8T/B
-----END PGP SIGNATURE-----

--VLyqDKa+9yql3vk0--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20101115192443.GX11110>