The attached patch (against libvirt-java) implements Java bindings for libvirt domain events. This version provides a libvirt EventImpl running in its own Java Thread, and provides per-Connect synchronization that makes using the bindings thread-safe. (Note the Domain, Network, StoragePool, and StorageVol methods also synchronize on their Connect object, as required by libvirt. I have similar changes for NodeDevice.java that need to be made when that code is checked in.) This version of the patch also implements and uses an enum class (DomainEvent.Type), as suggested by Tóth István. IMPORTANT: THIS PATCH WILL BREAK THINGS UNLESS THE NEXT [PATCH 2/2] IS APPLIED TO libvirt FIRST. Also, libvirt must be compiled WITH_PTHREADS for Java events to work. Dave
diff --git a/src/EventTest.java b/src/EventTest.java new file mode 100644 index 0000000..42782fa --- /dev/null +++ b/src/EventTest.java @@ -0,0 +1,39 @@ +import org.libvirt.*; + +class TestDomainEventListener implements DomainEventListener { + + String name; + + TestDomainEventListener(String name) { + this.name = name; + } + + public void handle(Domain dom, DomainEvent.Type event) { + try { + System.out.printf("%s: dom %s got event %s\n", name, dom.getName(), event); + } catch (LibvirtException e) { + System.out.println(e); + System.out.printf("%s: unknown dom got event %s\n", name, event); + } + } +} + +class EventTest { + + public static void main(String args[]) throws LibvirtException { + String URI = "qemu:///system"; + if (args.length > 0) + URI = args[0]; + Connect conn = new Connect(URI); + System.out.println("Connected to " + URI); + conn.domainEventRegister(new TestDomainEventListener("Test 1")); + conn.domainEventRegister(new TestDomainEventListener("Test 2")); + System.out.println("Listening for domain events ..."); + try { + while (true) + Thread.sleep(1000); + } catch (InterruptedException e) { + System.out.println("Exiting EventTest"); + } + } +} diff --git a/src/Makefile.am b/src/Makefile.am index 5200c1d..6ca0d81 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,9 +7,12 @@ java_libvirt_source_files = \ org/libvirt/ConnectAuthDefault.java \ org/libvirt/ConnectAuth.java \ org/libvirt/DomainBlockStats.java \ + org/libvirt/DomainEvent.java \ + org/libvirt/DomainEventListener.java \ org/libvirt/DomainInfo.java \ org/libvirt/DomainInterfaceStats.java \ org/libvirt/Domain.java \ + org/libvirt/EventImpl.java \ org/libvirt/ErrorException.java \ org/libvirt/Error.java \ org/libvirt/Network.java \ diff --git a/src/jni/Makefile.am b/src/jni/Makefile.am index c894024..829298a 100644 --- a/src/jni/Makefile.am +++ b/src/jni/Makefile.am @@ -5,6 +5,7 @@ GENERATED = \ org_libvirt_Domain_CreateFlags.h \ org_libvirt_Domain_MigrateFlags.h \ org_libvirt_Domain_XMLFlags.h \ + org_libvirt_EventImpl.h \ org_libvirt_StoragePool_BuildFlags.h \ org_libvirt_StoragePool_DeleteFlags.h \ org_libvirt_StoragePool.h \ @@ -25,6 +26,9 @@ org_libvirt_Network.h: $(JAVA_CLASS_ROOT)/org/libvirt/Network.class org_libvirt_Domain.h org_libvirt_Domain_CreateFlags.h org_libvirt_Domain_MigrateFlags.h org_libvirt_Domain_XMLFlags.h : $(JAVA_CLASS_ROOT)/org/libvirt/Domain.class $(JAVAH) -classpath $(JAVA_CLASS_ROOT) org.libvirt.Domain +org_libvirt_EventImpl.h : $(JAVA_CLASS_ROOT)/org/libvirt/EventImpl.class + $(JAVAH) -classpath $(JAVA_CLASS_ROOT) org.libvirt.EventImpl + org_libvirt_StoragePool.h org_libvirt_StoragePool_BuildFlags.h org_libvirt_StoragePool_DeleteFlags.h : $(JAVA_CLASS_ROOT)/org/libvirt/StoragePool.class $(JAVAH) -classpath $(JAVA_CLASS_ROOT) org.libvirt.StoragePool @@ -36,6 +40,7 @@ libvirt_jni_la_SOURCES = \ org_libvirt_Network.c \ org_libvirt_Connect.c \ org_libvirt_Domain.c \ + org_libvirt_EventImpl.c \ org_libvirt_StoragePool.c \ org_libvirt_StorageVol.c \ generic.h \ diff --git a/src/jni/org_libvirt_Connect.c b/src/jni/org_libvirt_Connect.c index cbf437c..612c5d7 100644 --- a/src/jni/org_libvirt_Connect.c +++ b/src/jni/org_libvirt_Connect.c @@ -1,3 +1,4 @@ +#include <jni.h> #include "org_libvirt_Connect.h" #include <libvirt/libvirt.h> #include <stdlib.h> @@ -361,3 +362,96 @@ JNIEXPORT jlong JNICALL Java_org_libvirt_Connect__1virStoragePoolLookupByName GENERIC_LOOKUPBY_STRING(env, obj, (virConnectPtr)VCP, j_name, virStoragePoolLookupByName) } + + +static JavaVM *jvm; // Setup by JNI_OnLoad, below + +// A "JNI_OnLoad" hook gets called when the JVM loads a JNI library. +// Here it is used to grab a pointer to the JavaVM for later use in +// obtaining the JNIEnv pointer when it is otherwise more difficult +// (e.g. in C callbacks invoked by libvirt). +jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) { + jvm = vm; + return JNI_VERSION_1_4; +} + + +static int domainEventCallback(virConnectPtr conn, virDomainPtr dom, + int event, void *opaque) +{ + jobject conn_obj = (jobject)opaque; + JNIEnv * env; + jobject dom_obj; + jclass dom_cls, conn_cls; + jmethodID ctorId, methId; + + // Invoke conn.fireDomainEventCallbacks(dom, event) + + if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4) != JNI_OK || env == NULL) { + printf("error getting JNIEnv\n"); + return -1; + } + + dom_cls = (*env)->FindClass(env, "org/libvirt/Domain"); + if (dom_cls == NULL) { + printf("error finding class Domain\n"); + return -1; + } + + ctorId = (*env)->GetMethodID(env, dom_cls, "<init>", "(Lorg/libvirt/Connect;J)V"); + if (ctorId == NULL) { + printf("error finding Domain constructor\n"); + return -1; + } + + dom_obj = (*env)->NewObject(env, dom_cls, ctorId, conn_obj, dom); + if (dom_obj == NULL) { + printf("error constructing Domain\n"); + return -1; + } + + conn_cls = (*env)->FindClass(env, "org/libvirt/Connect"); + if (conn_cls == NULL) { + printf("error finding class Connect\n"); + return -1; + } + + methId = (*env)->GetMethodID(env, conn_cls, "fireDomainEventCallbacks", "(Lorg/libvirt/Domain;I)V"); + if (methId == NULL) { + printf("error finding Connect.fireDomainEventCallbacks\n"); + return -1; + } + + (*env)->CallVoidMethod(env, conn_obj, methId, dom_obj, event); + + return 0; +} + + +static void delete_global_ref(void *opaque) +{ + jobject obj = (jobject)opaque; + JNIEnv *env; + + if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4) != JNI_OK || env == NULL) { + printf("%s: error getting JNIEnv\n", __FUNCTION__); + return; + } + + (*env)->DeleteGlobalRef(env, obj); +} + + +JNIEXPORT void JNICALL Java_org_libvirt_Connect_registerForDomainEvents +(JNIEnv *env, jobject obj, jlong VCP){ + obj = (*env)->NewGlobalRef(env, obj); + virConnectDomainEventRegister((virConnectPtr)VCP, domainEventCallback, obj, + delete_global_ref); + +} + +JNIEXPORT void JNICALL Java_org_libvirt_Connect_deregisterForDomainEvents +(JNIEnv *env, jobject obj, jlong VCP){ + virConnectDomainEventDeregister((virConnectPtr)VCP, domainEventCallback); +} + diff --git a/src/jni/org_libvirt_EventImpl.c b/src/jni/org_libvirt_EventImpl.c new file mode 100644 index 0000000..1050bc7 --- /dev/null +++ b/src/jni/org_libvirt_EventImpl.c @@ -0,0 +1,617 @@ +#include <stdlib.h> +#include <unistd.h> +#include <poll.h> +#include <string.h> +#include <errno.h> + +#include "org_libvirt_EventImpl.h" +#include <libvirt/libvirt.h> + +#define EVENT_DEBUG(fmt, ...) //do { printf("%s:%d (" fmt ")\n", __FUNCTION__, __LINE__, __VA_ARGS__); } while (0); + +// Copied from libvirt/src/memory.h: + +#define VIR_ALLOC_N(ptr, count) __virAllocN(&(ptr), sizeof(*(ptr)), (count)) +#define VIR_REALLOC_N(ptr, count) __virReallocN(&(ptr), sizeof(*(ptr)), (count)) +#define VIR_FREE(ptr) __virFree(&(ptr)) + +// Copied from libvirt/src/memory.c: + +static int __virAllocN(void *ptrptr, size_t size, size_t count) +{ + *(void**)ptrptr = calloc(count, size); + if (*(void**)ptrptr == NULL) + return -1; + return 0; +} + +static int __virReallocN(void *ptrptr, size_t size, size_t count) +{ + void *tmp; + tmp = realloc(*(void**)ptrptr, size * count); + if (!tmp && (size * count)) + return -1; + *(void**)ptrptr = tmp; + return 0; +} + +static void __virFree(void *ptrptr) +{ + free(*(void**)ptrptr); + *(void**)ptrptr = NULL; +} + + +// START Copied from libvirt/qemud/events.c + +/* State for a single file handle being monitored */ +struct virEventHandle { + int fd; + int events; + virEventHandleCallback cb; + void *opaque; + int deleted; +}; + +/* State for a single timer being generated */ +struct virEventTimeout { + int timer; + int frequency; + unsigned long long expiresAt; + virEventTimeoutCallback cb; + void *opaque; + int deleted; +}; + +/* Allocate extra slots for virEventHandle/virEventTimeout + records in this multiple */ +#define EVENT_ALLOC_EXTENT 10 + +/* State for the main event loop */ +struct virEventLoop { + int handlesCount; + int handlesAlloc; + struct virEventHandle *handles; + int timeoutsCount; + int timeoutsAlloc; + struct virEventTimeout *timeouts; +}; + +/* Only have one event loop */ +static struct virEventLoop eventLoop; + +/* Unique ID for the next timer to be registered */ +static int nextTimer = 0; + +/* + * Register a callback for monitoring file handle events. + * NB, it *must* be safe to call this from within a callback + * For this reason we only ever append to existing list. + */ +int virEventAddHandleImpl(int fd, int events, virEventHandleCallback cb, + void *opaque) { + EVENT_DEBUG("Add handle %d %d %p %p", fd, events, cb, opaque); + if (eventLoop.handlesCount == eventLoop.handlesAlloc) { + EVENT_DEBUG("Used %d handle slots, adding %d more", + eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT); + if (VIR_REALLOC_N(eventLoop.handles, + (eventLoop.handlesAlloc + EVENT_ALLOC_EXTENT)) < 0) + return -1; + eventLoop.handlesAlloc += EVENT_ALLOC_EXTENT; + } + + eventLoop.handles[eventLoop.handlesCount].fd = fd; + eventLoop.handles[eventLoop.handlesCount].events = + virEventHandleTypeToPollEvent(events); + eventLoop.handles[eventLoop.handlesCount].cb = cb; + eventLoop.handles[eventLoop.handlesCount].opaque = opaque; + eventLoop.handles[eventLoop.handlesCount].deleted = 0; + + eventLoop.handlesCount++; + + return 0; +} + +void virEventUpdateHandleImpl(int fd, int events) { + int i; + for (i = 0 ; i < eventLoop.handlesCount ; i++) { + if (eventLoop.handles[i].fd == fd) { + eventLoop.handles[i].events = + virEventHandleTypeToPollEvent(events); + break; + } + } +} + +/* + * Unregister a callback from a file handle + * NB, it *must* be safe to call this from within a callback + * For this reason we only ever set a flag in the existing list. + * Actual deletion will be done out-of-band + */ +int virEventRemoveHandleImpl(int fd) { + int i; + EVENT_DEBUG("Remove handle %d", fd); + for (i = 0 ; i < eventLoop.handlesCount ; i++) { + if (eventLoop.handles[i].deleted) + continue; + + if (eventLoop.handles[i].fd == fd) { + EVENT_DEBUG("mark delete %d", i); + eventLoop.handles[i].deleted = 1; + return 0; + } + } + return -1; +} + + +/* + * Register a callback for a timer event + * NB, it *must* be safe to call this from within a callback + * For this reason we only ever append to existing list. + */ +int virEventAddTimeoutImpl(int frequency, virEventTimeoutCallback cb, void *opaque) { + struct timeval now; + EVENT_DEBUG("Adding timer %d with %d ms freq", nextTimer, frequency); + if (gettimeofday(&now, NULL) < 0) { + return -1; + } + + if (eventLoop.timeoutsCount == eventLoop.timeoutsAlloc) { + EVENT_DEBUG("Used %d timeout slots, adding %d more", + eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT); + if (VIR_REALLOC_N(eventLoop.timeouts, + (eventLoop.timeoutsAlloc + EVENT_ALLOC_EXTENT)) < 0) + return -1; + eventLoop.timeoutsAlloc += EVENT_ALLOC_EXTENT; + } + + eventLoop.timeouts[eventLoop.timeoutsCount].timer = nextTimer++; + eventLoop.timeouts[eventLoop.timeoutsCount].frequency = frequency; + eventLoop.timeouts[eventLoop.timeoutsCount].cb = cb; + eventLoop.timeouts[eventLoop.timeoutsCount].opaque = opaque; + eventLoop.timeouts[eventLoop.timeoutsCount].deleted = 0; + eventLoop.timeouts[eventLoop.timeoutsCount].expiresAt = + frequency >= 0 ? frequency + + (((unsigned long long)now.tv_sec)*1000) + + (((unsigned long long)now.tv_usec)/1000) : 0; + + eventLoop.timeoutsCount++; + + return nextTimer-1; +} + +void virEventUpdateTimeoutImpl(int timer, int frequency) { + struct timeval tv; + int i; + EVENT_DEBUG("Updating timer %d timeout with %d ms freq", timer, frequency); + if (gettimeofday(&tv, NULL) < 0) { + return; + } + + for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { + if (eventLoop.timeouts[i].timer == timer) { + eventLoop.timeouts[i].frequency = frequency; + eventLoop.timeouts[i].expiresAt = + frequency >= 0 ? frequency + + (((unsigned long long)tv.tv_sec)*1000) + + (((unsigned long long)tv.tv_usec)/1000) : 0; + break; + } + } +} + +/* + * Unregister a callback for a timer + * NB, it *must* be safe to call this from within a callback + * For this reason we only ever set a flag in the existing list. + * Actual deletion will be done out-of-band + */ +int virEventRemoveTimeoutImpl(int timer) { + int i; + EVENT_DEBUG("Remove timer %d", timer); + for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { + if (eventLoop.timeouts[i].deleted) + continue; + + if (eventLoop.timeouts[i].timer == timer) { + eventLoop.timeouts[i].deleted = 1; + return 0; + } + } + return -1; +} + +/* Iterates over all registered timeouts and determine which + * will be the first to expire. + * @timeout: filled with expiry time of soonest timer, or -1 if + * no timeout is pending + * returns: 0 on success, -1 on error + */ +static int virEventCalculateTimeout(int *timeout) { + unsigned long long then = 0; + int i; + EVENT_DEBUG("Calculate expiry of %d timers", eventLoop.timeoutsCount); + /* Figure out if we need a timeout */ + for (i = 0 ; i < eventLoop.timeoutsCount ; i++) { + if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequency < 0) + continue; + + EVENT_DEBUG("Got a timeout scheduled for %llu", eventLoop.timeouts[i].expiresAt); + if (then == 0 || + eventLoop.timeouts[i].expiresAt < then) + then = eventLoop.timeouts[i].expiresAt; + } + + /* Calculate how long we should wait for a timeout if needed */ + if (then > 0) { + struct timeval tv; + + if (gettimeofday(&tv, NULL) < 0) { + return -1; + } + + *timeout = then - + ((((unsigned long long)tv.tv_sec)*1000) + + (((unsigned long long)tv.tv_usec)/1000)); + + if (*timeout < 0) + *timeout = 0; + } else { + *timeout = -1; + } + + EVENT_DEBUG("Timeout at %llu due in %d ms", then, *timeout); + + return 0; +} + +/* + * Allocate a pollfd array containing data for all registered + * file handles. The caller must free the returned data struct + * returns: the pollfd array, or NULL on error + */ +static int virEventMakePollFDs(struct pollfd **retfds) { + struct pollfd *fds; + int i, nfds = 0; + + for (i = 0 ; i < eventLoop.handlesCount ; i++) { + if (eventLoop.handles[i].deleted) + continue; + nfds++; + } + *retfds = NULL; + /* Setup the poll file handle data structs */ + if (VIR_ALLOC_N(fds, nfds) < 0) + return -1; + + for (i = 0, nfds = 0 ; i < eventLoop.handlesCount ; i++) { + if (eventLoop.handles[i].deleted) + continue; + fds[nfds].fd = eventLoop.handles[i].fd; + fds[nfds].events = eventLoop.handles[i].events; + fds[nfds].revents = 0; + //EVENT_DEBUG("Wait for %d %d", eventLoop.handles[i].fd, eventLoop.handles[i].events); + nfds++; + } + + *retfds = fds; + return nfds; +} + + +/* + * Iterate over all timers and determine if any have expired. + * Invoke the user supplied callback for each timer whose + * expiry time is met, and schedule the next timeout. Does + * not try to 'catch up' on time if the actual expiry time + * was later than the requested time. + * + * This method must cope with new timers being registered + * by a callback, and must skip any timers marked as deleted. + * + * Returns 0 upon success, -1 if an error occurred + */ +static int virEventDispatchTimeouts(void) { + struct timeval tv; + unsigned long long now; + int i; + /* Save this now - it may be changed during dispatch */ + int ntimeouts = eventLoop.timeoutsCount; + + if (gettimeofday(&tv, NULL) < 0) { + return -1; + } + now = (((unsigned long long)tv.tv_sec)*1000) + + (((unsigned long long)tv.tv_usec)/1000); + + for (i = 0 ; i < ntimeouts ; i++) { + if (eventLoop.timeouts[i].deleted || eventLoop.timeouts[i].frequency < 0) + continue; + + if (eventLoop.timeouts[i].expiresAt <= now) { + (eventLoop.timeouts[i].cb)(eventLoop.timeouts[i].timer, + eventLoop.timeouts[i].opaque); + eventLoop.timeouts[i].expiresAt = + now + eventLoop.timeouts[i].frequency; + } + } + return 0; +} + + +/* Iterate over all file handles and dispatch any which + * have pending events listed in the poll() data. Invoke + * the user supplied callback for each handle which has + * pending events + * + * This method must cope with new handles being registered + * by a callback, and must skip any handles marked as deleted. + * + * Returns 0 upon success, -1 if an error occurred + */ +static int virEventDispatchHandles(struct pollfd *fds) { + int i; + virEventHandleType hEvents; + /* Save this now - it may be changed during dispatch */ + int nhandles = eventLoop.handlesCount; + + for (i = 0 ; i < nhandles ; i++) { + if (eventLoop.handles[i].deleted) { + EVENT_DEBUG("Skip deleted %d", eventLoop.handles[i].fd); + continue; + } + + if (fds[i].revents) { + hEvents = virPollEventToEventHandleType(fds[i].revents); + EVENT_DEBUG("Dispatch %d %d %p", fds[i].fd, fds[i].revents, + eventLoop.handles[i].opaque); + (eventLoop.handles[i].cb)(fds[i].fd, hEvents, + eventLoop.handles[i].opaque); + } + } + + return 0; +} + + +/* Used post dispatch to actually remove any timers that + * were previously marked as deleted. This asynchronous + * cleanup is needed to make dispatch re-entrant safe. + */ +static int virEventCleanupTimeouts(void) { + int i; + + /* Remove deleted entries, shuffling down remaining + * entries as needed to form contiguous series + */ + for (i = 0 ; i < eventLoop.timeoutsCount ; ) { + if (!eventLoop.timeouts[i].deleted) { + i++; + continue; + } + + EVENT_DEBUG("Purging timeout %d with id %d", i, eventLoop.timeouts[i].timer); + if ((i+1) < eventLoop.timeoutsCount) { + memmove(eventLoop.timeouts+i, + eventLoop.timeouts+i+1, + sizeof(struct virEventTimeout)*(eventLoop.timeoutsCount-(i+1))); + } + eventLoop.timeoutsCount--; + } + + /* Release some memory if we've got a big chunk free */ + if ((eventLoop.timeoutsAlloc - EVENT_ALLOC_EXTENT) > eventLoop.timeoutsCount) { + EVENT_DEBUG("Releasing %d out of %d timeout slots used, releasing %d", + eventLoop.timeoutsCount, eventLoop.timeoutsAlloc, EVENT_ALLOC_EXTENT); + if (VIR_REALLOC_N(eventLoop.timeouts, + (eventLoop.timeoutsAlloc - EVENT_ALLOC_EXTENT)) < 0) + return -1; + eventLoop.timeoutsAlloc -= EVENT_ALLOC_EXTENT; + } + return 0; +} + +/* Used post dispatch to actually remove any handles that + * were previously marked as deleted. This asynchronous + * cleanup is needed to make dispatch re-entrant safe. + */ +static int virEventCleanupHandles(void) { + int i; + + /* Remove deleted entries, shuffling down remaining + * entries as needed to form contiguous series + */ + for (i = 0 ; i < eventLoop.handlesCount ; ) { + if (!eventLoop.handles[i].deleted) { + i++; + continue; + } + + if ((i+1) < eventLoop.handlesCount) { + memmove(eventLoop.handles+i, + eventLoop.handles+i+1, + sizeof(struct virEventHandle)*(eventLoop.handlesCount-(i+1))); + } + eventLoop.handlesCount--; + } + + /* Release some memory if we've got a big chunk free */ + if ((eventLoop.handlesAlloc - EVENT_ALLOC_EXTENT) > eventLoop.handlesCount) { + EVENT_DEBUG("Releasing %d out of %d handles slots used, releasing %d", + eventLoop.handlesCount, eventLoop.handlesAlloc, EVENT_ALLOC_EXTENT); + if (VIR_REALLOC_N(eventLoop.handles, + (eventLoop.handlesAlloc - EVENT_ALLOC_EXTENT)) < 0) + return -1; + eventLoop.handlesAlloc -= EVENT_ALLOC_EXTENT; + } + return 0; +} + +/* + * Run a single iteration of the event loop, blocking until + * at least one file handle has an event, or a timer expires + */ +int virEventRunOnce(void) { + struct pollfd *fds; + int ret, timeout, nfds; + + if ((nfds = virEventMakePollFDs(&fds)) < 0) + return -1; + + if (virEventCalculateTimeout(&timeout) < 0) { + VIR_FREE(fds); + return -1; + } + + retry: + EVENT_DEBUG("Poll on %d handles %p timeout %d", nfds, fds, timeout); + ret = poll(fds, nfds, timeout); + EVENT_DEBUG("Poll got %d event", ret); + if (ret < 0) { + if (errno == EINTR) { + goto retry; + } + VIR_FREE(fds); + return -1; + } + if (virEventDispatchTimeouts() < 0) { + VIR_FREE(fds); + return -1; + } + + if (ret > 0 && + virEventDispatchHandles(fds) < 0) { + VIR_FREE(fds); + return -1; + } + VIR_FREE(fds); + + if (virEventCleanupTimeouts() < 0) + return -1; + + if (virEventCleanupHandles() < 0) + return -1; + + return 0; +} + +int +virEventHandleTypeToPollEvent(int 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; +} + +int +virPollEventToEventHandleType(int events) +{ + int 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; +} + +// END Copied from libvirt/qemud/events.c + +/* Because the Java EventImpl runs in its own thread, it can run when + * there are no handles or timeouts registered, in which case + * virEventRunOnce() will wait forever. We'll handle this case + * by maintaining an internal pipe, whose read fd is registered + * with the wakeupFromPoll callback. Whenever any change is made to + * registered handles or timeouts, we'll write to this pipe to + * make sure virEventRunOnce() wakes from its poll() and notices + * the change. + */ +static int eventImpl_readfd; +static int eventImpl_writefd; + +static void wakeupFromPoll(int fd, int events, void *opaque) +{ + char dummy; + EVENT_DEBUG("reading fd %d (should be %d)", fd, eventImpl_readfd); + read(fd, &dummy, 1); +} + +static void wake() +{ + EVENT_DEBUG("writing fd %d", eventImpl_writefd); + write(eventImpl_writefd, "X", 1); +} + +static int addHandleImpl(int fd, int events, virEventHandleCallback cb, + void *opaque) { + int rv = virEventAddHandleImpl(fd, events, cb, opaque); + wake(); + return rv; +} + +void updateHandleImpl(int fd, int events) { + virEventUpdateHandleImpl(fd, events); + wake(); +} + +int removeHandleImpl(int fd) { + int rv = virEventRemoveHandleImpl(fd); + wake(); + return rv; +} + +int addTimeoutImpl(int frequency, virEventTimeoutCallback cb, void *opaque) { + int rv = virEventAddTimeoutImpl(frequency, cb, opaque); + wake(); + return rv; +} + +void updateTimeoutImpl(int timer, int frequency) { + virEventUpdateTimeoutImpl(timer, frequency); + wake(); +} + +int removeTimeoutImpl(int timer) { + int rv = virEventRemoveTimeoutImpl(timer); + wake(); + return rv; +} + + +JNIEXPORT jint JNICALL Java_org_libvirt_EventImpl_init(JNIEnv *env, jobject obj) +{ + int pipefds[2]; + int sts; + + sts = pipe(pipefds); + if (sts != 0) + return sts; + eventImpl_readfd = pipefds[0]; + eventImpl_writefd = pipefds[1]; + sts = virEventAddHandleImpl(eventImpl_readfd, VIR_EVENT_HANDLE_READABLE, + wakeupFromPoll, NULL); + if (sts != 0) + return sts; + + virEventRegisterImpl(addHandleImpl, updateHandleImpl, removeHandleImpl, + addTimeoutImpl, updateTimeoutImpl, removeTimeoutImpl); + + return 0; +} + +JNIEXPORT jint JNICALL Java_org_libvirt_EventImpl_run_1once(JNIEnv *env, jobject obj) +{ + return virEventRunOnce(); +} diff --git a/src/org/libvirt/Connect.java b/src/org/libvirt/Connect.java index 4271937..6ce9034 100644 --- a/src/org/libvirt/Connect.java +++ b/src/org/libvirt/Connect.java @@ -4,6 +4,9 @@ import org.libvirt.LibvirtException; import org.libvirt.StoragePool; import org.libvirt.StorageVol; +import java.util.HashSet; +import java.util.Iterator; + /** * The Connect object represents a connection to a local or remote hypervisor/driver. * @@ -16,14 +19,15 @@ public class Connect { static { System.loadLibrary("virt_jni"); _virInitialize(); + EventImpl.getInstance().start(); } - /** * the native virConnectPtr. */ long VCP; - + HashSet<DomainEventListener> domainEventListeners = new HashSet<DomainEventListener>(); + private static native int _virInitialize(); /** @@ -87,7 +91,7 @@ public class Connect { * * @throws LibvirtException */ - public void close() throws LibvirtException { + public synchronized void close() throws LibvirtException { _close(VCP); // If leave an invalid pointer dangling around JVM crashes and burns if // someone tries to call a method on us @@ -106,7 +110,7 @@ public class Connect { * @see <a href="http://libvirt.org/format.html#Capa1" >The XML format description</a> * */ - public String getCapabilities() throws LibvirtException { + public synchronized String getCapabilities() throws LibvirtException { return _getCapabilities(VCP); } @@ -121,7 +125,7 @@ public class Connect { * @return the hostname * @throws LibvirtException */ - public String getHostName() throws LibvirtException { + public synchronized String getHostName() throws LibvirtException { return _getHostName(VCP); } @@ -136,7 +140,7 @@ public class Connect { * @return the number of CPUs * @throws LibvirtException */ - public int getMaxVcpus(String type) throws LibvirtException { + public synchronized int getMaxVcpus(String type) throws LibvirtException { return _getMaxVcpus(VCP, type); } @@ -150,7 +154,7 @@ public class Connect { * @return the name * @throws LibvirtException */ - public String getType() throws LibvirtException { + public synchronized String getType() throws LibvirtException { return _getType(VCP); } @@ -165,7 +169,7 @@ public class Connect { * @return the URI * @throws LibvirtException */ - public String getURI() throws LibvirtException { + public synchronized String getURI() throws LibvirtException { return _getURI(VCP); } @@ -180,7 +184,7 @@ public class Connect { * @return major * 1,000,000 + minor * 1,000 + release * @throws LibvirtException */ - public long getVersion() throws LibvirtException { + public synchronized long getVersion() throws LibvirtException { return _getVersion(VCP); } @@ -193,7 +197,7 @@ public class Connect { // * @return major * 1,000,000 + minor * 1,000 + release * @throws LibvirtException */ - public long getLibVirVersion() throws LibvirtException { + public synchronized long getLibVirVersion() throws LibvirtException { return _virGetLibVirVersion(); } @@ -208,7 +212,7 @@ public class Connect { * @return major * 1,000,000 + minor * 1,000 + release * @throws LibvirtException */ - public long GetHypervisorVersion(String type) throws LibvirtException { + public synchronized long GetHypervisorVersion(String type) throws LibvirtException { return _virGetHypervisorVersion(type); } @@ -222,7 +226,7 @@ public class Connect { * @return an Array of Strings that contains the names of the defined domains currently inactive * @throws LibvirtException */ - public String[] listDefinedDomains() throws LibvirtException { + public synchronized String[] listDefinedDomains() throws LibvirtException { return _listDefinedDomains(VCP); } @@ -236,7 +240,7 @@ public class Connect { * @return an Array of Strings that contains the names of the inactive networks * @throws LibvirtException */ - public String[] listDefinedNetworks() throws LibvirtException { + public synchronized String[] listDefinedNetworks() throws LibvirtException { return _listDefinedNetworks(VCP); } @@ -250,7 +254,7 @@ public class Connect { * @return and array of the IDs of the active domains * @throws LibvirtException */ - public int[] listDomains() throws LibvirtException { + public synchronized int[] listDomains() throws LibvirtException { return _listDomains(VCP); } @@ -262,7 +266,7 @@ public class Connect { * @return an Array of Strings that contains the names of the active networks * @throws LibvirtException */ - public String[] listNetworks() throws LibvirtException { + public synchronized String[] listNetworks() throws LibvirtException { return _listNetworks(VCP); } @@ -275,7 +279,7 @@ public class Connect { * @return the number of inactive domains * @throws LibvirtException */ - public int numOfDefinedDomains() throws LibvirtException { + public synchronized int numOfDefinedDomains() throws LibvirtException { return _numOfDefinedDomains(VCP); } @@ -288,7 +292,7 @@ public class Connect { * @return the number of inactive networks * @throws LibvirtException */ - public int numOfDefinedNetworks() throws LibvirtException { + public synchronized int numOfDefinedNetworks() throws LibvirtException { return _numOfDefinedNetworks(VCP); } @@ -300,7 +304,7 @@ public class Connect { * @return the number of active domains * @throws LibvirtException */ - public int numOfDomains() throws LibvirtException { + public synchronized int numOfDomains() throws LibvirtException { return _numOfDomains(VCP); } @@ -313,7 +317,7 @@ public class Connect { * @return the number of active networks * @throws LibvirtException */ - public int numOfNetworks() throws LibvirtException { + public synchronized int numOfNetworks() throws LibvirtException { return _numOfNetworks(VCP); } @@ -337,7 +341,7 @@ public class Connect { * @return The Network object found * @throws LibvirtException */ - public Network networkLookupByName(String name) + public synchronized Network networkLookupByName(String name) throws LibvirtException { return new Network(this, _virNetworkLookupByName(VCP, name)); } @@ -354,7 +358,7 @@ public class Connect { * @return The Network object found * @throws LibvirtException */ - public Network networkLookupByUUID(int[] UUID) + public synchronized Network networkLookupByUUID(int[] UUID) throws LibvirtException { return new Network(this, _virNetworkLookupByUUID(VCP, UUID)); } @@ -368,7 +372,7 @@ public class Connect { * @return The Network object found * @throws LibvirtException */ - public Network networkLookupByUUIDString(String UUID) + public synchronized Network networkLookupByUUIDString(String UUID) throws LibvirtException { return new Network(this, _virNetworkLookupByUUIDString(VCP, UUID)); } @@ -386,7 +390,7 @@ public class Connect { * @throws LibvirtException * @see <a href="http://libvirt.org/format.html#Net1" >The XML format description</a> */ - public Network networkCreateXML(String xmlDesc) + public synchronized Network networkCreateXML(String xmlDesc) throws LibvirtException { return new Network(this, _virNetworkCreateXML(VCP, xmlDesc)); } @@ -404,7 +408,7 @@ public class Connect { * @throws LibvirtException * @see <a href="http://libvirt.org/format.html#Net1" >The XML format description</a> */ - public Network networkDefineXML(String xmlDesc) + public synchronized Network networkDefineXML(String xmlDesc) throws LibvirtException { return new Network(this, _virNetworkDefineXML(VCP, xmlDesc)); } @@ -419,7 +423,7 @@ public class Connect { * @return the Domain object * @throws LibvirtException */ - public Domain domainLookupByID(int id) throws LibvirtException { + public synchronized Domain domainLookupByID(int id) throws LibvirtException { return new Domain(this, _virDomainLookupByID(VCP, id)); } @@ -433,7 +437,7 @@ public class Connect { * @return the Domain object * @throws LibvirtException */ - public Domain domainLookupByName(String name) throws LibvirtException { + public synchronized Domain domainLookupByName(String name) throws LibvirtException { return new Domain(this, _virDomainLookupByName(VCP, name)); } @@ -449,7 +453,7 @@ public class Connect { * @return the Domain object * @throws LibvirtException */ - public Domain domainLookupByUUID(int[] UUID) throws LibvirtException { + public synchronized Domain domainLookupByUUID(int[] UUID) throws LibvirtException { return new Domain(this, _virDomainLookupByUUID(VCP, UUID)); } @@ -463,7 +467,7 @@ public class Connect { * @return the Domain object * @throws LibvirtException */ - public Domain domainLookupByUUIDString(String UUID) + public synchronized Domain domainLookupByUUIDString(String UUID) throws LibvirtException { return new Domain(this, _virDomainLookupByUUIDString(VCP, UUID)); } @@ -482,7 +486,7 @@ public class Connect { * @throws LibvirtException * @see <a href="http://libvirt.org/format.html#Normal1" > The XML format description </a> */ - public Domain domainCreateLinux(String xmlDesc, int flags) + public synchronized Domain domainCreateLinux(String xmlDesc, int flags) throws LibvirtException { return new Domain(this, _virDomainCreateLinux(VCP, xmlDesc, flags)); } @@ -498,7 +502,7 @@ public class Connect { * @throws LibvirtException * @see <a href="http://libvirt.org/format.html#Normal1" > The XML format description </a> */ - public Domain domainDefineXML(String xmlDesc) throws LibvirtException { + public synchronized Domain domainDefineXML(String xmlDesc) throws LibvirtException { return new Domain(this, _virDomainDefineXML(VCP, xmlDesc)); } @@ -512,7 +516,7 @@ public class Connect { * @param from the path of the saved file on the remote host * @throws LibvirtException */ - public void restore(String from) throws LibvirtException { + public synchronized void restore(String from) throws LibvirtException { _virDomainRestore(VCP, from); } @@ -525,7 +529,7 @@ public class Connect { * @return a NodeInfo object * @throws LibvirtException */ - public NodeInfo nodeInfo() throws LibvirtException { + public synchronized NodeInfo nodeInfo() throws LibvirtException { return _virNodeInfo(VCP); } @@ -539,7 +543,7 @@ public class Connect { * @param memory in kilobytes * @throws LibvirtException */ - public void setDom0Memory(long memory) throws LibvirtException { + public synchronized void setDom0Memory(long memory) throws LibvirtException { _setDom0Memory(memory); } @@ -551,7 +555,7 @@ public class Connect { * @return the number of pools found * @throws LibvirtException */ - public int numOfDefinedStoragePools() throws LibvirtException { + public synchronized int numOfDefinedStoragePools() throws LibvirtException { return _numOfDefinedStoragePools(VCP); } @@ -563,7 +567,7 @@ public class Connect { * @return the number of pools found * @throws LibvirtException */ - public int numOfStoragePools() throws LibvirtException { + public synchronized int numOfStoragePools() throws LibvirtException { return _numOfStoragePools(VCP); } @@ -575,7 +579,7 @@ public class Connect { * @return an Array of Strings that contains the names of the defined storage pools * @throws LibvirtException */ - public String[] listDefinedStoragePools() throws LibvirtException { + public synchronized String[] listDefinedStoragePools() throws LibvirtException { return _listDefinedStoragePools(VCP); } @@ -588,7 +592,7 @@ public class Connect { * @return an Array of Strings that contains the names of the defined storage pools * @throws LibvirtException */ - public String[] listStoragePools() throws LibvirtException { + public synchronized String[] listStoragePools() throws LibvirtException { return _listStoragePools(VCP); } @@ -604,7 +608,7 @@ public class Connect { * @return StoragePool object * @throws LibvirtException */ - public StoragePool storagePoolCreateXML(String xmlDesc, int flags) + public synchronized StoragePool storagePoolCreateXML(String xmlDesc, int flags) throws LibvirtException { return new StoragePool(this, _virStoragePoolCreateXML(VCP, xmlDesc, flags)); } @@ -621,7 +625,7 @@ public class Connect { * @return StoragePool object * @throws LibvirtException */ - public StoragePool storagePoolDefineXML(String xml, int flags) + public synchronized StoragePool storagePoolDefineXML(String xml, int flags) throws LibvirtException { return new StoragePool(this, _virStoragePoolDefineXML(VCP, xml, flags)); } @@ -636,7 +640,7 @@ public class Connect { * @return StoragePool object * @throws LibvirtException */ - public StoragePool storagePoolLookupByName(String name) + public synchronized StoragePool storagePoolLookupByName(String name) throws LibvirtException { return new StoragePool(this, _virStoragePoolLookupByName(VCP, name)); } @@ -651,7 +655,7 @@ public class Connect { * @return a new network object * @throws LibvirtException */ - public StoragePool storagePoolLookupByUUID(int[] UUID) + public synchronized StoragePool storagePoolLookupByUUID(int[] UUID) throws LibvirtException { return new StoragePool(this, _virStoragePoolLookupByUUID(VCP, UUID)); } @@ -665,7 +669,7 @@ public class Connect { * @return VirStoragePool object * @throws LibvirtException */ - public StoragePool storagePoolLookupByUUIDString(String UUID) + public synchronized StoragePool storagePoolLookupByUUIDString(String UUID) throws LibvirtException { return new StoragePool(this, _virStoragePoolLookupByUUIDString(VCP, UUID)); } @@ -679,7 +683,7 @@ public class Connect { * @param key globally unique key * @return a storage volume */ - public StorageVol storageVolLookupByKey(String key){ + public synchronized StorageVol storageVolLookupByKey(String key){ return new StorageVol(this, _virStorageVolLookupByKey(VCP, key)); } @@ -691,11 +695,47 @@ public class Connect { * @param path locally unique path * @return a storage volume */ - public StorageVol storageVolLookupByPath(String path){ + public synchronized StorageVol storageVolLookupByPath(String path){ return new StorageVol(this, _virStorageVolLookupByPath(VCP, path)); } private native long _virStorageVolLookupByPath(long VCP, String path); + /** + * Registers a new DomainEventListener. + * + * @param listener the new listener + */ + public synchronized void domainEventRegister(DomainEventListener listener) throws LibvirtException { + if (domainEventListeners.isEmpty()) { + registerForDomainEvents(VCP); + } + domainEventListeners.add(listener); + } + + /** + * Deregisters a previously-registered DomainEventListener. + * + * @param listener the listener to be deregistered + */ + public synchronized void domainEventDeregister(DomainEventListener listener) throws LibvirtException { + domainEventListeners.remove(listener); + if (domainEventListeners.isEmpty()) { + deregisterForDomainEvents(VCP); + } + } + + + // Invoked from JNI code by libvirt callback + private synchronized void fireDomainEventCallbacks(Domain dom, int event) { + Iterator<DomainEventListener> iter = domainEventListeners.iterator(); + while (iter.hasNext()) { + DomainEventListener listener = iter.next(); + listener.handle(dom, DomainEvent.Type.values()[event]); + } + } + + private native void registerForDomainEvents(long VCP) throws LibvirtException; + private native void deregisterForDomainEvents(long VCP) throws LibvirtException; } diff --git a/src/org/libvirt/Domain.java b/src/org/libvirt/Domain.java index 8e7fa74..5ab0b3c 100644 --- a/src/org/libvirt/Domain.java +++ b/src/org/libvirt/Domain.java @@ -57,7 +57,9 @@ public class Domain { * @see <a href="http://libvirt.org/format.html#Normal1" >The XML Description format </a> */ public String getXMLDesc(int flags) throws LibvirtException{ - return _getXMLDesc(VDP, flags); + synchronized (this.virConnect) { + return _getXMLDesc(VDP, flags); + } } private native String _getXMLDesc(long VDP, int flags) throws LibvirtException; @@ -69,7 +71,9 @@ public class Domain { * @throws LibvirtException */ public boolean getAutostart() throws LibvirtException{ - return _getAutostart(VDP); + synchronized (this.virConnect) { + return _getAutostart(VDP); + } } @@ -82,7 +86,9 @@ public class Domain { * @throws LibvirtException */ public void setAutostart(boolean autostart) throws LibvirtException{ + synchronized (this.virConnect) { _setAutostart(VDP, autostart); + } } private native int _setAutostart(long VDP, boolean autostart) throws LibvirtException; @@ -103,7 +109,9 @@ public class Domain { * @throws LibvirtException */ public int getID() throws LibvirtException{ - return _getID(VDP); + synchronized (this.virConnect) { + return _getID(VDP); + } } private native int _getID(long VDP) throws LibvirtException; @@ -117,7 +125,9 @@ public class Domain { * @throws LibvirtException */ public DomainInfo getInfo() throws LibvirtException{ - return _getInfo(VDP); + synchronized (this.virConnect) { + return _getInfo(VDP); + } } private native DomainInfo _getInfo(long VDP) throws LibvirtException; @@ -129,7 +139,9 @@ public class Domain { * @throws LibvirtException */ public long getMaxMemory() throws LibvirtException{ - return _getMaxMemory(VDP); + synchronized (this.virConnect) { + return _getMaxMemory(VDP); + } } private native long _getMaxMemory(long VDP) throws LibvirtException; @@ -142,7 +154,9 @@ public class Domain { * @throws LibvirtException */ public void setMaxMemory(long memory) throws LibvirtException{ - _setMaxMemory(VDP, memory); + synchronized (this.virConnect) { + _setMaxMemory(VDP, memory); + } } private native long _setMaxMemory(long VDP, long memory) throws LibvirtException; @@ -157,7 +171,9 @@ public class Domain { * @throws LibvirtException */ public int getMaxVcpus() throws LibvirtException{ - return _getMaxVcpus(VDP); + synchronized (this.virConnect) { + return _getMaxVcpus(VDP); + } } private native int _getMaxVcpus(long VDP) throws LibvirtException; @@ -170,7 +186,9 @@ public class Domain { * @throws LibvirtException */ public String getName() throws LibvirtException{ - return _getName(VDP); + synchronized (this.virConnect) { + return _getName(VDP); + } } private native String _getName(long VDP) throws LibvirtException; @@ -182,7 +200,9 @@ public class Domain { * @throws LibvirtException */ public String getOSType() throws LibvirtException{ - return _getOSType(VDP); + synchronized (this.virConnect) { + return _getOSType(VDP); + } } private native String _getOSType(long VDP) throws LibvirtException; @@ -195,7 +215,9 @@ public class Domain { * @throws LibvirtException */ public SchedParameter[] getSchedulerParameters() throws LibvirtException{ - return _getSchedulerParameters(VDP); + synchronized (this.virConnect) { + return _getSchedulerParameters(VDP); + } } private native SchedParameter[] _getSchedulerParameters (long VDP) throws LibvirtException; @@ -207,7 +229,9 @@ public class Domain { * @throws LibvirtException */ public void setSchedulerParameters(SchedParameter[] params) throws LibvirtException{ - _setSchedulerParameters(VDP, params); + synchronized (this.virConnect) { + _setSchedulerParameters(VDP, params); + } } private native int _setSchedulerParameters(long VDP, SchedParameter[] params) throws LibvirtException; @@ -222,7 +246,9 @@ public class Domain { * @throws LibvirtException */ public String[] getSchedulerType() throws LibvirtException{ - return _getSchedulerType(VDP); + synchronized (this.virConnect) { + return _getSchedulerType(VDP); + } } private native String[] _getSchedulerType(long VDP) throws LibvirtException; @@ -235,7 +261,9 @@ public class Domain { * @see <a href="http://www.ietf.org/rfc/rfc4122.txt">rfc4122</a> */ public int[] getUUID() throws LibvirtException{ - return _getUUID(VDP); + synchronized (this.virConnect) { + return _getUUID(VDP); + } } private native int[] _getUUID(long VDP) throws LibvirtException; @@ -248,7 +276,9 @@ public class Domain { * @see <a href="http://www.ietf.org/rfc/rfc4122.txt">rfc4122</a> */ public String getUUIDString() throws LibvirtException{ - return _getUUIDString(VDP); + synchronized (this.virConnect) { + return _getUUIDString(VDP); + } } private native String _getUUIDString(long VDP) throws LibvirtException; @@ -260,7 +290,9 @@ public class Domain { * @throws LibvirtException */ public VcpuInfo[] getVcpusInfo() throws LibvirtException{ - return _getVcpusInfo(VDP); + synchronized (this.virConnect) { + return _getVcpusInfo(VDP); + } } private native VcpuInfo[] _getVcpusInfo(long VDP) throws LibvirtException; @@ -273,7 +305,9 @@ public class Domain { * @throws LibvirtException */ public int[] getVcpusCpuMaps() throws LibvirtException{ - return _getVcpusCpuMaps(VDP); + synchronized (this.virConnect) { + return _getVcpusCpuMaps(VDP); + } } private native int[] _getVcpusCpuMaps(long VDP) throws LibvirtException; @@ -288,7 +322,9 @@ public class Domain { * @throws LibvirtException */ public void pinVcpu(int vcpu, int[] cpumap) throws LibvirtException{ - _pinVcpu(VDP, vcpu, cpumap); + synchronized (this.virConnect) { + _pinVcpu(VDP, vcpu, cpumap); + } } private native int _pinVcpu(long VDP, int vcpu, int[]cpumap) throws LibvirtException; @@ -302,7 +338,9 @@ public class Domain { * @throws LibvirtException */ public void setVcpus(int nvcpus) throws LibvirtException{ - _setVcpus(VDP, nvcpus); + synchronized (this.virConnect) { + _setVcpus(VDP, nvcpus); + } } private native int _setVcpus(long VDP, int nvcpus) throws LibvirtException; @@ -314,7 +352,9 @@ public class Domain { * @throws LibvirtException */ public void attachDevice(String xmlDesc) throws LibvirtException{ - _attachDevice(VDP, xmlDesc); + synchronized (this.virConnect) { + _attachDevice(VDP, xmlDesc); + } } private native int _attachDevice(long VDP, String xmlDesc) throws LibvirtException; @@ -326,7 +366,9 @@ public class Domain { * @throws LibvirtException */ public void detachDevice(String xmlDesc) throws LibvirtException{ - _detachDevice(VDP, xmlDesc); + synchronized (this.virConnect) { + _detachDevice(VDP, xmlDesc); + } } private native int _detachDevice(long VDP, String xmlDesc) throws LibvirtException; @@ -345,7 +387,9 @@ public class Domain { * @throws LibvirtException */ public DomainBlockStats blockStats(String path) throws LibvirtException{ - return _blockStats(VDP, path); + synchronized (this.virConnect) { + return _blockStats(VDP, path); + } } private native DomainBlockStats _blockStats(long VDP, String path) throws LibvirtException; @@ -362,7 +406,9 @@ public class Domain { * @throws LibvirtException */ public DomainInterfaceStats interfaceStats(String path) throws LibvirtException{ - return _interfaceStats(VDP, path); + synchronized (this.virConnect) { + return _interfaceStats(VDP, path); + } } private native DomainInterfaceStats _interfaceStats(long VDP, String path) throws LibvirtException; @@ -376,7 +422,9 @@ public class Domain { * @throws LibvirtException */ public void coreDump(String to, int flags) throws LibvirtException{ - _coreDump(VDP, to, flags); + synchronized (this.virConnect) { + _coreDump(VDP, to, flags); + } } private native int _coreDump(long VDP, String to, int flags) throws LibvirtException; @@ -388,7 +436,9 @@ public class Domain { * @throws LibvirtException */ public void create() throws LibvirtException{ - _create(VDP); + synchronized (this.virConnect) { + _create(VDP); + } } private native int _create(long VDP) throws LibvirtException; @@ -402,7 +452,9 @@ public class Domain { * @throws LibvirtException */ public void destroy() throws LibvirtException{ - _destroy(VDP); + synchronized (this.virConnect) { + _destroy(VDP); + } } private native int _destroy(long VDP) throws LibvirtException; @@ -415,8 +467,10 @@ public class Domain { * @throws LibvirtException */ public void free() throws LibvirtException{ - _free(VDP); - VDP=0; + synchronized (this.virConnect) { + _free(VDP); + VDP=0; + } } private native int _free(long VDP) throws LibvirtException; @@ -449,7 +503,9 @@ public class Domain { * @throws LibvirtException */ public Domain migrate(Connect dconn, long flags, String dname, String uri, long bandwidth) throws LibvirtException{ - return new Domain(dconn, _migrate(VDP, dconn, flags, dname, uri, bandwidth)); + synchronized (this.virConnect) { + return new Domain(dconn, _migrate(VDP, dconn, flags, dname, uri, bandwidth)); + } } private native long _migrate(long VDP, Connect dconn, long flags, String dname, String uri, long bandwidth) throws LibvirtException; @@ -462,7 +518,9 @@ public class Domain { * @throws LibvirtException */ public void reboot(int flags) throws LibvirtException{ - _reboot(VDP, flags); + synchronized (this.virConnect) { + _reboot(VDP, flags); + } } private native int _reboot(long VDP, int flags) throws LibvirtException; @@ -474,7 +532,9 @@ public class Domain { * @throws LibvirtException */ public void suspend() throws LibvirtException{ - _suspend(VDP); + synchronized (this.virConnect) { + _suspend(VDP); + } } private native int _suspend(long VDP) throws LibvirtException; @@ -486,7 +546,9 @@ public class Domain { * @throws LibvirtException */ public void resume() throws LibvirtException{ - _resume(VDP); + synchronized (this.virConnect) { + _resume(VDP); + } } private native int _resume(long VDP) throws LibvirtException; @@ -500,7 +562,9 @@ public class Domain { * @throws LibvirtException */ public void save(String to) throws LibvirtException{ - _save(VDP, to); + synchronized (this.virConnect) { + _save(VDP, to); + } } private native int _save(long VDP, String to) throws LibvirtException; @@ -513,7 +577,9 @@ public class Domain { * @throws LibvirtException */ public void shutdown() throws LibvirtException{ - _shutdown(VDP); + synchronized (this.virConnect) { + _shutdown(VDP); + } } private native int _shutdown(long VDP) throws LibvirtException; @@ -524,7 +590,9 @@ public class Domain { * @throws LibvirtException */ public void undefine() throws LibvirtException{ - _undefine(VDP); + synchronized (this.virConnect) { + _undefine(VDP); + } } private native int _undefine(long VDP) throws LibvirtException; @@ -537,7 +605,9 @@ public class Domain { * @throws LibvirtException */ public void setMemory(long memory) throws LibvirtException{ - _setMemory(VDP, memory); + synchronized (this.virConnect) { + _setMemory(VDP, memory); + } } private native int _setMemory(long VDP, long memory) throws LibvirtException; diff --git a/src/org/libvirt/DomainEvent.java b/src/org/libvirt/DomainEvent.java new file mode 100644 index 0000000..b3f2985 --- /dev/null +++ b/src/org/libvirt/DomainEvent.java @@ -0,0 +1,17 @@ +package org.libvirt; + +public class DomainEvent { + + public enum Type { + VIR_DOMAIN_EVENT_ADDED, + VIR_DOMAIN_EVENT_REMOVED, + VIR_DOMAIN_EVENT_STARTED, + VIR_DOMAIN_EVENT_SUSPENDED, + VIR_DOMAIN_EVENT_RESUMED, + VIR_DOMAIN_EVENT_STOPPED, + VIR_DOMAIN_EVENT_SAVED, + VIR_DOMAIN_EVENT_RESTORED; + }; + +} + diff --git a/src/org/libvirt/DomainEventListener.java b/src/org/libvirt/DomainEventListener.java new file mode 100644 index 0000000..dc2c833 --- /dev/null +++ b/src/org/libvirt/DomainEventListener.java @@ -0,0 +1,7 @@ +package org.libvirt; + +public interface DomainEventListener extends java.util.EventListener { + + public void handle(Domain dom, DomainEvent.Type event); + +} diff --git a/src/org/libvirt/EventImpl.java b/src/org/libvirt/EventImpl.java new file mode 100644 index 0000000..5535ff6 --- /dev/null +++ b/src/org/libvirt/EventImpl.java @@ -0,0 +1,32 @@ +package org.libvirt; + +import java.util.HashMap; + +// Singleton class wrapping libvirt EventImpl with a Java Thread + +class EventImpl extends Thread { + + static EventImpl theEventImpl; + + private native int init(); + + private EventImpl() { + init(); + setDaemon(true); + } + + public static EventImpl getInstance() { + if (theEventImpl == null) + theEventImpl = new EventImpl(); + return theEventImpl; + } + + public native int run_once(); + + public void run() { + while (! isInterrupted()) { + if (run_once() != 0) + break; + } + } +} diff --git a/src/org/libvirt/Network.java b/src/org/libvirt/Network.java index 6fda985..cb7ccec 100644 --- a/src/org/libvirt/Network.java +++ b/src/org/libvirt/Network.java @@ -36,7 +36,9 @@ public class Network { * @throws LibvirtException */ public String getXMLDesc(int flags) throws LibvirtException{ - return _getXMLDesc(VNP, flags); + synchronized (this.virConnect) { + return _getXMLDesc(VNP, flags); + } } private native String _getXMLDesc(long VNP, int flags) throws LibvirtException; @@ -48,7 +50,9 @@ public class Network { * @throws LibvirtException */ public boolean getAutostart() throws LibvirtException{ - return _getAutostart(VNP); + synchronized (this.virConnect) { + return _getAutostart(VNP); + } } private native boolean _getAutostart(long VNP) throws LibvirtException; @@ -61,7 +65,9 @@ public class Network { * @throws LibvirtException */ public void setAutostart(boolean autostart) throws LibvirtException{ - _setAutostart(VNP, autostart); + synchronized (this.virConnect) { + _setAutostart(VNP, autostart); + } } private native int _setAutostart(long VNP, boolean autostart) throws LibvirtException; @@ -73,7 +79,9 @@ public class Network { * @throws LibvirtException */ public String getBridgeName() throws LibvirtException{ - return _getBridgeName(VNP); + synchronized (this.virConnect) { + return _getBridgeName(VNP); + } } private native String _getBridgeName(long VNP) throws LibvirtException; @@ -85,7 +93,9 @@ public class Network { * @return the Connect object */ public Connect getConnect(){ - return virConnect; + synchronized (this.virConnect) { + return virConnect; + } } @@ -96,7 +106,9 @@ public class Network { * @throws LibvirtException */ public String getName() throws LibvirtException{ - return _getName(VNP); + synchronized (this.virConnect) { + return _getName(VNP); + } } private native String _getName(long VNP) throws LibvirtException; @@ -109,7 +121,9 @@ public class Network { * @see <a href="http://www.ietf.org/rfc/rfc4122.txt">rfc4122</a> */ public int[] getUUID() throws LibvirtException{ - return _getUUID(VNP); + synchronized (this.virConnect) { + return _getUUID(VNP); + } } private native int[] _getUUID(long VNP) throws LibvirtException; @@ -122,7 +136,9 @@ public class Network { * @see <a href="http://www.ietf.org/rfc/rfc4122.txt">rfc4122</a> */ public String getUUIDString() throws LibvirtException{ - return _getUUIDString(VNP); + synchronized (this.virConnect) { + return _getUUIDString(VNP); + } } private native String _getUUIDString(long VNP) throws LibvirtException; @@ -134,7 +150,9 @@ public class Network { * @throws LibvirtException */ public void create() throws LibvirtException{ - _create(VNP); + synchronized (this.virConnect) { + _create(VNP); + } } private native int _create(long VNP) throws LibvirtException; @@ -148,7 +166,9 @@ public class Network { * @throws LibvirtException */ public void destroy() throws LibvirtException{ - _destroy(VNP); + synchronized (this.virConnect) { + _destroy(VNP); + } } private native int _destroy(long VNP) throws LibvirtException; @@ -161,8 +181,10 @@ public class Network { * @throws LibvirtException */ public void free() throws LibvirtException{ - _free(VNP); - VNP=0; + synchronized (this.virConnect) { + _free(VNP); + VNP=0; + } } private native int _free(long VNP) throws LibvirtException; @@ -173,7 +195,9 @@ public class Network { * @throws LibvirtException */ public void undefine() throws LibvirtException{ - _undefine(VNP); + synchronized (this.virConnect) { + _undefine(VNP); + } } private native int _undefine(long VNP) throws LibvirtException; diff --git a/src/org/libvirt/StoragePool.java b/src/org/libvirt/StoragePool.java index 6fc3db4..f787797 100644 --- a/src/org/libvirt/StoragePool.java +++ b/src/org/libvirt/StoragePool.java @@ -57,7 +57,9 @@ public class StoragePool { * @param flags future flags, use 0 for now */ public void build(int flags) throws LibvirtException{ - _build(VSPP, flags); + synchronized (this.virConnect) { + _build(VSPP, flags); + } } private native int _build(long VSPP, int flags) throws LibvirtException; @@ -68,7 +70,9 @@ public class StoragePool { * @param flags future flags, use 0 for now */ public void create(int flags) throws LibvirtException{ - _create(VSPP, flags); + synchronized (this.virConnect) { + _create(VSPP, flags); + } } private native int _create(long VSPP, int flags) throws LibvirtException; @@ -80,7 +84,9 @@ public class StoragePool { * @param flags flags for obliteration process */ public void delete(int flags) throws LibvirtException{ - _delete(VSPP, flags); + synchronized (this.virConnect) { + _delete(VSPP, flags); + } } private native int _delete(long VSPP, int flags) throws LibvirtException; @@ -92,7 +98,9 @@ public class StoragePool { * This does not free the associated virStoragePoolPtr object. */ public void destroy() throws LibvirtException{ - _destroy(VSPP); + synchronized (this.virConnect) { + _destroy(VSPP); + } } private native int _destroy(long VSPP) throws LibvirtException; @@ -102,7 +110,9 @@ public class StoragePool { * Does not change the state of the pool on the host. */ public void free() throws LibvirtException{ - _free(VSPP); + synchronized (this.virConnect) { + _free(VSPP); + } } private native int _free(long VSPP) throws LibvirtException; @@ -115,7 +125,9 @@ public class StoragePool { * @throws LibvirtException */ public boolean getAutostart() throws LibvirtException{ - return _getAutostart(VSPP); + synchronized (this.virConnect) { + return _getAutostart(VSPP); + } } private native boolean _getAutostart(long VSPP) throws LibvirtException; @@ -147,7 +159,9 @@ public class StoragePool { * @throws LibvirtException */ public String getName() throws LibvirtException{ - return _getName(VSPP); + synchronized (this.virConnect) { + return _getName(VSPP); + } } private native String _getName(long VSPP) throws LibvirtException; @@ -159,7 +173,9 @@ public class StoragePool { * @throws LibvirtException */ public int[] getUUID() throws LibvirtException{ - return _getUUID(VSPP); + synchronized (this.virConnect) { + return _getUUID(VSPP); + } } private native int[] _getUUID(long VSPP) throws LibvirtException; @@ -172,7 +188,9 @@ public class StoragePool { * @throws LibvirtException */ public String getUUIDString() throws LibvirtException{ - return _getUUIDString(VSPP); + synchronized (this.virConnect) { + return _getUUIDString(VSPP); + } } private native String _getUUIDString(long VSPP) throws LibvirtException; @@ -186,7 +204,9 @@ public class StoragePool { *-java @throws LibvirtException */ public String getXMLDesc(int flags) throws LibvirtException{ - return _getXMLDesc(VSPP, flags); + synchronized (this.virConnect) { + return _getXMLDesc(VSPP, flags); + } } private native String _getXMLDesc(long VSPP, int flags) throws LibvirtException; @@ -198,7 +218,9 @@ public class StoragePool { * @throws LibvirtException */ public String[] listVolumes() throws LibvirtException { - return _listVolumes(VSPP); + synchronized (this.virConnect) { + return _listVolumes(VSPP); + } } private native String[] _listVolumes(long VSPP) @@ -211,7 +233,9 @@ public class StoragePool { * @throws LibvirtException */ public int numOfVolumes() throws LibvirtException { - return _numOfVolumes(VSPP); + synchronized (this.virConnect) { + return _numOfVolumes(VSPP); + } } private native int _numOfVolumes(long VSPP) throws LibvirtException; @@ -224,7 +248,9 @@ public class StoragePool { * @throws LibvirtException */ public void refresh(int flags) throws LibvirtException { - _refresh(VSPP, flags); + synchronized (this.virConnect) { + _refresh(VSPP, flags); + } } private native int _refresh(long VSPP, int flags) throws LibvirtException; @@ -236,7 +262,9 @@ public class StoragePool { * @throws LibvirtException */ public void setAutostart(int autostart) throws LibvirtException { - _setAutostart(VSPP, autostart); + synchronized (this.virConnect) { + _setAutostart(VSPP, autostart); + } } private native int _setAutostart(long VSPP, int autostart) throws LibvirtException; @@ -247,7 +275,9 @@ public class StoragePool { * @throws LibvirtException */ public void undefine() throws LibvirtException { - _undefine(VSPP); + synchronized (this.virConnect) { + _undefine(VSPP); + } } private native int _undefine(long VSPP) throws LibvirtException; @@ -261,7 +291,9 @@ public class StoragePool { */ public StorageVol storageVolLookupByName(String name) throws LibvirtException { - return new StorageVol(virConnect, _storageVolLookupByName(VSPP, name)); + synchronized (this.virConnect) { + return new StorageVol(virConnect, _storageVolLookupByName(VSPP, name)); + } } private native long _storageVolLookupByName(long VSPP, String name) @@ -277,7 +309,9 @@ public class StoragePool { */ public StorageVol storageVolCreateXML(String xmlDesc, int flags) throws LibvirtException { - return new StorageVol(virConnect, _storageVolCreateXML(VSPP, xmlDesc, flags)); + synchronized (this.virConnect) { + return new StorageVol(virConnect, _storageVolCreateXML(VSPP, xmlDesc, flags)); + } } private native long _storageVolCreateXML(long VSPP, String xmlDesc, int flags) diff --git a/src/org/libvirt/StorageVol.java b/src/org/libvirt/StorageVol.java index 97694e1..f4a2d12 100644 --- a/src/org/libvirt/StorageVol.java +++ b/src/org/libvirt/StorageVol.java @@ -55,7 +55,9 @@ public class StorageVol { */ public StoragePool storagePoolLookupByVolume() throws LibvirtException { - return new StoragePool(virConnect, _storagePoolLookupByVolume(VSVP)); + synchronized (this.virConnect) { + return new StoragePool(virConnect, _storagePoolLookupByVolume(VSVP)); + } } private native long _storagePoolLookupByVolume(long VSVP) @@ -68,7 +70,9 @@ public class StorageVol { * @throws LibvirtException */ public void delete(int flags) throws LibvirtException{ - _delete(VSVP, flags); + synchronized (this.virConnect) { + _delete(VSVP, flags); + } } private native int _delete(long VSVP, int flags) throws LibvirtException; @@ -79,7 +83,9 @@ public class StorageVol { * @throws LibvirtException */ public void free() throws LibvirtException{ - _free(VSVP); + synchronized (this.virConnect) { + _free(VSVP); + } } private native int _free(long VSVP) throws LibvirtException; @@ -100,7 +106,9 @@ public class StorageVol { * @throws LibvirtException */ public StorageVolInfo getInfo() throws LibvirtException{ - return _getInfo(VSVP); + synchronized (this.virConnect) { + return _getInfo(VSVP); + } } private native StorageVolInfo _getInfo(long VSVP) throws LibvirtException; @@ -112,7 +120,9 @@ public class StorageVol { * @throws LibvirtException */ public String getKey() throws LibvirtException{ - return _getKey(VSVP); + synchronized (this.virConnect) { + return _getKey(VSVP); + } } private native String _getKey(long VSVP) throws LibvirtException; @@ -124,7 +134,9 @@ public class StorageVol { * @throws LibvirtException */ public String getName() throws LibvirtException{ - return _getName(VSVP); + synchronized (this.virConnect) { + return _getName(VSVP); + } } private native String _getName(long VSVP) throws LibvirtException; @@ -138,7 +150,9 @@ public class StorageVol { * @throws LibvirtException */ public String getPath() throws LibvirtException{ - return _getPath(VSVP); + synchronized (this.virConnect) { + return _getPath(VSVP); + } } private native String _getPath(long VSVP) throws LibvirtException; @@ -151,7 +165,9 @@ public class StorageVol { * @throws LibvirtException */ public String getXMLDesc(int flags) throws LibvirtException{ - return _getXMLDesc(VSVP, flags); + synchronized (this.virConnect) { + return _getXMLDesc(VSVP, flags); + } } private native String _getXMLDesc(long VSVP, int flags) throws LibvirtException;
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list