mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
Update event loop example programs to demonstrate best practice
The example C event loop code is a nasty hack and not compliant with the require API semantics. Delete this, so that developers don't mistakenly copy it. Instead call the new public event loop APIs. Update the python event loop example, so that it can optionally use the public event APIs, as an alternative to the pure python code. The pure python event code is a good working example, so don't delete it. Also make the python example use a read only connection to avoid authentication prompts * examples/domain-events/events-c/event-test.c: Replace event loop code with use of public APIs * examples/domain-events/events-python/event-test.py: Allow optional use of new public event APIs
This commit is contained in:
parent
83b77fa589
commit
0c97e70b74
@ -5,36 +5,18 @@
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#if HAVE_SYS_POLL_H
|
||||
# include <sys/types.h>
|
||||
# include <sys/poll.h>
|
||||
# include <libvirt/libvirt.h>
|
||||
#include <libvirt/libvirt.h>
|
||||
#include <libvirt/virterror.h>
|
||||
|
||||
# define VIR_DEBUG0(fmt) printf("%s:%d :: " fmt "\n", \
|
||||
#define VIR_DEBUG0(fmt) printf("%s:%d :: " fmt "\n", \
|
||||
__func__, __LINE__)
|
||||
# define VIR_DEBUG(fmt, ...) printf("%s:%d: " fmt "\n", \
|
||||
#define VIR_DEBUG(fmt, ...) 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
|
||||
|
||||
/* 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;
|
||||
#define STREQ(a,b) (strcmp(a,b) == 0)
|
||||
|
||||
#ifndef ATTRIBUTE_UNUSED
|
||||
# define ATTRIBUTE_UNUSED __attribute__((__unused__))
|
||||
#endif
|
||||
|
||||
/* Prototypes */
|
||||
const char *eventToString(int event);
|
||||
@ -266,94 +248,6 @@ static void myFreeFunc(void *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)
|
||||
{
|
||||
VIR_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)
|
||||
{
|
||||
VIR_DEBUG("Updated Handle %d %d", fd, event);
|
||||
h_event = myEventHandleTypeToPollEvent(event);
|
||||
return;
|
||||
}
|
||||
|
||||
int myEventRemoveHandleFunc(int fd)
|
||||
{
|
||||
VIR_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)
|
||||
{
|
||||
VIR_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)
|
||||
{
|
||||
/*VIR_DEBUG("Timeout updated %d %d", timer, timeout);*/
|
||||
t_timeout = timeout;
|
||||
}
|
||||
|
||||
int myEventRemoveTimeoutFunc(int timer)
|
||||
{
|
||||
VIR_DEBUG("Timeout removed %d", timer);
|
||||
t_active = 0;
|
||||
if (t_ff)
|
||||
(t_ff)(t_opaque);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* main test functions */
|
||||
|
||||
void usage(const char *pname)
|
||||
@ -372,7 +266,6 @@ static void stop(int sig)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int sts;
|
||||
int callback1ret = -1;
|
||||
int callback2ret = -1;
|
||||
int callback3ret = -1;
|
||||
@ -386,17 +279,12 @@ int main(int argc, char **argv)
|
||||
|
||||
action_stop.sa_handler = stop;
|
||||
|
||||
if(argc > 1 && STREQ(argv[1],"--help")) {
|
||||
if (argc > 1 && STREQ(argv[1], "--help")) {
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virEventRegisterImpl( myEventAddHandleFunc,
|
||||
myEventUpdateHandleFunc,
|
||||
myEventRemoveHandleFunc,
|
||||
myEventAddTimeoutFunc,
|
||||
myEventUpdateTimeoutFunc,
|
||||
myEventRemoveTimeoutFunc);
|
||||
virEventRegisterDefaultImpl();
|
||||
|
||||
virConnectPtr dconn = NULL;
|
||||
dconn = virConnectOpenReadOnly (argv[1] ? argv[1] : NULL);
|
||||
@ -451,38 +339,12 @@ int main(int argc, char **argv)
|
||||
(callback5ret != -1) &&
|
||||
(callback6ret != -1) &&
|
||||
(callback7ret != -1)) {
|
||||
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);
|
||||
while (run) {
|
||||
if (virEventRunDefaultImpl() < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
fprintf(stderr, "Failed to run event loop: %s\n",
|
||||
err && err->message ? err->message : "Unknown error");
|
||||
}
|
||||
|
||||
if (sts == 0) {
|
||||
/* VIR_DEBUG0("Poll timeout"); */
|
||||
continue;
|
||||
}
|
||||
if (sts < 0 ) {
|
||||
VIR_DEBUG0("Poll failed");
|
||||
continue;
|
||||
}
|
||||
if ( pfd.revents & POLLHUP ) {
|
||||
VIR_DEBUG0("Reset by peer");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(h_cb) {
|
||||
h_cb(0,
|
||||
h_fd,
|
||||
myPollEventToEventHandleType(pfd.revents & h_event),
|
||||
h_opaque);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VIR_DEBUG0("Deregistering event handlers");
|
||||
@ -496,17 +358,10 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
VIR_DEBUG0("Closing connection");
|
||||
if( dconn && virConnectClose(dconn)<0 ) {
|
||||
if (dconn && virConnectClose(dconn) < 0) {
|
||||
printf("error closing\n");
|
||||
}
|
||||
|
||||
printf("done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) {
|
||||
printf("event-test program not available without sys/poll.h support\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
@ -15,6 +15,17 @@ import errno
|
||||
import time
|
||||
import threading
|
||||
|
||||
# For the sake of demonstration, this example program includes
|
||||
# an implementation of a pure python event loop. Most applications
|
||||
# would be better off just using the default libvirt event loop
|
||||
# APIs, instead of implementing this in python. The exception is
|
||||
# where an application wants to integrate with an existing 3rd
|
||||
# party event loop impl
|
||||
#
|
||||
# Change this to 'False' to make the demo use the native
|
||||
# libvirt event loop impl
|
||||
use_pure_python_event_loop = True
|
||||
|
||||
do_debug = False
|
||||
def debug(msg):
|
||||
global do_debug
|
||||
@ -392,6 +403,10 @@ def virEventLoopPureRun():
|
||||
global eventLoop
|
||||
eventLoop.run_loop()
|
||||
|
||||
def virEventLoopNativeRun():
|
||||
while True:
|
||||
libvirt.virEventRunDefaultImpl()
|
||||
|
||||
# Spawn a background thread to run the event loop
|
||||
def virEventLoopPureStart():
|
||||
global eventLoopThread
|
||||
@ -400,6 +415,13 @@ def virEventLoopPureStart():
|
||||
eventLoopThread.setDaemon(True)
|
||||
eventLoopThread.start()
|
||||
|
||||
def virEventLoopNativeStart():
|
||||
global eventLoopThread
|
||||
libvirt.virEventRegisterDefaultImpl()
|
||||
eventLoopThread = threading.Thread(target=virEventLoopNativeRun, name="libvirtEventLoop")
|
||||
eventLoopThread.setDaemon(True)
|
||||
eventLoopThread.start()
|
||||
|
||||
|
||||
##########################################################################
|
||||
# Everything that now follows is a simple demo of domain lifecycle events
|
||||
@ -474,9 +496,12 @@ def main():
|
||||
print "Using uri:" + uri
|
||||
|
||||
# Run a background thread with the event loop
|
||||
virEventLoopPureStart()
|
||||
if use_pure_python_event_loop:
|
||||
virEventLoopPureStart()
|
||||
else:
|
||||
virEventLoopNativeStart()
|
||||
|
||||
vc = libvirt.open(uri)
|
||||
vc = libvirt.openReadOnly(uri)
|
||||
|
||||
# Close connection on exit (to test cleanup paths)
|
||||
old_exitfunc = getattr(sys, 'exitfunc', None)
|
||||
|
Loading…
Reference in New Issue
Block a user