[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [libvirt] Python stream callback removal



On Tue, Aug 09, 2011 at 10:59:02AM +0100, Daniel P. Berrange wrote:
> On Mon, Aug 08, 2011 at 06:04:50PM -0400, Dave Allan wrote:
> > I'm trying to write an example serial console implementation in python
> > (attached), but I'm having some trouble getting stream events to do
> > what I want.  The console itself works fine as long as the domain
> > stays up, but as soon as the domain shuts down the python script goes
> > into a tight loop repeatedly calling the stream event callback.
> > Debugging indicates that the stream event callback is being requested
> > to be removed, but it never actually is removed which makes me think I
> > am not properly releasing some resource, but I was under the
> > impression that an error on a stream resulting in the stream aborting
> > was supposed to free all the resources for me.  Is that not correct?
> 
> No where in your code do you ever invoke eventRemoveCallback.
> When the stream is "aborted" this just means that libvirtd
> has released server side resource & reported the error back
> to the client. You still have to remove your event callbacks
> otherwise you'll just be invoked forever. See tools/console.c
> for example code doing what you're attempting, but in C.
> In particular the places which call virConsoleShutdown.
> Your code in Python should  basically be a straight conversion
> of tools/console.c from C into Python.

Thanks, that was the problem; calling remove fixed it.

What I'm trying to do is to write a console that does not exit when
the domain is down, and the code is now working, at least for a short
while.  However, I am seeing a strange behavior.  After the domain has
been powered off twice--regardless of whether the domain was started
or stopped when the console program is started--when starting the
domain the next time the console hangs and no callbacks are called.  I
attached to the process with gdb and the backtraces are very different
when the process is responsive vs. when it is ok.

Any ideas on what's going wrong?

Dave
When ok:
(gdb) bt
#0  0x00000030f2ad7248 in poll () from /lib64/libc.so.6
#1  0x00007ffd47608f4a in virEventPollRunOnce () at util/event_poll.c:594
#2  0x00007ffd47607ba5 in virEventRunDefaultImpl () at util/event.c:247
#3  0x00007ffd47a89f8e in libvirt_virEventRunDefaultImpl (self=<value optimized out>, args=<value optimized out>)
    at libvirt.c:3598
#4  0x00000030feae965b in PyEval_EvalFrameEx () from /usr/lib64/libpython2.7.so.1.0
#5  0x00000030feaea71d in PyEval_EvalFrameEx () from /usr/lib64/libpython2.7.so.1.0
#6  0x00000030feaeb04d in PyEval_EvalCodeEx () from /usr/lib64/libpython2.7.so.1.0
#7  0x00000030feaeb162 in PyEval_EvalCode () from /usr/lib64/libpython2.7.so.1.0
#8  0x00000030feb0639c in ?? () from /usr/lib64/libpython2.7.so.1.0
#9  0x00000030feb071d0 in PyRun_FileExFlags () from /usr/lib64/libpython2.7.so.1.0
#10 0x00000030feb07daf in PyRun_SimpleFileExFlags () from /usr/lib64/libpython2.7.so.1.0
#11 0x00000030feb198ce in Py_Main () from /usr/lib64/libpython2.7.so.1.0
#12 0x00000030f2a1ee5d in __libc_start_main () from /lib64/libc.so.6
#13 0x0000000000400649 in _start ()


When unresponsive:
#0  0x00000030f2ad7248 in poll () from /lib64/libc.so.6
#1  0x00007ffd476d259f in virNetClientIOEventLoop (client=0x7ffd47107010, thiscall=0xb5b5d0) at rpc/virnetclient.c:884
#2  0x00007ffd476d3adc in virNetClientIO (client=0x7ffd47107010, msg=<value optimized out>, expectReply=true)
    at rpc/virnetclient.c:1121
#3  virNetClientSend (client=0x7ffd47107010, msg=<value optimized out>, expectReply=true) at rpc/virnetclient.c:1196
#4  0x00007ffd476d4348 in virNetClientProgramCall (prog=0xb27d90, client=0x7ffd47107010, serial=11, proc=212, 
    args_filter=0x7ffd476d1110 <xdr_remote_domain_get_state_args>, args=0x7fff888267a0, 
    ret_filter=0x7ffd476d1180 <xdr_remote_domain_get_state_ret>, ret=0x7fff88826790) at rpc/virnetclientprogram.c:291
#5  0x00007ffd476b5049 in call (priv=0xb8a300, flags=<value optimized out>, proc_nr=212, 
    args_filter=0x7ffd476d1110 <xdr_remote_domain_get_state_args>, args=<value optimized out>, 
    ret_filter=<value optimized out>, ret=0x7fff88826790 "", conn=<value optimized out>) at remote/remote_driver.c:4039
#6  0x00007ffd476bc228 in remoteDomainGetState (domain=0xb139e0, state=0x7fff888268bc, reason=0x7fff888268b8, flags=0)
    at remote/remote_driver.c:1656
#7  0x00007ffd4768b4b7 in virDomainGetState (domain=0xb139e0, state=0x7fff888268bc, reason=0x7fff888268b8, flags=0)
    at libvirt.c:3655
#8  0x00007ffd47a808f5 in libvirt_virDomainGetState (self=<value optimized out>, args=<value optimized out>)
    at libvirt-override.c:1712
#9  0x00000030feae965b in PyEval_EvalFrameEx () from /usr/lib64/libpython2.7.so.1.0
#10 0x00000030feaea71d in PyEval_EvalFrameEx () from /usr/lib64/libpython2.7.so.1.0
#11 0x00000030feaea71d in PyEval_EvalFrameEx () from /usr/lib64/libpython2.7.so.1.0
#12 0x00000030feaeb04d in PyEval_EvalCodeEx () from /usr/lib64/libpython2.7.so.1.0
#13 0x00000030fea71c62 in ?? () from /usr/lib64/libpython2.7.so.1.0
#14 0x00000030fea48fc3 in PyObject_Call () from /usr/lib64/libpython2.7.so.1.0
#15 0x00000030fea5a65f in ?? () from /usr/lib64/libpython2.7.so.1.0
#16 0x00000030fea48fc3 in PyObject_Call () from /usr/lib64/libpython2.7.so.1.0
#17 0x00000030fea490ab in ?? () from /usr/lib64/libpython2.7.so.1.0
#18 0x00000030fea4935b in PyObject_CallMethod () from /usr/lib64/libpython2.7.so.1.0
#19 0x00007ffd47a82082 in libvirt_virConnectDomainEventCallback (conn=<value optimized out>, dom=<value optimized out>, 
    event=2, detail=0, opaque=0x7ffd47ccdb90) at libvirt-override.c:3210
#20 0x00007ffd4764f0c6 in virDomainEventDispatchDefaultFunc (conn=0xb02620, event=0xbbdf90, 
    cb=0x7ffd47a81f30 <libvirt_virConnectDomainEventCallback>, cbopaque=0x7ffd47ccdb90, opaque=<value optimized out>)
    at conf/domain_event.c:1023
#21 0x00007ffd476b48fa in remoteDomainEventDispatchFunc (conn=0xb02620, event=0xbbdf90, 
    cb=0x7ffd47a81f30 <libvirt_virConnectDomainEventCallback>, cbopaque=0x7ffd47ccdb90, opaque=0xb8a300)
    at remote/remote_driver.c:4063
#22 0x00007ffd4764f26f in virDomainEventDispatch (event=0xbbdf90, callbacks=0xa52ac0, dispatch=<value optimized out>, 
    opaque=0xb8a300) at conf/domain_event.c:1136
#23 0x00007ffd4764f30a in virDomainEventQueueDispatch (queue=0x7fff888273e0, callbacks=0xa52ac0, 
    dispatch=0x7ffd476b4870 <remoteDomainEventDispatchFunc>, opaque=0xb8a300) at conf/domain_event.c:1153
#24 0x00007ffd4764f4de in virDomainEventStateFlush (state=0xb5ad00, 
    dispatchFunc=0x7ffd476b4870 <remoteDomainEventDispatchFunc>, opaque=0xb8a300) at conf/domain_event.c:1195
#25 0x00007ffd476b4845 in remoteDomainEventQueueFlush (timer=<value optimized out>, opaque=0xb02620)
    at remote/remote_driver.c:4077
#26 0x00007ffd47609116 in virEventPollDispatchTimeouts () at util/event_poll.c:421
#27 virEventPollRunOnce () at util/event_poll.c:607
#28 0x00007ffd47607ba5 in virEventRunDefaultImpl () at util/event.c:247
#29 0x00007ffd47a89f8e in libvirt_virEventRunDefaultImpl (self=<value optimized out>, args=<value optimized out>)
    at libvirt.c:3598
#30 0x00000030feae965b in PyEval_EvalFrameEx () from /usr/lib64/libpython2.7.so.1.0
#31 0x00000030feaea71d in PyEval_EvalFrameEx () from /usr/lib64/libpython2.7.so.1.0
#32 0x00000030feaeb04d in PyEval_EvalCodeEx () from /usr/lib64/libpython2.7.so.1.0
#33 0x00000030feaeb162 in PyEval_EvalCode () from /usr/lib64/libpython2.7.so.1.0
#34 0x00000030feb0639c in ?? () from /usr/lib64/libpython2.7.so.1.0
#35 0x00000030feb071d0 in PyRun_FileExFlags () from /usr/lib64/libpython2.7.so.1.0
#36 0x00000030feb07daf in PyRun_SimpleFileExFlags () from /usr/lib64/libpython2.7.so.1.0
#37 0x00000030feb198ce in Py_Main () from /usr/lib64/libpython2.7.so.1.0
#38 0x00000030f2a1ee5d in __libc_start_main () from /lib64/libc.so.6
#39 0x0000000000400649 in _start ()

#!/usr/bin/python -u
import sys, os, logging, libvirt, tty, termios, atexit

def reset_term():
    termios.tcsetattr(0, termios.TCSADRAIN, attrs)

def error_handler(unused, error):
    # The console stream errors on VM shutdown; we don't care, right?
    # if (error[0] == libvirt.VIR_ERR_RPC and
    #    error[1] == libvirt.VIR_FROM_STREAMS):
    #    return
    logging.warn(error)

class Console(object):
    def __init__(self, uri, uuid):
        self.uri = uri
        self.uuid = uuid
        self.connection = libvirt.open(uri)
        self.domain = self.connection.lookupByUUIDString(uuid)
        self.state = self.domain.state(0)
        self.connection.domainEventRegister(lifecycle_callback, self)
        self.stream = None
        self.run_console = True
        logging.info("%s initial state %d, reason %d",
                     self.uuid, self.state[0], self.state[1])

def check_console(console):
    if (console.state[0] == libvirt.VIR_DOMAIN_RUNNING or
        console.state[0] == libvirt.VIR_DOMAIN_PAUSED):
        if console.stream == None:
            console.stream = console.connection.newStream(libvirt.VIR_STREAM_NONBLOCK)
            console.domain.openConsole(None, console.stream, 0)
            console.stream.eventAddCallback(libvirt.VIR_STREAM_EVENT_READABLE, stream_callback, console)
    else:
        if console.stream:
            console.stream.eventRemoveCallback()
            console.stream = None

    return console.run_console

def stdin_callback(watch, fd, events, console):
    readbuf = os.read(fd, 1024)
    if readbuf.startswith(""):
        console.run_console = False
        return
    if console.stream:
        console.stream.send(readbuf)

def stream_callback(stream, events, console):
    try:
        received_data = console.stream.recv(1024)
    except:
        return
    os.write(0, received_data)

def lifecycle_callback (connection, domain, event, detail, console):
    console.state = console.domain.state(0)
    logging.info("%s transitioned to state %d, reason %d",
                 console.uuid, console.state[0], console.state[1])

# main
uri = sys.argv[1]
uuid = sys.argv[2]

logging.basicConfig(filename='msg.log', level=logging.DEBUG)
logging.info("URI: %s", uri)
logging.info("UUID: %s", uuid)

libvirt.virEventRegisterDefaultImpl()
libvirt.registerErrorHandler(error_handler, None)

atexit.register(reset_term)
attrs = termios.tcgetattr(0)
tty.setraw(0)

console = Console(uri, uuid)
console.stdin_watch = libvirt.virEventAddHandle(0, libvirt.VIR_EVENT_HANDLE_READABLE, stdin_callback, console)

while check_console(console):
    libvirt.virEventRunDefaultImpl()

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]