double call tcp_chr_free_connection generates a crash.
Signed-off-by: Li Feng <fengli@smartx.com>
---
chardev/char-socket.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 185fe38dda..43aab8f24b 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -476,6 +476,11 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
SocketChardev *s = SOCKET_CHARDEV(chr);
bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
+ /* avoid re-enter when socket read/write error and disconnect event. */
+ if (s->state == TCP_CHARDEV_STATE_DISCONNECTED) {
+ return;
+ }
+
tcp_chr_free_connection(chr);
if (s->listener) {
--
2.11.0
--
The SmartX email address is only for business purpose. Any sent message
that is not related to the business is not authorized or permitted by
SmartX.
本邮箱为北京志凌海纳科技有限公司(SmartX)工作邮箱. 如本邮箱发出的邮件与工作无关,该邮件未得到本公司任何的明示或默示的授权.
Hi
On Wed, Apr 15, 2020 at 5:31 AM Li Feng <fengli@smartx.com> wrote:
>
> double call tcp_chr_free_connection generates a crash.
>
> Signed-off-by: Li Feng <fengli@smartx.com>
Could you describe how you reach the "double call".
Even better would be to write a test for it in tests/test-char.c
thanks
> ---
> chardev/char-socket.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/chardev/char-socket.c b/chardev/char-socket.c
> index 185fe38dda..43aab8f24b 100644
> --- a/chardev/char-socket.c
> +++ b/chardev/char-socket.c
> @@ -476,6 +476,11 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
> SocketChardev *s = SOCKET_CHARDEV(chr);
> bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
>
> + /* avoid re-enter when socket read/write error and disconnect event. */
> + if (s->state == TCP_CHARDEV_STATE_DISCONNECTED) {
> + return;
> + }
> +
> tcp_chr_free_connection(chr);
>
> if (s->listener) {
> --
> 2.11.0
>
>
> --
> The SmartX email address is only for business purpose. Any sent message
> that is not related to the business is not authorized or permitted by
> SmartX.
> 本邮箱为北京志凌海纳科技有限公司(SmartX)工作邮箱. 如本邮箱发出的邮件与工作无关,该邮件未得到本公司任何的明示或默示的授权.
>
>
>
--
Marc-André Lureau
Hi Lureau,
Thanks for your comment.
I have spent some time to reproduce this crash, so that delay my
reply, apologies.
This is the description of this bug using gdb:
1. Set break points using gdb;
b chardev/char-socket.c:410 if s->state == TCP_CHARDEV_STATE_DISCONNECTED
b break vhost_user_write
2. hotplug a vhost-blk device:
echo "chardev-add
socket,id=spdk_vhost_blk2,path=/vhost-blk.0,reconnect=1 "| nc -U
/tmp/a.socket
echo "device_add
vhost-user-blk-pci,chardev=spdk_vhost_blk2,id=spdk_vhost_blk2,num-queues=4"
| nc -U /tmp/a.socket
3. Gdb will stop at vhost_user_write, and CTRL-C the vhost target.
4. Put 'c' to let gdb continue.
You will see a crash:
192 login: qemu-system-x86_64: chardev/char-socket.c:125:
qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed.
The related code:
394 static void tcp_chr_free_connection(Chardev *chr)
395 {
396 SocketChardev *s = SOCKET_CHARDEV(chr);
397 int i;
398
399 if (s->read_msgfds_num) {
400 for (i = 0; i < s->read_msgfds_num; i++) {
401 close(s->read_msgfds[i]);
402 }
403 g_free(s->read_msgfds);
404 s->read_msgfds = NULL;
405 s->read_msgfds_num = 0;
406 }
407
408 remove_hup_source(s);
409
410 tcp_set_msgfds(chr, NULL, 0);
411 remove_fd_in_watch(chr);
412 object_unref(OBJECT(s->sioc));
413 s->sioc = NULL;
414 object_unref(OBJECT(s->ioc));
415 s->ioc = NULL;
416 g_free(chr->filename);
417 chr->filename = NULL;
418 tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
419 }
#0 0x0000555555c1aae8 in tcp_chr_free_connection
(chr=chr@entry=0x55555751ee00) at chardev/char-socket.c:410
#1 0x0000555555c1aec8 in tcp_chr_disconnect_locked
(chr=0x55555751ee00) at chardev/char-socket.c:479
#2 0x0000555555c1af5d in tcp_chr_disconnect (chr=0x55555751ee00) at
chardev/char-socket.c:497
#3 0x0000555555c16715 in qemu_chr_fe_set_handlers
(b=b@entry=0x5555575f3b48, fd_can_read=fd_can_read@entry=0x0,
fd_read=fd_
read@entry=0x0, fd_event=fd_event@entry=0x55555588e740
<vhost_user_blk_event>, be_change=be_change@entry=0x0, opaque=opaque@
entry=0x5555575f3990, context=0x0, set_open=true) at chardev/char-fe.c:304
#4 0x000055555588e5c0 in vhost_user_blk_device_realize
(dev=0x5555575f3990, errp=<optimized out>)
at /root/qemu-master/hw/block/vhost-user-blk.c:447
#5 0x00005555558ca478 in virtio_device_realize (dev=0x5555575f3990,
errp=0x7fffffffbb90)
at /root/qemu-master/hw/virtio/virtio.c:3615
#6 0x00005555559dc842 in device_set_realized (obj=<optimized out>,
value=<optimized out>, errp=0x7fffffffbd20)
at hw/core/qdev.c:891
#7 0x0000555555b78e07 in property_set_bool (obj=0x5555575f3990,
v=<optimized out>, name=<optimized out>, opaque=0x555556453
040, errp=0x7fffffffbd20) at qom/object.c:2238
#8 0x0000555555b7db3f in object_property_set_qobject
(obj=obj@entry=0x5555575f3990, value=value@entry=0x555556ab89c0, name=
name@entry=0x555555d15308 "realized", errp=errp@entry=0x7fffffffbd20)
at qom/qom-qobject.c:26
#9 0x0000555555b7b2c5 in object_property_set_bool
(obj=0x5555575f3990, value=<optimized out>, name=0x555555d15308
"realized
", errp=0x7fffffffbd20) at qom/object.c:1390
#10 0x0000555555af13b2 in virtio_pci_realize (pci_dev=0x5555575eb800,
errp=0x7fffffffbd20) at hw/virtio/virtio-pci.c:1807
#11 0x0000555555a7a14b in pci_qdev_realize (qdev=<optimized out>,
errp=<optimized out>) at hw/pci/pci.c:2098
#12 0x00005555559dc842 in device_set_realized (obj=<optimized out>,
value=<optimized out>, errp=0x7fffffffbef8)
at hw/core/qdev.c:891
(gdb) p s
$23 = (SocketChardev *) 0x55555751ee00
(gdb) p s->state
$24 = TCP_CHARDEV_STATE_DISCONNECTED
At 410 line of char-socket.c, the state has been changed to
TCP_CHARDEV_STATE_DISCONNECTED before tcp_chr_change_state(s,
TCP_CHARDEV_STATE_DISCONNECTED);
It means the tcp_chr_disconnect_locked is called by more than one
times, and the tcp socket has been freed before.
The crash reason is s->reconnect_timer is set in the previous call of
tcp_chr_disconnect_locked.
The another approach fix maybe like this:
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 185fe38dda..94957de367 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -486,7 +486,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
if (emit_close) {
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
- if (s->reconnect_time) {
+ if (s->reconnect_time && !s->reconnect_timer) {
qemu_chr_socket_restart_timer(chr);
}
}
The base code is here:
474 static void tcp_chr_disconnect_locked(Chardev *chr)
475 {
476 SocketChardev *s = SOCKET_CHARDEV(chr);
477 bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
478
479 tcp_chr_free_connection(chr);
480
481 if (s->listener) {
482 qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept,
483 chr, NULL, chr->gcontext);
484 }
485 update_disconnected_filename(s);
486 if (emit_close) {
487 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
488 }
489 if (s->reconnect_time) {
490 qemu_chr_socket_restart_timer(chr);
491 }
492 }
Which one is better?
I don't know how to inject an error at socket write when writing tests
code(tests/test-char.c ).
Any tips?
Thanks,
Feng Li
Marc-André Lureau <marcandre.lureau@gmail.com> 于2020年4月15日周三 下午6:35写道:
>
> Hi
>
> On Wed, Apr 15, 2020 at 5:31 AM Li Feng <fengli@smartx.com> wrote:
> >
> > double call tcp_chr_free_connection generates a crash.
> >
> > Signed-off-by: Li Feng <fengli@smartx.com>
>
> Could you describe how you reach the "double call".
>
> Even better would be to write a test for it in tests/test-char.c
>
> thanks
>
> > ---
> > chardev/char-socket.c | 5 +++++
> > 1 file changed, 5 insertions(+)
> >
> > diff --git a/chardev/char-socket.c b/chardev/char-socket.c
> > index 185fe38dda..43aab8f24b 100644
> > --- a/chardev/char-socket.c
> > +++ b/chardev/char-socket.c
> > @@ -476,6 +476,11 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
> > SocketChardev *s = SOCKET_CHARDEV(chr);
> > bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
> >
> > + /* avoid re-enter when socket read/write error and disconnect event. */
> > + if (s->state == TCP_CHARDEV_STATE_DISCONNECTED) {
> > + return;
> > + }
> > +
> > tcp_chr_free_connection(chr);
> >
> > if (s->listener) {
> > --
> > 2.11.0
> >
> >
> > --
> > The SmartX email address is only for business purpose. Any sent message
> > that is not related to the business is not authorized or permitted by
> > SmartX.
> > 本邮箱为北京志凌海纳科技有限公司(SmartX)工作邮箱. 如本邮箱发出的邮件与工作无关,该邮件未得到本公司任何的明示或默示的授权.
> >
> >
> >
>
>
> --
> Marc-André Lureau
--
The SmartX email address is only for business purpose. Any sent message
that is not related to the business is not authorized or permitted by
SmartX.
本邮箱为北京志凌海纳科技有限公司(SmartX)工作邮箱. 如本邮箱发出的邮件与工作无关,该邮件未得到本公司任何的明示或默示的授权.
Hi
On Mon, Apr 20, 2020 at 5:10 AM Li Feng <fengli@smartx.com> wrote:
>
> Hi Lureau,
>
> Thanks for your comment.
> I have spent some time to reproduce this crash, so that delay my
> reply, apologies.
>
> This is the description of this bug using gdb:
> 1. Set break points using gdb;
> b chardev/char-socket.c:410 if s->state == TCP_CHARDEV_STATE_DISCONNECTED
> b break vhost_user_write
>
> 2. hotplug a vhost-blk device:
> echo "chardev-add
> socket,id=spdk_vhost_blk2,path=/vhost-blk.0,reconnect=1 "| nc -U
> /tmp/a.socket
> echo "device_add
> vhost-user-blk-pci,chardev=spdk_vhost_blk2,id=spdk_vhost_blk2,num-queues=4"
> | nc -U /tmp/a.socket
>
> 3. Gdb will stop at vhost_user_write, and CTRL-C the vhost target.
> 4. Put 'c' to let gdb continue.
> You will see a crash:
>
> 192 login: qemu-system-x86_64: chardev/char-socket.c:125:
> qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed.
>
> The related code:
> 394 static void tcp_chr_free_connection(Chardev *chr)
> 395 {
> 396 SocketChardev *s = SOCKET_CHARDEV(chr);
> 397 int i;
> 398
> 399 if (s->read_msgfds_num) {
> 400 for (i = 0; i < s->read_msgfds_num; i++) {
> 401 close(s->read_msgfds[i]);
> 402 }
> 403 g_free(s->read_msgfds);
> 404 s->read_msgfds = NULL;
> 405 s->read_msgfds_num = 0;
> 406 }
> 407
> 408 remove_hup_source(s);
> 409
> 410 tcp_set_msgfds(chr, NULL, 0);
> 411 remove_fd_in_watch(chr);
> 412 object_unref(OBJECT(s->sioc));
> 413 s->sioc = NULL;
> 414 object_unref(OBJECT(s->ioc));
> 415 s->ioc = NULL;
> 416 g_free(chr->filename);
> 417 chr->filename = NULL;
> 418 tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED);
> 419 }
>
> #0 0x0000555555c1aae8 in tcp_chr_free_connection
> (chr=chr@entry=0x55555751ee00) at chardev/char-socket.c:410
> #1 0x0000555555c1aec8 in tcp_chr_disconnect_locked
> (chr=0x55555751ee00) at chardev/char-socket.c:479
> #2 0x0000555555c1af5d in tcp_chr_disconnect (chr=0x55555751ee00) at
> chardev/char-socket.c:497
> #3 0x0000555555c16715 in qemu_chr_fe_set_handlers
> (b=b@entry=0x5555575f3b48, fd_can_read=fd_can_read@entry=0x0,
> fd_read=fd_
> read@entry=0x0, fd_event=fd_event@entry=0x55555588e740
> <vhost_user_blk_event>, be_change=be_change@entry=0x0, opaque=opaque@
> entry=0x5555575f3990, context=0x0, set_open=true) at chardev/char-fe.c:304
> #4 0x000055555588e5c0 in vhost_user_blk_device_realize
> (dev=0x5555575f3990, errp=<optimized out>)
> at /root/qemu-master/hw/block/vhost-user-blk.c:447
> #5 0x00005555558ca478 in virtio_device_realize (dev=0x5555575f3990,
> errp=0x7fffffffbb90)
> at /root/qemu-master/hw/virtio/virtio.c:3615
> #6 0x00005555559dc842 in device_set_realized (obj=<optimized out>,
> value=<optimized out>, errp=0x7fffffffbd20)
> at hw/core/qdev.c:891
> #7 0x0000555555b78e07 in property_set_bool (obj=0x5555575f3990,
> v=<optimized out>, name=<optimized out>, opaque=0x555556453
> 040, errp=0x7fffffffbd20) at qom/object.c:2238
> #8 0x0000555555b7db3f in object_property_set_qobject
> (obj=obj@entry=0x5555575f3990, value=value@entry=0x555556ab89c0, name=
> name@entry=0x555555d15308 "realized", errp=errp@entry=0x7fffffffbd20)
> at qom/qom-qobject.c:26
> #9 0x0000555555b7b2c5 in object_property_set_bool
> (obj=0x5555575f3990, value=<optimized out>, name=0x555555d15308
> "realized
> ", errp=0x7fffffffbd20) at qom/object.c:1390
> #10 0x0000555555af13b2 in virtio_pci_realize (pci_dev=0x5555575eb800,
> errp=0x7fffffffbd20) at hw/virtio/virtio-pci.c:1807
> #11 0x0000555555a7a14b in pci_qdev_realize (qdev=<optimized out>,
> errp=<optimized out>) at hw/pci/pci.c:2098
> #12 0x00005555559dc842 in device_set_realized (obj=<optimized out>,
> value=<optimized out>, errp=0x7fffffffbef8)
> at hw/core/qdev.c:891
>
> (gdb) p s
> $23 = (SocketChardev *) 0x55555751ee00
> (gdb) p s->state
> $24 = TCP_CHARDEV_STATE_DISCONNECTED
>
> At 410 line of char-socket.c, the state has been changed to
> TCP_CHARDEV_STATE_DISCONNECTED before tcp_chr_change_state(s,
> TCP_CHARDEV_STATE_DISCONNECTED);
> It means the tcp_chr_disconnect_locked is called by more than one
> times, and the tcp socket has been freed before.
>
> The crash reason is s->reconnect_timer is set in the previous call of
> tcp_chr_disconnect_locked.
> The another approach fix maybe like this:
>
> diff --git a/chardev/char-socket.c b/chardev/char-socket.c
> index 185fe38dda..94957de367 100644
> --- a/chardev/char-socket.c
> +++ b/chardev/char-socket.c
> @@ -486,7 +486,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
> if (emit_close) {
> qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
> }
> - if (s->reconnect_time) {
> + if (s->reconnect_time && !s->reconnect_timer) {
> qemu_chr_socket_restart_timer(chr);
> }
> }
>
> The base code is here:
> 474 static void tcp_chr_disconnect_locked(Chardev *chr)
> 475 {
> 476 SocketChardev *s = SOCKET_CHARDEV(chr);
> 477 bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
> 478
> 479 tcp_chr_free_connection(chr);
> 480
> 481 if (s->listener) {
> 482 qio_net_listener_set_client_func_full(s->listener, tcp_chr_accept,
> 483 chr, NULL, chr->gcontext);
> 484 }
> 485 update_disconnected_filename(s);
> 486 if (emit_close) {
> 487 qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
> 488 }
> 489 if (s->reconnect_time) {
> 490 qemu_chr_socket_restart_timer(chr);
> 491 }
> 492 }
>
> Which one is better?
+ if (s->reconnect_time && !s->reconnect_timer)
Looks like a good solution to me.
>
> I don't know how to inject an error at socket write when writing tests
> code(tests/test-char.c ).
> Any tips?
You could check the patch I just sent fixing a related issue:
https://patchew.org/QEMU/20200420112012.567284-1-marcandre.lureau@redhat.com/
In your case, it might be as easy as calling qemu_chr_fe_disconnect()
2 times on a reconnect socket, I'll let you figure out.
Thanks!
>
> Thanks,
> Feng Li
>
> Marc-André Lureau <marcandre.lureau@gmail.com> 于2020年4月15日周三 下午6:35写道:
>
> >
> > Hi
> >
> > On Wed, Apr 15, 2020 at 5:31 AM Li Feng <fengli@smartx.com> wrote:
> > >
> > > double call tcp_chr_free_connection generates a crash.
> > >
> > > Signed-off-by: Li Feng <fengli@smartx.com>
> >
> > Could you describe how you reach the "double call".
> >
> > Even better would be to write a test for it in tests/test-char.c
> >
> > thanks
> >
> > > ---
> > > chardev/char-socket.c | 5 +++++
> > > 1 file changed, 5 insertions(+)
> > >
> > > diff --git a/chardev/char-socket.c b/chardev/char-socket.c
> > > index 185fe38dda..43aab8f24b 100644
> > > --- a/chardev/char-socket.c
> > > +++ b/chardev/char-socket.c
> > > @@ -476,6 +476,11 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
> > > SocketChardev *s = SOCKET_CHARDEV(chr);
> > > bool emit_close = s->state == TCP_CHARDEV_STATE_CONNECTED;
> > >
> > > + /* avoid re-enter when socket read/write error and disconnect event. */
> > > + if (s->state == TCP_CHARDEV_STATE_DISCONNECTED) {
> > > + return;
> > > + }
> > > +
> > > tcp_chr_free_connection(chr);
> > >
> > > if (s->listener) {
> > > --
> > > 2.11.0
> > >
> > >
> > > --
> > > The SmartX email address is only for business purpose. Any sent message
> > > that is not related to the business is not authorized or permitted by
> > > SmartX.
> > > 本邮箱为北京志凌海纳科技有限公司(SmartX)工作邮箱. 如本邮箱发出的邮件与工作无关,该邮件未得到本公司任何的明示或默示的授权.
> > >
> > >
> > >
> >
> >
> > --
> > Marc-André Lureau
>
> --
> The SmartX email address is only for business purpose. Any sent message
> that is not related to the business is not authorized or permitted by
> SmartX.
> 本邮箱为北京志凌海纳科技有限公司(SmartX)工作邮箱. 如本邮箱发出的邮件与工作无关,该邮件未得到本公司任何的明示或默示的授权.
>
>
--
Marc-André Lureau
When the disconnect event is triggered in the connecting stage,
the tcp_chr_disconnect_locked may be called twice.
The first call:
#0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120
#1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490
#2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497
#3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892
#4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090
#5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196
#6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111
#7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190
#8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013
#9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152
The second call:
#0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6
#1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6
#2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6
#3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6
#4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125
#5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490
#6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497
#7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892
#8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944
#9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035
#10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023
Run test/test-char to reproduce this issue.
test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed.
Signed-off-by: Li Feng <fengli@smartx.com>
---
v2:
- Rewrite the solution.
- Add test to reproduce this issue.
chardev/char-socket.c | 2 +-
tests/test-char.c | 48 ++++++++++++++++++++++++++++++++++++++----------
2 files changed, 39 insertions(+), 11 deletions(-)
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 1f14c2c7c8..d84330b3c9 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -486,7 +486,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
if (emit_close) {
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
- if (s->reconnect_time) {
+ if (s->reconnect_time && !s->reconnect_timer) {
qemu_chr_socket_restart_timer(chr);
}
}
diff --git a/tests/test-char.c b/tests/test-char.c
index 8d39bdc9fa..13dbbfe2a3 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -625,12 +625,14 @@ static void char_udp_test(void)
typedef struct {
int event;
bool got_pong;
+ CharBackend *be;
} CharSocketTestData;
#define SOCKET_PING "Hello"
#define SOCKET_PONG "World"
+typedef void (*char_socket_cb)(void *opaque, QEMUChrEvent event);
static void
char_socket_event(void *opaque, QEMUChrEvent event)
@@ -639,6 +641,23 @@ char_socket_event(void *opaque, QEMUChrEvent event)
data->event = event;
}
+static void
+char_socket_event_with_error(void *opaque, QEMUChrEvent event)
+{
+ CharSocketTestData *data = opaque;
+ CharBackend *be = data->be;
+ data->event = event;
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ qemu_chr_fe_disconnect(be);
+ return;
+ case CHR_EVENT_CLOSED:
+ return;
+ default:
+ return;
+ }
+}
+
static void
char_socket_read(void *opaque, const uint8_t *buf, int size)
@@ -783,6 +802,7 @@ static void char_socket_server_test(gconstpointer opaque)
reconnect:
data.event = -1;
+ data.be = &be;
qemu_chr_fe_set_handlers(&be, NULL, NULL,
char_socket_event, NULL,
&data, NULL, true);
@@ -869,6 +889,7 @@ typedef struct {
const char *reconnect;
bool wait_connected;
bool fd_pass;
+ char_socket_cb event_cb;
} CharSocketClientTestConfig;
static void char_socket_client_dupid_test(gconstpointer opaque)
@@ -920,6 +941,7 @@ static void char_socket_client_dupid_test(gconstpointer opaque)
static void char_socket_client_test(gconstpointer opaque)
{
const CharSocketClientTestConfig *config = opaque;
+ const char_socket_cb event_cb = config->event_cb;
QIOChannelSocket *ioc;
char *optstr;
Chardev *chr;
@@ -983,8 +1005,9 @@ static void char_socket_client_test(gconstpointer opaque)
reconnect:
data.event = -1;
+ data.be = &be;
qemu_chr_fe_set_handlers(&be, NULL, NULL,
- char_socket_event, NULL,
+ event_cb, NULL,
&data, NULL, true);
if (config->reconnect) {
g_assert(data.event == -1);
@@ -1022,7 +1045,7 @@ static void char_socket_client_test(gconstpointer opaque)
/* Setup a callback to receive the reply to our greeting */
qemu_chr_fe_set_handlers(&be, char_socket_can_read,
char_socket_read,
- char_socket_event, NULL,
+ event_cb, NULL,
&data, NULL, true);
g_assert(data.event == CHR_EVENT_OPENED);
data.event = -1;
@@ -1467,19 +1490,22 @@ int main(int argc, char **argv)
#define SOCKET_CLIENT_TEST(name, addr) \
static CharSocketClientTestConfig client1 ## name = \
- { addr, NULL, false, false }; \
+ { addr, NULL, false, false, char_socket_event}; \
static CharSocketClientTestConfig client2 ## name = \
- { addr, NULL, true, false }; \
+ { addr, NULL, true, false, char_socket_event }; \
static CharSocketClientTestConfig client3 ## name = \
- { addr, ",reconnect=1", false }; \
+ { addr, ",reconnect=1", false, false, char_socket_event }; \
static CharSocketClientTestConfig client4 ## name = \
- { addr, ",reconnect=1", true }; \
+ { addr, ",reconnect=1", true, false, char_socket_event }; \
static CharSocketClientTestConfig client5 ## name = \
- { addr, NULL, false, true }; \
+ { addr, NULL, false, true, char_socket_event }; \
static CharSocketClientTestConfig client6 ## name = \
- { addr, NULL, true, true }; \
+ { addr, NULL, true, true, char_socket_event }; \
static CharSocketClientTestConfig client7 ## name = \
- { addr, ",reconnect=1", false, false }; \
+ { addr, ",reconnect=1", false, false, char_socket_event }; \
+ static CharSocketClientTestConfig client8 ## name = \
+ { addr, ",reconnect=1", true, false, \
+ char_socket_event_with_error }; \
g_test_add_data_func("/char/socket/client/mainloop/" # name, \
&client1 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/wait-conn/" # name, \
@@ -1493,7 +1519,9 @@ int main(int argc, char **argv)
g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \
&client6 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \
- &client7 ##name, char_socket_client_dupid_test)
+ &client7 ##name, char_socket_client_dupid_test);\
+ g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \
+ &client8 ##name, char_socket_client_test)
if (has_ipv4) {
SOCKET_SERVER_TEST(tcp, &tcpaddr);
--
2.11.0
When the disconnect event is triggered in the connecting stage,
the tcp_chr_disconnect_locked may be called twice.
The first call:
#0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120
#1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490
#2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497
#3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892
#4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090
#5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196
#6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111
#7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190
#8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013
#9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152
The second call:
#0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6
#1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6
#2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6
#3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6
#4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125
#5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490
#6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497
#7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892
#8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944
#9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035
#10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023
Run test/test-char to reproduce this issue.
test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed.
Signed-off-by: Li Feng <fengli@smartx.com>
---
v2:
- Rewrite the solution.
- Add test to reproduce this issue.
chardev/char-socket.c | 2 +-
tests/test-char.c | 48 ++++++++++++++++++++++++++++++++++++++----------
2 files changed, 39 insertions(+), 11 deletions(-)
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 1f14c2c7c8..d84330b3c9 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -486,7 +486,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
if (emit_close) {
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
}
- if (s->reconnect_time) {
+ if (s->reconnect_time && !s->reconnect_timer) {
qemu_chr_socket_restart_timer(chr);
}
}
diff --git a/tests/test-char.c b/tests/test-char.c
index 8d39bdc9fa..13dbbfe2a3 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -625,12 +625,14 @@ static void char_udp_test(void)
typedef struct {
int event;
bool got_pong;
+ CharBackend *be;
} CharSocketTestData;
#define SOCKET_PING "Hello"
#define SOCKET_PONG "World"
+typedef void (*char_socket_cb)(void *opaque, QEMUChrEvent event);
static void
char_socket_event(void *opaque, QEMUChrEvent event)
@@ -639,6 +641,23 @@ char_socket_event(void *opaque, QEMUChrEvent event)
data->event = event;
}
+static void
+char_socket_event_with_error(void *opaque, QEMUChrEvent event)
+{
+ CharSocketTestData *data = opaque;
+ CharBackend *be = data->be;
+ data->event = event;
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ qemu_chr_fe_disconnect(be);
+ return;
+ case CHR_EVENT_CLOSED:
+ return;
+ default:
+ return;
+ }
+}
+
static void
char_socket_read(void *opaque, const uint8_t *buf, int size)
@@ -783,6 +802,7 @@ static void char_socket_server_test(gconstpointer opaque)
reconnect:
data.event = -1;
+ data.be = &be;
qemu_chr_fe_set_handlers(&be, NULL, NULL,
char_socket_event, NULL,
&data, NULL, true);
@@ -869,6 +889,7 @@ typedef struct {
const char *reconnect;
bool wait_connected;
bool fd_pass;
+ char_socket_cb event_cb;
} CharSocketClientTestConfig;
static void char_socket_client_dupid_test(gconstpointer opaque)
@@ -920,6 +941,7 @@ static void char_socket_client_dupid_test(gconstpointer opaque)
static void char_socket_client_test(gconstpointer opaque)
{
const CharSocketClientTestConfig *config = opaque;
+ const char_socket_cb event_cb = config->event_cb;
QIOChannelSocket *ioc;
char *optstr;
Chardev *chr;
@@ -983,8 +1005,9 @@ static void char_socket_client_test(gconstpointer opaque)
reconnect:
data.event = -1;
+ data.be = &be;
qemu_chr_fe_set_handlers(&be, NULL, NULL,
- char_socket_event, NULL,
+ event_cb, NULL,
&data, NULL, true);
if (config->reconnect) {
g_assert(data.event == -1);
@@ -1022,7 +1045,7 @@ static void char_socket_client_test(gconstpointer opaque)
/* Setup a callback to receive the reply to our greeting */
qemu_chr_fe_set_handlers(&be, char_socket_can_read,
char_socket_read,
- char_socket_event, NULL,
+ event_cb, NULL,
&data, NULL, true);
g_assert(data.event == CHR_EVENT_OPENED);
data.event = -1;
@@ -1467,19 +1490,22 @@ int main(int argc, char **argv)
#define SOCKET_CLIENT_TEST(name, addr) \
static CharSocketClientTestConfig client1 ## name = \
- { addr, NULL, false, false }; \
+ { addr, NULL, false, false, char_socket_event}; \
static CharSocketClientTestConfig client2 ## name = \
- { addr, NULL, true, false }; \
+ { addr, NULL, true, false, char_socket_event }; \
static CharSocketClientTestConfig client3 ## name = \
- { addr, ",reconnect=1", false }; \
+ { addr, ",reconnect=1", false, false, char_socket_event }; \
static CharSocketClientTestConfig client4 ## name = \
- { addr, ",reconnect=1", true }; \
+ { addr, ",reconnect=1", true, false, char_socket_event }; \
static CharSocketClientTestConfig client5 ## name = \
- { addr, NULL, false, true }; \
+ { addr, NULL, false, true, char_socket_event }; \
static CharSocketClientTestConfig client6 ## name = \
- { addr, NULL, true, true }; \
+ { addr, NULL, true, true, char_socket_event }; \
static CharSocketClientTestConfig client7 ## name = \
- { addr, ",reconnect=1", false, false }; \
+ { addr, ",reconnect=1", false, false, char_socket_event }; \
+ static CharSocketClientTestConfig client8 ## name = \
+ { addr, ",reconnect=1", true, false, \
+ char_socket_event_with_error }; \
g_test_add_data_func("/char/socket/client/mainloop/" # name, \
&client1 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/wait-conn/" # name, \
@@ -1493,7 +1519,9 @@ int main(int argc, char **argv)
g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \
&client6 ##name, char_socket_client_test); \
g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \
- &client7 ##name, char_socket_client_dupid_test)
+ &client7 ##name, char_socket_client_dupid_test);\
+ g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \
+ &client8 ##name, char_socket_client_test)
if (has_ipv4) {
SOCKET_SERVER_TEST(tcp, &tcpaddr);
--
2.11.0
Sorry for sending the weird same mail out.
Ignore the second one.
Hi Lureau,
I found another issue when running my new test: tests/test-char -p
/char/socket/client/reconnect-error/unix
The backtrace like this:
#0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6
#1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6
#2 0x00005555555aaa34 in error_handle_fatal (errp=<optimized out>,
err=0x7fffec0012d0) at util/error.c:40
#3 0x00005555555aab0d in error_setv (errp=0x555555802a08
<error_abort>, src=0x5555555c4220 "io/channel.c", line=148,
func=0x5555555c4520 <__func__.17450> "qio_channel_readv_all",
err_class=ERROR_CLASS_GENERIC_ERROR, fmt=<optimized out>,
ap=0x7ffff423bb10, suffix=0x0) at util/error.c:73
#4 0x00005555555aac90 in error_setg_internal
(errp=errp@entry=0x555555802a08 <error_abort>,
src=src@entry=0x5555555c4220 "io/channel.c", line=line@entry=148,
func=func@entry=0x5555555c4520 <__func__.17450>
"qio_channel_readv_all", fmt=fmt@entry=0x5555555c4340 "Unexpected
end-of-file before all bytes were read") at util/error.c:97
#5 0x000055555556c1fc in qio_channel_readv_all (ioc=<optimized out>,
iov=<optimized out>, niov=<optimized out>, errp=0x555555802a08
<error_abort>) at io/channel.c:147
#6 0x000055555556c23a in qio_channel_read_all (ioc=<optimized out>,
buf=<optimized out>, buflen=<optimized out>, errp=<optimized out>) at
io/channel.c:247
#7 0x000055555556ad0e in char_socket_ping_pong (ioc=0x7fffec0008c0)
at tests/test-char.c:727
#8 0x000055555556adcf in char_socket_client_server_thread
(data=data@entry=0x55555582e350) at tests/test-char.c:881
#9 0x00005555555a9556 in qemu_thread_start (args=<optimized out>) at
util/qemu-thread-posix.c:519
#10 0x00007ffff5e61e25 in start_thread () from /lib64/libpthread.so.0
#11 0x00007ffff5b8bbad in clone () from /lib64/libc.so.6
I think this is a new issue of qemu, not my test issue.
How do you think?
Thanks,
Feng Li
Li Feng <fengli@smartx.com> 于2020年4月28日周二 下午4:53写道:
>
> When the disconnect event is triggered in the connecting stage,
> the tcp_chr_disconnect_locked may be called twice.
>
> The first call:
> #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120
> #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490
> #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497
> #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892
> #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090
> #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196
> #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111
> #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190
> #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013
> #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152
> The second call:
> #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6
> #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6
> #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6
> #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6
> #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125
> #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490
> #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497
> #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892
> #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944
> #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035
> #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023
>
> Run test/test-char to reproduce this issue.
>
> test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed.
>
> Signed-off-by: Li Feng <fengli@smartx.com>
> ---
> v2:
> - Rewrite the solution.
> - Add test to reproduce this issue.
>
> chardev/char-socket.c | 2 +-
> tests/test-char.c | 48 ++++++++++++++++++++++++++++++++++++++----------
> 2 files changed, 39 insertions(+), 11 deletions(-)
>
> diff --git a/chardev/char-socket.c b/chardev/char-socket.c
> index 1f14c2c7c8..d84330b3c9 100644
> --- a/chardev/char-socket.c
> +++ b/chardev/char-socket.c
> @@ -486,7 +486,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
> if (emit_close) {
> qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
> }
> - if (s->reconnect_time) {
> + if (s->reconnect_time && !s->reconnect_timer) {
> qemu_chr_socket_restart_timer(chr);
> }
> }
> diff --git a/tests/test-char.c b/tests/test-char.c
> index 8d39bdc9fa..13dbbfe2a3 100644
> --- a/tests/test-char.c
> +++ b/tests/test-char.c
> @@ -625,12 +625,14 @@ static void char_udp_test(void)
> typedef struct {
> int event;
> bool got_pong;
> + CharBackend *be;
> } CharSocketTestData;
>
>
> #define SOCKET_PING "Hello"
> #define SOCKET_PONG "World"
>
> +typedef void (*char_socket_cb)(void *opaque, QEMUChrEvent event);
>
> static void
> char_socket_event(void *opaque, QEMUChrEvent event)
> @@ -639,6 +641,23 @@ char_socket_event(void *opaque, QEMUChrEvent event)
> data->event = event;
> }
>
> +static void
> +char_socket_event_with_error(void *opaque, QEMUChrEvent event)
> +{
> + CharSocketTestData *data = opaque;
> + CharBackend *be = data->be;
> + data->event = event;
> + switch (event) {
> + case CHR_EVENT_OPENED:
> + qemu_chr_fe_disconnect(be);
> + return;
> + case CHR_EVENT_CLOSED:
> + return;
> + default:
> + return;
> + }
> +}
> +
>
> static void
> char_socket_read(void *opaque, const uint8_t *buf, int size)
> @@ -783,6 +802,7 @@ static void char_socket_server_test(gconstpointer opaque)
>
> reconnect:
> data.event = -1;
> + data.be = &be;
> qemu_chr_fe_set_handlers(&be, NULL, NULL,
> char_socket_event, NULL,
> &data, NULL, true);
> @@ -869,6 +889,7 @@ typedef struct {
> const char *reconnect;
> bool wait_connected;
> bool fd_pass;
> + char_socket_cb event_cb;
> } CharSocketClientTestConfig;
>
> static void char_socket_client_dupid_test(gconstpointer opaque)
> @@ -920,6 +941,7 @@ static void char_socket_client_dupid_test(gconstpointer opaque)
> static void char_socket_client_test(gconstpointer opaque)
> {
> const CharSocketClientTestConfig *config = opaque;
> + const char_socket_cb event_cb = config->event_cb;
> QIOChannelSocket *ioc;
> char *optstr;
> Chardev *chr;
> @@ -983,8 +1005,9 @@ static void char_socket_client_test(gconstpointer opaque)
>
> reconnect:
> data.event = -1;
> + data.be = &be;
> qemu_chr_fe_set_handlers(&be, NULL, NULL,
> - char_socket_event, NULL,
> + event_cb, NULL,
> &data, NULL, true);
> if (config->reconnect) {
> g_assert(data.event == -1);
> @@ -1022,7 +1045,7 @@ static void char_socket_client_test(gconstpointer opaque)
> /* Setup a callback to receive the reply to our greeting */
> qemu_chr_fe_set_handlers(&be, char_socket_can_read,
> char_socket_read,
> - char_socket_event, NULL,
> + event_cb, NULL,
> &data, NULL, true);
> g_assert(data.event == CHR_EVENT_OPENED);
> data.event = -1;
> @@ -1467,19 +1490,22 @@ int main(int argc, char **argv)
>
> #define SOCKET_CLIENT_TEST(name, addr) \
> static CharSocketClientTestConfig client1 ## name = \
> - { addr, NULL, false, false }; \
> + { addr, NULL, false, false, char_socket_event}; \
> static CharSocketClientTestConfig client2 ## name = \
> - { addr, NULL, true, false }; \
> + { addr, NULL, true, false, char_socket_event }; \
> static CharSocketClientTestConfig client3 ## name = \
> - { addr, ",reconnect=1", false }; \
> + { addr, ",reconnect=1", false, false, char_socket_event }; \
> static CharSocketClientTestConfig client4 ## name = \
> - { addr, ",reconnect=1", true }; \
> + { addr, ",reconnect=1", true, false, char_socket_event }; \
> static CharSocketClientTestConfig client5 ## name = \
> - { addr, NULL, false, true }; \
> + { addr, NULL, false, true, char_socket_event }; \
> static CharSocketClientTestConfig client6 ## name = \
> - { addr, NULL, true, true }; \
> + { addr, NULL, true, true, char_socket_event }; \
> static CharSocketClientTestConfig client7 ## name = \
> - { addr, ",reconnect=1", false, false }; \
> + { addr, ",reconnect=1", false, false, char_socket_event }; \
> + static CharSocketClientTestConfig client8 ## name = \
> + { addr, ",reconnect=1", true, false, \
> + char_socket_event_with_error }; \
> g_test_add_data_func("/char/socket/client/mainloop/" # name, \
> &client1 ##name, char_socket_client_test); \
> g_test_add_data_func("/char/socket/client/wait-conn/" # name, \
> @@ -1493,7 +1519,9 @@ int main(int argc, char **argv)
> g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \
> &client6 ##name, char_socket_client_test); \
> g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \
> - &client7 ##name, char_socket_client_dupid_test)
> + &client7 ##name, char_socket_client_dupid_test);\
> + g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \
> + &client8 ##name, char_socket_client_test)
>
> if (has_ipv4) {
> SOCKET_SERVER_TEST(tcp, &tcpaddr);
> --
> 2.11.0
>
Hi
On Tue, Apr 28, 2020 at 10:59 AM Li Feng <fengli@smartx.com> wrote:
>
> Sorry for sending the weird same mail out.
> Ignore the second one.
>
> Hi Lureau,
>
> I found another issue when running my new test: tests/test-char -p
> /char/socket/client/reconnect-error/unix
> The backtrace like this:
> #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6
> #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6
> #2 0x00005555555aaa34 in error_handle_fatal (errp=<optimized out>,
> err=0x7fffec0012d0) at util/error.c:40
> #3 0x00005555555aab0d in error_setv (errp=0x555555802a08
> <error_abort>, src=0x5555555c4220 "io/channel.c", line=148,
> func=0x5555555c4520 <__func__.17450> "qio_channel_readv_all",
> err_class=ERROR_CLASS_GENERIC_ERROR, fmt=<optimized out>,
> ap=0x7ffff423bb10, suffix=0x0) at util/error.c:73
> #4 0x00005555555aac90 in error_setg_internal
> (errp=errp@entry=0x555555802a08 <error_abort>,
> src=src@entry=0x5555555c4220 "io/channel.c", line=line@entry=148,
> func=func@entry=0x5555555c4520 <__func__.17450>
> "qio_channel_readv_all", fmt=fmt@entry=0x5555555c4340 "Unexpected
> end-of-file before all bytes were read") at util/error.c:97
> #5 0x000055555556c1fc in qio_channel_readv_all (ioc=<optimized out>,
> iov=<optimized out>, niov=<optimized out>, errp=0x555555802a08
> <error_abort>) at io/channel.c:147
> #6 0x000055555556c23a in qio_channel_read_all (ioc=<optimized out>,
> buf=<optimized out>, buflen=<optimized out>, errp=<optimized out>) at
> io/channel.c:247
> #7 0x000055555556ad0e in char_socket_ping_pong (ioc=0x7fffec0008c0)
> at tests/test-char.c:727
> #8 0x000055555556adcf in char_socket_client_server_thread
> (data=data@entry=0x55555582e350) at tests/test-char.c:881
> #9 0x00005555555a9556 in qemu_thread_start (args=<optimized out>) at
> util/qemu-thread-posix.c:519
> #10 0x00007ffff5e61e25 in start_thread () from /lib64/libpthread.so.0
> #11 0x00007ffff5b8bbad in clone () from /lib64/libc.so.6
>
> I think this is a new issue of qemu, not my test issue.
> How do you think?
No idea, it could be a bug in the test itself. How did you produce it?
>
> Thanks,
>
> Feng Li
>
> Li Feng <fengli@smartx.com> 于2020年4月28日周二 下午4:53写道:
>
> >
> > When the disconnect event is triggered in the connecting stage,
> > the tcp_chr_disconnect_locked may be called twice.
> >
> > The first call:
> > #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120
> > #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490
> > #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497
> > #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892
> > #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090
> > #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196
> > #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111
> > #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190
> > #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013
> > #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152
> > The second call:
> > #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6
> > #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6
> > #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6
> > #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6
> > #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125
> > #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490
> > #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497
> > #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892
> > #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944
> > #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035
> > #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023
> >
> > Run test/test-char to reproduce this issue.
> >
> > test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed.
> >
> > Signed-off-by: Li Feng <fengli@smartx.com>
> > ---
> > v2:
> > - Rewrite the solution.
> > - Add test to reproduce this issue.
> >
> > chardev/char-socket.c | 2 +-
> > tests/test-char.c | 48 ++++++++++++++++++++++++++++++++++++++----------
> > 2 files changed, 39 insertions(+), 11 deletions(-)
> >
> > diff --git a/chardev/char-socket.c b/chardev/char-socket.c
> > index 1f14c2c7c8..d84330b3c9 100644
> > --- a/chardev/char-socket.c
> > +++ b/chardev/char-socket.c
> > @@ -486,7 +486,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
> > if (emit_close) {
> > qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
> > }
> > - if (s->reconnect_time) {
> > + if (s->reconnect_time && !s->reconnect_timer) {
> > qemu_chr_socket_restart_timer(chr);
> > }
> > }
> > diff --git a/tests/test-char.c b/tests/test-char.c
> > index 8d39bdc9fa..13dbbfe2a3 100644
> > --- a/tests/test-char.c
> > +++ b/tests/test-char.c
> > @@ -625,12 +625,14 @@ static void char_udp_test(void)
> > typedef struct {
> > int event;
> > bool got_pong;
> > + CharBackend *be;
> > } CharSocketTestData;
> >
> >
> > #define SOCKET_PING "Hello"
> > #define SOCKET_PONG "World"
> >
> > +typedef void (*char_socket_cb)(void *opaque, QEMUChrEvent event);
> >
> > static void
> > char_socket_event(void *opaque, QEMUChrEvent event)
> > @@ -639,6 +641,23 @@ char_socket_event(void *opaque, QEMUChrEvent event)
> > data->event = event;
> > }
> >
> > +static void
> > +char_socket_event_with_error(void *opaque, QEMUChrEvent event)
> > +{
> > + CharSocketTestData *data = opaque;
> > + CharBackend *be = data->be;
> > + data->event = event;
> > + switch (event) {
> > + case CHR_EVENT_OPENED:
> > + qemu_chr_fe_disconnect(be);
> > + return;
> > + case CHR_EVENT_CLOSED:
> > + return;
> > + default:
> > + return;
> > + }
> > +}
> > +
> >
> > static void
> > char_socket_read(void *opaque, const uint8_t *buf, int size)
> > @@ -783,6 +802,7 @@ static void char_socket_server_test(gconstpointer opaque)
> >
> > reconnect:
> > data.event = -1;
> > + data.be = &be;
> > qemu_chr_fe_set_handlers(&be, NULL, NULL,
> > char_socket_event, NULL,
> > &data, NULL, true);
> > @@ -869,6 +889,7 @@ typedef struct {
> > const char *reconnect;
> > bool wait_connected;
> > bool fd_pass;
> > + char_socket_cb event_cb;
> > } CharSocketClientTestConfig;
> >
> > static void char_socket_client_dupid_test(gconstpointer opaque)
> > @@ -920,6 +941,7 @@ static void char_socket_client_dupid_test(gconstpointer opaque)
> > static void char_socket_client_test(gconstpointer opaque)
> > {
> > const CharSocketClientTestConfig *config = opaque;
> > + const char_socket_cb event_cb = config->event_cb;
> > QIOChannelSocket *ioc;
> > char *optstr;
> > Chardev *chr;
> > @@ -983,8 +1005,9 @@ static void char_socket_client_test(gconstpointer opaque)
> >
> > reconnect:
> > data.event = -1;
> > + data.be = &be;
> > qemu_chr_fe_set_handlers(&be, NULL, NULL,
> > - char_socket_event, NULL,
> > + event_cb, NULL,
> > &data, NULL, true);
> > if (config->reconnect) {
> > g_assert(data.event == -1);
> > @@ -1022,7 +1045,7 @@ static void char_socket_client_test(gconstpointer opaque)
> > /* Setup a callback to receive the reply to our greeting */
> > qemu_chr_fe_set_handlers(&be, char_socket_can_read,
> > char_socket_read,
> > - char_socket_event, NULL,
> > + event_cb, NULL,
> > &data, NULL, true);
> > g_assert(data.event == CHR_EVENT_OPENED);
> > data.event = -1;
> > @@ -1467,19 +1490,22 @@ int main(int argc, char **argv)
> >
> > #define SOCKET_CLIENT_TEST(name, addr) \
> > static CharSocketClientTestConfig client1 ## name = \
> > - { addr, NULL, false, false }; \
> > + { addr, NULL, false, false, char_socket_event}; \
> > static CharSocketClientTestConfig client2 ## name = \
> > - { addr, NULL, true, false }; \
> > + { addr, NULL, true, false, char_socket_event }; \
> > static CharSocketClientTestConfig client3 ## name = \
> > - { addr, ",reconnect=1", false }; \
> > + { addr, ",reconnect=1", false, false, char_socket_event }; \
> > static CharSocketClientTestConfig client4 ## name = \
> > - { addr, ",reconnect=1", true }; \
> > + { addr, ",reconnect=1", true, false, char_socket_event }; \
> > static CharSocketClientTestConfig client5 ## name = \
> > - { addr, NULL, false, true }; \
> > + { addr, NULL, false, true, char_socket_event }; \
> > static CharSocketClientTestConfig client6 ## name = \
> > - { addr, NULL, true, true }; \
> > + { addr, NULL, true, true, char_socket_event }; \
> > static CharSocketClientTestConfig client7 ## name = \
> > - { addr, ",reconnect=1", false, false }; \
> > + { addr, ",reconnect=1", false, false, char_socket_event }; \
> > + static CharSocketClientTestConfig client8 ## name = \
> > + { addr, ",reconnect=1", true, false, \
> > + char_socket_event_with_error }; \
> > g_test_add_data_func("/char/socket/client/mainloop/" # name, \
> > &client1 ##name, char_socket_client_test); \
> > g_test_add_data_func("/char/socket/client/wait-conn/" # name, \
> > @@ -1493,7 +1519,9 @@ int main(int argc, char **argv)
> > g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \
> > &client6 ##name, char_socket_client_test); \
> > g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \
> > - &client7 ##name, char_socket_client_dupid_test)
> > + &client7 ##name, char_socket_client_dupid_test);\
> > + g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \
> > + &client8 ##name, char_socket_client_test)
> >
> > if (has_ipv4) {
> > SOCKET_SERVER_TEST(tcp, &tcpaddr);
> > --
> > 2.11.0
> >
>
Apply the above patch, then `make check-unit`
or
`tests/test-char -p /char/socket/client/reconnect-error/unix`
Marc-André Lureau <marcandre.lureau@redhat.com> 于2020年4月28日周二 下午7:06写道:
>
> Hi
>
> On Tue, Apr 28, 2020 at 10:59 AM Li Feng <fengli@smartx.com> wrote:
> >
> > Sorry for sending the weird same mail out.
> > Ignore the second one.
> >
> > Hi Lureau,
> >
> > I found another issue when running my new test: tests/test-char -p
> > /char/socket/client/reconnect-error/unix
> > The backtrace like this:
> > #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6
> > #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6
> > #2 0x00005555555aaa34 in error_handle_fatal (errp=<optimized out>,
> > err=0x7fffec0012d0) at util/error.c:40
> > #3 0x00005555555aab0d in error_setv (errp=0x555555802a08
> > <error_abort>, src=0x5555555c4220 "io/channel.c", line=148,
> > func=0x5555555c4520 <__func__.17450> "qio_channel_readv_all",
> > err_class=ERROR_CLASS_GENERIC_ERROR, fmt=<optimized out>,
> > ap=0x7ffff423bb10, suffix=0x0) at util/error.c:73
> > #4 0x00005555555aac90 in error_setg_internal
> > (errp=errp@entry=0x555555802a08 <error_abort>,
> > src=src@entry=0x5555555c4220 "io/channel.c", line=line@entry=148,
> > func=func@entry=0x5555555c4520 <__func__.17450>
> > "qio_channel_readv_all", fmt=fmt@entry=0x5555555c4340 "Unexpected
> > end-of-file before all bytes were read") at util/error.c:97
> > #5 0x000055555556c1fc in qio_channel_readv_all (ioc=<optimized out>,
> > iov=<optimized out>, niov=<optimized out>, errp=0x555555802a08
> > <error_abort>) at io/channel.c:147
> > #6 0x000055555556c23a in qio_channel_read_all (ioc=<optimized out>,
> > buf=<optimized out>, buflen=<optimized out>, errp=<optimized out>) at
> > io/channel.c:247
> > #7 0x000055555556ad0e in char_socket_ping_pong (ioc=0x7fffec0008c0)
> > at tests/test-char.c:727
> > #8 0x000055555556adcf in char_socket_client_server_thread
> > (data=data@entry=0x55555582e350) at tests/test-char.c:881
> > #9 0x00005555555a9556 in qemu_thread_start (args=<optimized out>) at
> > util/qemu-thread-posix.c:519
> > #10 0x00007ffff5e61e25 in start_thread () from /lib64/libpthread.so.0
> > #11 0x00007ffff5b8bbad in clone () from /lib64/libc.so.6
> >
> > I think this is a new issue of qemu, not my test issue.
> > How do you think?
>
>
> No idea, it could be a bug in the test itself. How did you produce it?
>
> >
> > Thanks,
> >
> > Feng Li
> >
> > Li Feng <fengli@smartx.com> 于2020年4月28日周二 下午4:53写道:
> >
> > >
> > > When the disconnect event is triggered in the connecting stage,
> > > the tcp_chr_disconnect_locked may be called twice.
> > >
> > > The first call:
> > > #0 qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:120
> > > #1 0x000055555558e38c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490
> > > #2 0x000055555558e3cd in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497
> > > #3 0x000055555558ea32 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892
> > > #4 0x000055555558eeb8 in qemu_chr_socket_connected (task=0x55555582f300, opaque=<optimized out>) at chardev/char-socket.c:1090
> > > #5 0x0000555555574352 in qio_task_complete (task=task@entry=0x55555582f300) at io/task.c:196
> > > #6 0x00005555555745f4 in qio_task_thread_result (opaque=0x55555582f300) at io/task.c:111
> > > #7 qio_task_wait_thread (task=0x55555582f300) at io/task.c:190
> > > #8 0x000055555558f17e in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1013
> > > #9 0x0000555555567cbd in char_socket_client_reconnect_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1152
> > > The second call:
> > > #0 0x00007ffff5ac3277 in raise () from /lib64/libc.so.6
> > > #1 0x00007ffff5ac4968 in abort () from /lib64/libc.so.6
> > > #2 0x00007ffff5abc096 in __assert_fail_base () from /lib64/libc.so.6
> > > #3 0x00007ffff5abc142 in __assert_fail () from /lib64/libc.so.6
> > > #4 0x000055555558d10a in qemu_chr_socket_restart_timer (chr=0x55555582ee90) at chardev/char-socket.c:125
> > > #5 0x000055555558df0c in tcp_chr_disconnect_locked (chr=<optimized out>) at chardev/char-socket.c:490
> > > #6 0x000055555558df4d in tcp_chr_disconnect (chr=0x55555582ee90) at chardev/char-socket.c:497
> > > #7 0x000055555558e5b2 in tcp_chr_new_client (chr=chr@entry=0x55555582ee90, sioc=sioc@entry=0x55555582f0b0) at chardev/char-socket.c:892
> > > #8 0x000055555558e93a in tcp_chr_connect_client_sync (chr=chr@entry=0x55555582ee90, errp=errp@entry=0x7fffffffd178) at chardev/char-socket.c:944
> > > #9 0x000055555558ec78 in tcp_chr_wait_connected (chr=0x55555582ee90, errp=0x555555802a08 <error_abort>) at chardev/char-socket.c:1035
> > > #10 0x000055555556804b in char_socket_client_test (opaque=0x5555557fe020 <client8unix>) at tests/test-char.c:1023
> > >
> > > Run test/test-char to reproduce this issue.
> > >
> > > test-char: chardev/char-socket.c:125: qemu_chr_socket_restart_timer: Assertion `!s->reconnect_timer' failed.
> > >
> > > Signed-off-by: Li Feng <fengli@smartx.com>
> > > ---
> > > v2:
> > > - Rewrite the solution.
> > > - Add test to reproduce this issue.
> > >
> > > chardev/char-socket.c | 2 +-
> > > tests/test-char.c | 48 ++++++++++++++++++++++++++++++++++++++----------
> > > 2 files changed, 39 insertions(+), 11 deletions(-)
> > >
> > > diff --git a/chardev/char-socket.c b/chardev/char-socket.c
> > > index 1f14c2c7c8..d84330b3c9 100644
> > > --- a/chardev/char-socket.c
> > > +++ b/chardev/char-socket.c
> > > @@ -486,7 +486,7 @@ static void tcp_chr_disconnect_locked(Chardev *chr)
> > > if (emit_close) {
> > > qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
> > > }
> > > - if (s->reconnect_time) {
> > > + if (s->reconnect_time && !s->reconnect_timer) {
> > > qemu_chr_socket_restart_timer(chr);
> > > }
> > > }
> > > diff --git a/tests/test-char.c b/tests/test-char.c
> > > index 8d39bdc9fa..13dbbfe2a3 100644
> > > --- a/tests/test-char.c
> > > +++ b/tests/test-char.c
> > > @@ -625,12 +625,14 @@ static void char_udp_test(void)
> > > typedef struct {
> > > int event;
> > > bool got_pong;
> > > + CharBackend *be;
> > > } CharSocketTestData;
> > >
> > >
> > > #define SOCKET_PING "Hello"
> > > #define SOCKET_PONG "World"
> > >
> > > +typedef void (*char_socket_cb)(void *opaque, QEMUChrEvent event);
> > >
> > > static void
> > > char_socket_event(void *opaque, QEMUChrEvent event)
> > > @@ -639,6 +641,23 @@ char_socket_event(void *opaque, QEMUChrEvent event)
> > > data->event = event;
> > > }
> > >
> > > +static void
> > > +char_socket_event_with_error(void *opaque, QEMUChrEvent event)
> > > +{
> > > + CharSocketTestData *data = opaque;
> > > + CharBackend *be = data->be;
> > > + data->event = event;
> > > + switch (event) {
> > > + case CHR_EVENT_OPENED:
> > > + qemu_chr_fe_disconnect(be);
> > > + return;
> > > + case CHR_EVENT_CLOSED:
> > > + return;
> > > + default:
> > > + return;
> > > + }
> > > +}
> > > +
> > >
> > > static void
> > > char_socket_read(void *opaque, const uint8_t *buf, int size)
> > > @@ -783,6 +802,7 @@ static void char_socket_server_test(gconstpointer opaque)
> > >
> > > reconnect:
> > > data.event = -1;
> > > + data.be = &be;
> > > qemu_chr_fe_set_handlers(&be, NULL, NULL,
> > > char_socket_event, NULL,
> > > &data, NULL, true);
> > > @@ -869,6 +889,7 @@ typedef struct {
> > > const char *reconnect;
> > > bool wait_connected;
> > > bool fd_pass;
> > > + char_socket_cb event_cb;
> > > } CharSocketClientTestConfig;
> > >
> > > static void char_socket_client_dupid_test(gconstpointer opaque)
> > > @@ -920,6 +941,7 @@ static void char_socket_client_dupid_test(gconstpointer opaque)
> > > static void char_socket_client_test(gconstpointer opaque)
> > > {
> > > const CharSocketClientTestConfig *config = opaque;
> > > + const char_socket_cb event_cb = config->event_cb;
> > > QIOChannelSocket *ioc;
> > > char *optstr;
> > > Chardev *chr;
> > > @@ -983,8 +1005,9 @@ static void char_socket_client_test(gconstpointer opaque)
> > >
> > > reconnect:
> > > data.event = -1;
> > > + data.be = &be;
> > > qemu_chr_fe_set_handlers(&be, NULL, NULL,
> > > - char_socket_event, NULL,
> > > + event_cb, NULL,
> > > &data, NULL, true);
> > > if (config->reconnect) {
> > > g_assert(data.event == -1);
> > > @@ -1022,7 +1045,7 @@ static void char_socket_client_test(gconstpointer opaque)
> > > /* Setup a callback to receive the reply to our greeting */
> > > qemu_chr_fe_set_handlers(&be, char_socket_can_read,
> > > char_socket_read,
> > > - char_socket_event, NULL,
> > > + event_cb, NULL,
> > > &data, NULL, true);
> > > g_assert(data.event == CHR_EVENT_OPENED);
> > > data.event = -1;
> > > @@ -1467,19 +1490,22 @@ int main(int argc, char **argv)
> > >
> > > #define SOCKET_CLIENT_TEST(name, addr) \
> > > static CharSocketClientTestConfig client1 ## name = \
> > > - { addr, NULL, false, false }; \
> > > + { addr, NULL, false, false, char_socket_event}; \
> > > static CharSocketClientTestConfig client2 ## name = \
> > > - { addr, NULL, true, false }; \
> > > + { addr, NULL, true, false, char_socket_event }; \
> > > static CharSocketClientTestConfig client3 ## name = \
> > > - { addr, ",reconnect=1", false }; \
> > > + { addr, ",reconnect=1", false, false, char_socket_event }; \
> > > static CharSocketClientTestConfig client4 ## name = \
> > > - { addr, ",reconnect=1", true }; \
> > > + { addr, ",reconnect=1", true, false, char_socket_event }; \
> > > static CharSocketClientTestConfig client5 ## name = \
> > > - { addr, NULL, false, true }; \
> > > + { addr, NULL, false, true, char_socket_event }; \
> > > static CharSocketClientTestConfig client6 ## name = \
> > > - { addr, NULL, true, true }; \
> > > + { addr, NULL, true, true, char_socket_event }; \
> > > static CharSocketClientTestConfig client7 ## name = \
> > > - { addr, ",reconnect=1", false, false }; \
> > > + { addr, ",reconnect=1", false, false, char_socket_event }; \
> > > + static CharSocketClientTestConfig client8 ## name = \
> > > + { addr, ",reconnect=1", true, false, \
> > > + char_socket_event_with_error }; \
> > > g_test_add_data_func("/char/socket/client/mainloop/" # name, \
> > > &client1 ##name, char_socket_client_test); \
> > > g_test_add_data_func("/char/socket/client/wait-conn/" # name, \
> > > @@ -1493,7 +1519,9 @@ int main(int argc, char **argv)
> > > g_test_add_data_func("/char/socket/client/wait-conn-fdpass/" # name, \
> > > &client6 ##name, char_socket_client_test); \
> > > g_test_add_data_func("/char/socket/client/dupid-reconnect/" # name, \
> > > - &client7 ##name, char_socket_client_dupid_test)
> > > + &client7 ##name, char_socket_client_dupid_test);\
> > > + g_test_add_data_func("/char/socket/client/reconnect-error/" # name, \
> > > + &client8 ##name, char_socket_client_test)
> > >
> > > if (has_ipv4) {
> > > SOCKET_SERVER_TEST(tcp, &tcpaddr);
> > > --
> > > 2.11.0
> > >
> >
>
© 2016 - 2026 Red Hat, Inc.