On Wed, Mar 23, 2011 at 11:06:08AM +0100, Michal Privoznik wrote: > diff --git a/src/libvirtSnmp.c b/src/libvirtSnmp.c > index > dd1bd33dc3fbc08656d09075a3c1a1741ebc002f..1bc947d85384e2ced111cde301951b4e5c3666f6 > 100644 > --- a/src/libvirtSnmp.c > +++ b/src/libvirtSnmp.c > @@ -22,12 +22,168 @@ > > #include <stdio.h> > #include <stdlib.h> > +#include <sys/types.h> > +#include <sys/poll.h> > +#include <pthread.h> > +#include <signal.h> > > #include "libvirtSnmp.h" > -/* include our MIB structures*/ > -#include "libvirtGuestTable.h" > +#include "libvirtGuestTable.h" /* include our MIB structures*/ > +#include "libvirtNotifications.h" > > +#define DEBUG0(fmt) if (verbose) printf("%s:%d :: " fmt "\n", \ > + __func__, __LINE__) > +#define DEBUG(fmt, ...) if (verbose) printf("%s:%d: " fmt "\n", \ > + __func__, __LINE__, __VA_ARGS__) > +#define STREQ(a,b) (strcmp(a,b) == 0) > + > +#ifndef ATTRIBUTE_UNUSED > +#define ATTRIBUTE_UNUSED __attribute__((__unused__)) > +#endif > + > +int verbose = 0; > virConnectPtr conn; > +int callbackRet = -1; > +int run = 1; > +pthread_t poll_thread; > + > +/* handle globals */ > +int h_fd = 0; > +virEventHandleType h_event = 0; > +virEventHandleCallback h_cb = NULL; > +virFreeCallback h_ff = NULL; > +void *h_opaque = NULL; > + > +/* timeout globals */ > +#define TIMEOUT_MS 1000 > +int t_active = 0; > +int t_timeout = -1; > +virEventTimeoutCallback t_cb = NULL; > +virFreeCallback t_ff = NULL; > +void *t_opaque = NULL; > + > + > +static int > +domainEventCallback(virConnectPtr conn ATTRIBUTE_UNUSED, > + virDomainPtr dom, int event, int detail, > + void *opaque ATTRIBUTE_UNUSED) > +{ > + DEBUG("%s EVENT: Domain %s(%d) %d %d\n", __func__, > + virDomainGetName(dom), virDomainGetID(dom), event, detail); > + > + send_libvirtGuestNotif_trap(dom); > + return 0; > +} > + > +static void > +myFreeFunc(void *opaque) > +{ > + if (opaque) > + free(opaque); > +} > + > +/* EventImpl Functions */ > +int > +myEventHandleTypeToPollEvent(virEventHandleType events) > +{ > + int ret = 0; > + > + if (events & VIR_EVENT_HANDLE_READABLE) > + ret |= POLLIN; > + if (events & VIR_EVENT_HANDLE_WRITABLE) > + ret |= POLLOUT; > + if (events & VIR_EVENT_HANDLE_ERROR) > + ret |= POLLERR; > + if (events & VIR_EVENT_HANDLE_HANGUP) > + ret |= POLLHUP; > + return ret; > +} > + > +virEventHandleType > +myPollEventToEventHandleType(int events) > +{ > + virEventHandleType ret = 0; > + > + if (events & POLLIN) > + ret |= VIR_EVENT_HANDLE_READABLE; > + if (events & POLLOUT) > + ret |= VIR_EVENT_HANDLE_WRITABLE; > + if (events & POLLERR) > + ret |= VIR_EVENT_HANDLE_ERROR; > + if (events & POLLHUP) > + ret |= VIR_EVENT_HANDLE_HANGUP; > + return ret; > +} > + > +int > +myEventAddHandleFunc(int fd, int event, > + virEventHandleCallback cb, > + void *opaque, virFreeCallback ff) > +{ > + DEBUG("Add handle %d %d %p %p", fd, event, cb, opaque); > + h_fd = fd; > + h_event = myEventHandleTypeToPollEvent(event); > + h_cb = cb; > + h_ff = ff; > + h_opaque = opaque; > + return 0; > +} > + > +void > +myEventUpdateHandleFunc(int fd, int event) > +{ > + DEBUG("Updated Handle %d %d", fd, event); > + h_event = myEventHandleTypeToPollEvent(event); > + return; > +} > + > +int > +myEventRemoveHandleFunc(int fd) > +{ > + DEBUG("Removed Handle %d", fd); > + h_fd = 0; > + if (h_ff) > + (h_ff) (h_opaque); > + return 0; > +} > + > +int > +myEventAddTimeoutFunc(int timeout, > + virEventTimeoutCallback cb, > + void *opaque, virFreeCallback ff) > +{ > + DEBUG("Adding Timeout %d %p %p", timeout, cb, opaque); > + t_active = 1; > + t_timeout = timeout; > + t_cb = cb; > + t_ff = ff; > + t_opaque = opaque; > + return 0; > +} > + > +void > +myEventUpdateTimeoutFunc(int timer ATTRIBUTE_UNUSED, int timeout) > +{ > + /*DEBUG("Timeout updated %d %d", timer, timeout); */ > + t_timeout = timeout; > +} > + > +int > +myEventRemoveTimeoutFunc(int timer) > +{ > + DEBUG("Timeout removed %d", timer); > + t_active = 0; > + if (t_ff) > + (t_ff) (t_opaque); > + return 0; > +}
What is the oldest version of libvirt that you need to be able to run libvirt-snmp against ? This impl of the file handle / timer callbacks taken from the C example program is really not a very good one to copy / use. If you are able to say that you only need to support the next libvirt 0.9.0 or newer, then you can simply use our new public APIs for this int virEventRegisterDefaultImpl(void); int virEventRunDefaultImpl(void); > +/* Polling thread function */ > +void * > +pollingThreadFunc(void *foo) { > + int sts; > + > + while (run) { > + struct pollfd pfd = {.fd = h_fd, > + .events = h_event, > + .revents = 0 > + }; > + > + sts = poll(&pfd, 1, TIMEOUT_MS); > + > + /* if t_timeout < 0 then t_cb must not be called */ > + if (t_cb && t_active && t_timeout >= 0) { > + t_cb(t_timeout, t_opaque); > + } > + > + if (sts == 0) { > + /* DEBUG0("Poll timeout"); */ > + continue; > + } > + if (sts < 0) { > + DEBUG0("Poll failed"); > + continue; > + } > + if (pfd.revents & POLLHUP) { > + DEBUG0("Reset by peer"); > + pthread_exit(NULL); > + } > + > + if (h_cb) { > + h_cb(0, > + h_fd, > + myPollEventToEventHandleType(pfd.revents & h_event), > + h_opaque); > + } > + > + } > + > + pthread_exit(NULL); > +} This loop would just turn into while (run) { if (virEventRunDefaultImpl() < 0) { ...print error... pthread_exit(NULL); } } > + > +/* Function to register domain lifecycle events collection */ > +int > +libvirtRegisterEvents(virConnectPtr conn) { > + struct sigaction action_stop; > + pthread_attr_t thread_attr; > + > + memset(&action_stop, 0, sizeof action_stop); > + > + action_stop.sa_handler = stop; > + > + sigaction(SIGTERM, &action_stop, NULL); > + sigaction(SIGINT, &action_stop, NULL); > + > + DEBUG0("Registering domain event callback"); > + > + callbackRet = virConnectDomainEventRegisterAny(conn, NULL, > + > VIR_DOMAIN_EVENT_ID_LIFECYCLE, > + VIR_DOMAIN_EVENT_CALLBACK > + (domainEventCallback), > + NULL, myFreeFunc); > + > + if (callbackRet == -1) > + return -1; > + > + /* we need a thread to poll for events */ > + pthread_attr_init(&thread_attr); > + pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE); > + > + if (pthread_create > + (&poll_thread, &thread_attr, pollingThreadFunc, NULL)) > + return -1; > + > + pthread_attr_destroy(&thread_attr); > + > + return 0; > +} > + > +/* Unregister domain events collection */ > +int > +libvirtUnregisterEvents(virConnectPtr conn) > +{ > + void *status; > + > + pthread_join(poll_thread, &status); > + virConnectDomainEventDeregisterAny(conn, callbackRet); > + callbackRet = -1; > + return 0; > +} > + > int libvirtSnmpInit(void) > { > - /* virConnectOpenAuth is called here with all default parameters, > - * except, possibly, the URI of the hypervisor. */ > + char *verbose_env = getenv("LIBVIRT_SNMP_VERBOSE"); > + > + verbose = verbose_env != NULL; > + > + /* if we don't already have registered callback */ > + if (callbackRet == -1) > + virEventRegisterImpl(myEventAddHandleFunc, > + myEventUpdateHandleFunc, > + myEventRemoveHandleFunc, > + myEventAddTimeoutFunc, > + myEventUpdateTimeoutFunc, > + myEventRemoveTimeoutFunc); And this can be replaced by virEventRegisterDefaultImpl(). On the other hand, if you need to be able to build against older libvirt releases, then you should probably just copy the code from src/util/event_poll.c in the libvirt GIT repo, straight into libvirt-snmp, instead of using the C event example code. Regards, Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list