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 :|