chardev: allow telnet gsource to switch gcontext
It was originally created by qio_channel_add_watch() so it's always assigning the task to main context. Now we use the new API called qio_channel_add_watch_source() so that we get the GSource handle rather than the tag ID. Meanwhile, caching the gsource and TCPChardevTelnetInit (which holds the handshake data) in SocketChardev.telnet_source so that we can also do dynamic context switch when update read handlers. Signed-off-by: Peter Xu <peterx@redhat.com> Message-Id: <20180306053320.15401-5-peterx@redhat.com> Acked-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									3da9de5ce2
								
							
						
					
					
						commit
						ce1230c054
					
				@ -40,6 +40,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define TCP_MAX_FDS 16
 | 
					#define TCP_MAX_FDS 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    char buf[21];
 | 
				
			||||||
 | 
					    size_t buflen;
 | 
				
			||||||
 | 
					} TCPChardevTelnetInit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    Chardev parent;
 | 
					    Chardev parent;
 | 
				
			||||||
    QIOChannel *ioc; /* Client I/O channel */
 | 
					    QIOChannel *ioc; /* Client I/O channel */
 | 
				
			||||||
@ -60,6 +65,8 @@ typedef struct {
 | 
				
			|||||||
    bool is_listen;
 | 
					    bool is_listen;
 | 
				
			||||||
    bool is_telnet;
 | 
					    bool is_telnet;
 | 
				
			||||||
    bool is_tn3270;
 | 
					    bool is_tn3270;
 | 
				
			||||||
 | 
					    GSource *telnet_source;
 | 
				
			||||||
 | 
					    TCPChardevTelnetInit *telnet_init;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    GSource *reconnect_timer;
 | 
					    GSource *reconnect_timer;
 | 
				
			||||||
    int64_t reconnect_time;
 | 
					    int64_t reconnect_time;
 | 
				
			||||||
@ -70,6 +77,7 @@ typedef struct {
 | 
				
			|||||||
    OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
 | 
					    OBJECT_CHECK(SocketChardev, (obj), TYPE_CHARDEV_SOCKET)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static gboolean socket_reconnect_timeout(gpointer opaque);
 | 
					static gboolean socket_reconnect_timeout(gpointer opaque);
 | 
				
			||||||
 | 
					static void tcp_chr_telnet_init(Chardev *chr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void tcp_chr_reconn_timer_cancel(SocketChardev *s)
 | 
					static void tcp_chr_reconn_timer_cancel(SocketChardev *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -556,6 +564,15 @@ static void tcp_chr_connect(void *opaque)
 | 
				
			|||||||
    qemu_chr_be_event(chr, CHR_EVENT_OPENED);
 | 
					    qemu_chr_be_event(chr, CHR_EVENT_OPENED);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tcp_chr_telnet_destroy(SocketChardev *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (s->telnet_source) {
 | 
				
			||||||
 | 
					        g_source_destroy(s->telnet_source);
 | 
				
			||||||
 | 
					        g_source_unref(s->telnet_source);
 | 
				
			||||||
 | 
					        s->telnet_source = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void tcp_chr_update_read_handler(Chardev *chr)
 | 
					static void tcp_chr_update_read_handler(Chardev *chr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    SocketChardev *s = SOCKET_CHARDEV(chr);
 | 
					    SocketChardev *s = SOCKET_CHARDEV(chr);
 | 
				
			||||||
@ -570,6 +587,10 @@ static void tcp_chr_update_read_handler(Chardev *chr)
 | 
				
			|||||||
                                              chr, NULL, chr->gcontext);
 | 
					                                              chr, NULL, chr->gcontext);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->telnet_source) {
 | 
				
			||||||
 | 
					        tcp_chr_telnet_init(CHARDEV(s));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!s->connected) {
 | 
					    if (!s->connected) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -583,32 +604,30 @@ static void tcp_chr_update_read_handler(Chardev *chr)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
    Chardev *chr;
 | 
					 | 
				
			||||||
    char buf[21];
 | 
					 | 
				
			||||||
    size_t buflen;
 | 
					 | 
				
			||||||
} TCPChardevTelnetInit;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
 | 
					static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
 | 
				
			||||||
                                       GIOCondition cond G_GNUC_UNUSED,
 | 
					                                       GIOCondition cond G_GNUC_UNUSED,
 | 
				
			||||||
                                       gpointer user_data)
 | 
					                                       gpointer user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    TCPChardevTelnetInit *init = user_data;
 | 
					    SocketChardev *s = user_data;
 | 
				
			||||||
 | 
					    Chardev *chr = CHARDEV(s);
 | 
				
			||||||
 | 
					    TCPChardevTelnetInit *init = s->telnet_init;
 | 
				
			||||||
    ssize_t ret;
 | 
					    ssize_t ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    assert(init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
 | 
					    ret = qio_channel_write(ioc, init->buf, init->buflen, NULL);
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
        if (ret == QIO_CHANNEL_ERR_BLOCK) {
 | 
					        if (ret == QIO_CHANNEL_ERR_BLOCK) {
 | 
				
			||||||
            ret = 0;
 | 
					            ret = 0;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            tcp_chr_disconnect(init->chr);
 | 
					            tcp_chr_disconnect(chr);
 | 
				
			||||||
            goto end;
 | 
					            goto end;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    init->buflen -= ret;
 | 
					    init->buflen -= ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (init->buflen == 0) {
 | 
					    if (init->buflen == 0) {
 | 
				
			||||||
        tcp_chr_connect(init->chr);
 | 
					        tcp_chr_connect(chr);
 | 
				
			||||||
        goto end;
 | 
					        goto end;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -617,16 +636,30 @@ static gboolean tcp_chr_telnet_init_io(QIOChannel *ioc,
 | 
				
			|||||||
    return G_SOURCE_CONTINUE;
 | 
					    return G_SOURCE_CONTINUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
end:
 | 
					end:
 | 
				
			||||||
    g_free(init);
 | 
					    g_free(s->telnet_init);
 | 
				
			||||||
 | 
					    s->telnet_init = NULL;
 | 
				
			||||||
 | 
					    g_source_unref(s->telnet_source);
 | 
				
			||||||
 | 
					    s->telnet_source = NULL;
 | 
				
			||||||
    return G_SOURCE_REMOVE;
 | 
					    return G_SOURCE_REMOVE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void tcp_chr_telnet_init(Chardev *chr)
 | 
					static void tcp_chr_telnet_init(Chardev *chr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    SocketChardev *s = SOCKET_CHARDEV(chr);
 | 
					    SocketChardev *s = SOCKET_CHARDEV(chr);
 | 
				
			||||||
    TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1);
 | 
					    TCPChardevTelnetInit *init;
 | 
				
			||||||
    size_t n = 0;
 | 
					    size_t n = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Destroy existing task */
 | 
				
			||||||
 | 
					    tcp_chr_telnet_destroy(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->telnet_init) {
 | 
				
			||||||
 | 
					        /* We are possibly during a handshake already */
 | 
				
			||||||
 | 
					        goto cont;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->telnet_init = g_new0(TCPChardevTelnetInit, 1);
 | 
				
			||||||
 | 
					    init = s->telnet_init;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IACSET(x, a, b, c)                      \
 | 
					#define IACSET(x, a, b, c)                      \
 | 
				
			||||||
    do {                                        \
 | 
					    do {                                        \
 | 
				
			||||||
        x[n++] = a;                             \
 | 
					        x[n++] = a;                             \
 | 
				
			||||||
@ -634,7 +667,6 @@ static void tcp_chr_telnet_init(Chardev *chr)
 | 
				
			|||||||
        x[n++] = c;                             \
 | 
					        x[n++] = c;                             \
 | 
				
			||||||
    } while (0)
 | 
					    } while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init->chr = chr;
 | 
					 | 
				
			||||||
    if (!s->is_tn3270) {
 | 
					    if (!s->is_tn3270) {
 | 
				
			||||||
        init->buflen = 12;
 | 
					        init->buflen = 12;
 | 
				
			||||||
        /* Prep the telnet negotion to put telnet in binary,
 | 
					        /* Prep the telnet negotion to put telnet in binary,
 | 
				
			||||||
@ -657,10 +689,11 @@ static void tcp_chr_telnet_init(Chardev *chr)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#undef IACSET
 | 
					#undef IACSET
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    qio_channel_add_watch(
 | 
					cont:
 | 
				
			||||||
        s->ioc, G_IO_OUT,
 | 
					    s->telnet_source = qio_channel_add_watch_source(s->ioc, G_IO_OUT,
 | 
				
			||||||
                                                    tcp_chr_telnet_init_io,
 | 
					                                                    tcp_chr_telnet_init_io,
 | 
				
			||||||
        init, NULL);
 | 
					                                                    s, NULL,
 | 
				
			||||||
 | 
					                                                    chr->gcontext);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -835,6 +868,8 @@ static void char_socket_finalize(Object *obj)
 | 
				
			|||||||
    tcp_chr_free_connection(chr);
 | 
					    tcp_chr_free_connection(chr);
 | 
				
			||||||
    tcp_chr_reconn_timer_cancel(s);
 | 
					    tcp_chr_reconn_timer_cancel(s);
 | 
				
			||||||
    qapi_free_SocketAddress(s->addr);
 | 
					    qapi_free_SocketAddress(s->addr);
 | 
				
			||||||
 | 
					    tcp_chr_telnet_destroy(s);
 | 
				
			||||||
 | 
					    g_free(s->telnet_init);
 | 
				
			||||||
    if (s->listener) {
 | 
					    if (s->listener) {
 | 
				
			||||||
        qio_net_listener_set_client_func_full(s->listener, NULL, NULL,
 | 
					        qio_net_listener_set_client_func_full(s->listener, NULL, NULL,
 | 
				
			||||||
                                              NULL, chr->gcontext);
 | 
					                                              NULL, chr->gcontext);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user