On Tue, Jan 10, 2017 at 10:48:47AM +0100, Martin Kletzander wrote:
On Tue, Jan 10, 2017 at 02:58:21AM -0500, Laine Stump wrote:
> On 01/09/2017 08:09 PM, Richard W.M. Jones wrote:
> > On Mon, Jan 09, 2017 at 04:58:49PM +0000, Daniel P. Berrange wrote:
> > > For those who don't already know, GCC and CLang both implement a C
language
> > > extension that enables automatic free'ing of resources when variables
go
> > > out of scope. This is done by annotating the variable with the
"cleanup"
> > > attribute, pointing to a function the compiler will wire up a call to
when
> > > unwinding the stack. Since the annotation points to an arbitrary user
> > > defined function, you're not limited to simple free() like semantics.
The
> > > cleanup function could unlock a mutex, or decrement a reference count,
etc
> > >
> > > This annotation is used extensively by systemd, and libguestfs, amongst
> > > other projects. This obviously doesn't bring full garbage collection
to
> > > C, but it does enable the code to be simplified. By removing the need to
> > > put in many free() (or equiv) calls to cleanup state, the
"interesting"
> > > logic in the code stands out more, not being obscured by cleanup calls
> > > and goto jumps.
> > >
> > > I'm wondering what people think of making use of this in libvirt ?
> > >
> > > To my mind the only real reason to *not* use it, would be to maintain
> > > code portability to non-GCC/non-CLang compilers. OS-X, *BSD and *Linux
> > > all use GCC or CLang or both, so its a non-issue there. So the only place
> > > this could cause pain is people building libvirt on Win32, who are using
> > > the Microsoft compilers instead og GCC.
> > >
Only reason I see for not using it is the "temporary" mess it will
cause. Yes, we can change to that incrementally, but it will take some
time and effort and it will never be all of the code that uses it.
Don't get me wrong, I would love using more builtin compiler features
and shortening the code here and there. I'm just worried this
particular one might be more disrupting than useful. Most of us are
pretty used to the code flow we already have and there's nothing you
can't achieve without the cleanup attribute.
And yes, I used quotation marks around the word temporary intentionally.
Yes, that's why I thought of it as something that would make for a GSoc
project - have someone do a full conversion of particular areas of code.
eg convert all of util/ or convert the domain XML parser, etc. Basically
if we did it, I think we'd want to have entire files converted at once.
Only converting individual methods ad-hoc would be quite messy.
> > > IMHO, it is perfectly valid for us to declare that
MSVC is unsupported
> > > with Libvirt and users must use GCC to build on Windows, either natively
> > > via cygwin, or cross-build from Linux hosts.
I would love to know if anyone actually tried doing that lately. Given
how often we are broken with mingw and we only foind out thanks to our
test suite (and sometomes the fixing takes more than a release cycle), I
think nobody does that and from what I know, it might not even work.
We have mingw in the CI system for a while now and its generally fixed
as quickly as native arch builds are fixed these days.
> > (2) You must not write code like:
> >
> > fn ()
> > {
> > CLEANUP_FREE char *v; // uninitialized
> >
> > if (some error condition) {
> > return -1;
> > }
> > ...
> > }
> >
> > because that will call free (v) on the uninitialized variable.
> > Sometimes GCC can spot this. In libguestfs we tend to initialize
> > every CLEANUP_* variable to either an explicit value or NULL. GCC
> > optimizes away calls to free (NULL).
>
I'm trying to initialize all variables, always, so I don't see this as a
problem, but there are some of us that (I have the feeling) are trying
to initialize as few as possible, so this (although it's a different
story) might still be a problem for someone.
We pretty much have the same problem already with 'goto cleanup' - you
have to make sure everything is initialized sanely before the first
"goto cleanup". So I think we're safe in this respect already and
the cleanup attributes wouldn't make it any more complex.
> You've covered one of the worries that I had about it
(accidentally
> marking for CLEANUP a pointer whose value gets returned, and the fact
> that you can't use it for the cleanup of objects that would have
> normally been returned, in the case that the function encounters an
> error and has to dump everything). And since the nice cleanup isn't
> happening for *everything*, people will have to be paying attention to
> which objects are auto-cleaned up and which aren't, which will
> inevitably lead to incorrect classification and/or accidentally adding
> manual cleanup for something that's auto-cleaned or vice versa. (and
> merging this into the code bit by bit is going to exacerbate this
> problem). Also, there is something to be said for having all the code
> that's executed sitting out there in the open in an easy to follow
> format rather than obscured behind a macro and a compiler directive that
> points you up to somewhere else.
>
I don't really like our macros around __attribute__ although I
understand we need to have some of them to be dynamically defined to
nothing in some cases. However with __attribute__((cleanup)), we will
need to have that all the time. What's even better, you immediatelly
see what function will be called on the cleanup and you can jump to the
tag definition more easily.
If we mandate use of gcc / clang, then we wouldn't need to hide it
behind a macro - we'd be able to use it inline. That said, using a
macro makes it smaller and gives a bit of standardization. eg with
libguestfs style:
#define CLEANUP_FREE __attribute__((cleanup(free)))
#define CLEANUP_OBJECT_UNREF __attribute__((cleanup(virObjectUnref)))
CLEANUP_FREE char *str;
CLEANUP_OBJECT_UNREF virDomainPtr dom;
vs full inline style:
__attribute__((cleanup(free))) char *str;
__attribute__((cleanup(virObjectUnref))) virDomainPtr dom;
That said I see systemd took a halfway house
#define _cleanup_(x) __attribute__((cleanup(x)))
_cleanup(free) char *str;
_cleanup(virObjectUnref) virDomainPtr dom;
I think the systemd style is quite reasonable, as its shorter
and the function called is still clear.
Regards,
Daniel
--
|:
http://berrange.com -o-
http://www.flickr.com/photos/dberrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org :|
|:
http://entangle-photo.org -o-
http://search.cpan.org/~danberr/ :|