qemu_thread_create: propagate errors to callers to check
v5 cover qemu_thread_create: propagate errors to callers to check
Hi,
This idea comes from BiteSizedTasks, and this patch series implement the error checking of qemu_thread_create: make qemu_thread_create return a flag to indicate if it succeeded rather than failing with an error; make all callers check it.
The first three patches apply to those call traces whose further callers already have the *errp to pass, thus add a new Error paramater in the call trace to propagate the error and let the further caller check it. The last patch modifies the qemu_thread_create() and makes it return a bool to all direct callers to indicate if it succeeds. The middle three fix some segmentation fault when using GDB to debug.
###### Here I have a concern about using multifd migration. ###### It is about "[PATCH RFC v4 5/7] migration: fix the multifd code". In our current code, when multifd is used during migration, if there is an error before the destination receives all new channels (I mean multifd_recv_new_channel(ioc)), the destination does not exit but keeps waiting (Hang in recvmsg() in qio_channel_socket_readv) until the source exits. I know hang is not right, but so sorry that I did not come up with a good idea on handling this. Not so familiar with that part of code.. Hope @Juan could give a hand. Thanks!
Please help to review, thanks. :)
v5:
- Remove errno = err in qemu_thread_create() for Linux, and change return errno to return -1 in qemu_signal_init() to indicate the error in case qemu_thread_create() fails.
- Delete the v4-added qemu_cond/mutex_destroy() in iothread_complete() as the destroy() will be done by its callers' object_unref().
v4:
- Separate the migration compression patch from this series
- Add one more error handling patch related with migration
- Add more cleaning up code for touched functions
v3:
- Add two migration related patches to fix the segmentaion fault
- Extract the segmentation fault fix from v2's last patch to be a separate patch
- Add cleaning up code for touched functions
- Update some error messages
v2:
- Pass errp straightly instead of using a local_err & error_propagate
- Return a bool: false/true to indicate if one function succeeds
- Merge v1's last two patches into one to avoid the compile error
- Fix one omitted error in patch1 and update some error messages
Fei Li (7):
Fix segmentation fault when qemu_signal_init fails ui/vnc.c: polish vnc_init_func
qemu_init_vcpu: add a new Error parameter to propagate
qemu_thread_join: fix segmentation fault
migration: fix the multifd code
migration: fix some error handling
qemu_thread_create: propagate the error to callers to handle
accel/tcg/user-exec-stub.c | 2 +- cpus.c | 79 ++++++++++++++++++++++++++--------------- dump.c | 6 ++-- hw/misc/edu.c | 6 ++-- hw/ppc/spapr_hcall.c | 10 ++++-- hw/rdma/rdma_backend.c | 4 ++- hw/usb/ccid-card-emulated.c | 13 ++++--- include/qemu/osdep.h | 2 +- include/qemu/thread.h | 4 +-- include/qom/cpu.h | 2 +- include/ui/console.h | 2 +- io/task.c | 3 +- iothread.c | 16 ++++++--- migration/migration.c | 54 ++++++++++++++++++---------- migration/postcopy-ram.c | 17 +++++++-- migration/ram.c | 68 ++++++++++++++++++++++++----------- migration/ram.h | 2 +- migration/savevm.c | 11 ++++-- target/alpha/cpu.c | 4 ++- target/arm/cpu.c | 4 ++- target/cris/cpu.c | 4 ++- target/hppa/cpu.c | 4 ++- target/i386/cpu.c | 4 ++- target/lm32/cpu.c | 4 ++- target/m68k/cpu.c | 4 ++- target/microblaze/cpu.c | 4 ++- target/mips/cpu.c | 4 ++- target/moxie/cpu.c | 4 ++- target/nios2/cpu.c | 4 ++- target/openrisc/cpu.c | 4 ++- target/ppc/translate_init.inc.c | 4 ++- target/riscv/cpu.c | 4 ++- target/s390x/cpu.c | 4 ++- target/sh4/cpu.c | 4 ++- target/sparc/cpu.c | 4 ++- target/tilegx/cpu.c | 4 ++- target/tricore/cpu.c | 4 ++- target/unicore32/cpu.c | 4 ++- target/xtensa/cpu.c | 4 ++- tests/atomic_add-bench.c | 3 +- tests/iothread.c | 2 +- tests/qht-bench.c | 3 +- tests/rcutorture.c | 3 +- tests/test-aio.c | 2 +- tests/test-rcu-list.c | 3 +- ui/vnc-jobs.c | 17 ++++++--- ui/vnc-jobs.h | 2 +- ui/vnc.c | 12 +++++-- util/compatfd.c | 18 +++++++--- util/main-loop.c | 11 +++--- util/oslib-posix.c | 17 ++++++--- util/qemu-thread-posix.c | 25 ++++++++----- util/qemu-thread-win32.c | 18 +++++++--- util/rcu.c | 3 +- util/thread-pool.c | 4 ++- 55 files changed, 366 insertions(+), 162 deletions(-)
Signature · 1 line
2.13.7
RFC PATCH v5 1/7 Fix segmentation fault when qemu_signal_init fails
Currently, when qemu_signal_init() fails it only returns a non-zero value but without propagating any Error. But its callers need a non-null err when runs error_report_err(err), or else 0->msg occurs.
To avoid such segmentation fault, add a new Error parameter to make the call trace to propagate the err to the final caller.
--- include/qemu/osdep.h | 2 +- util/compatfd.c | 9 ++++++--- util/main-loop.c | 9 ++++----- 3 files changed, 11 insertions(+), 9 deletions(-)
include/qemu/osdep.h +1 -1
@@ -421,7 +421,7 @@ struct qemu_signalfd_siginfo { additional fields in the future) */ }; -int qemu_signalfd (const sigset_t *mask); +int qemu_signalfd (const sigset_t *mask,Error **errp);void sigaction_invoke (struct sigaction *action,struct qemu_signalfd_siginfo *info);#endif
util/compatfd.c +6 -3
@@ -16,6 +16,7 @@#include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/thread.h" +#include "qapi/error.h" #include <sys/syscall.h>
@@ -65,7 +66,7 @@ static void *sigwait_compat(void *opaque) } } -static int qemu_signalfd_compat (const sigset_t *mask) +static int qemu_signalfd_compat (const sigset_t *mask,Error **errp) {struct sigfd_compat_info *info;QemuThread thread;
@@ -73,11 +74,13 @@ static int qemu_signalfd_compat(const sigset_t *mask) info =malloc (sizeof (*info));if (info ==NULL ) { +error_setg (errp,"Failed to allocate signalfd memory" ); errno =ENOMEM ;return -1 ; }if (pipe (fds) ==-1 ) { +error_setg (errp,"Failed to create signalfd pipe" );free (info);return -1 ; }
@@ -94,7 +97,7 @@ static int qemu_signalfd_compat(const sigset_t *mask)return fds[0 ]; } -int qemu_signalfd (const sigset_t *mask) +int qemu_signalfd (const sigset_t *mask,Error **errp) {#if defined(CONFIG_SIGNALFD )int ret;
@@ -106,5 +109,5 @@ int qemu_signalfd(const sigset_t *mask) }#endif -return qemu_signalfd_compat (mask); +return qemu_signalfd_compat (mask, errp); }
util/main-loop.c +4 -5
@@ -71,7 +71,7 @@ static void sigfd_handler(void *opaque) } } -static int qemu_signal_init (void ) +static int qemu_signal_init (Error **errp) {int sigfd;sigset_t set;
@@ -94,9 +94,8 @@ static int qemu_signal_init(void)pthread_sigmask (SIG_BLOCK , &set,NULL );sigdelset (&set,SIG_IPI ); - sigfd =qemu_signalfd (&set); + sigfd =qemu_signalfd (&set, errp);if (sigfd ==-1 ) { -fprintf (stderr,"failed to create signalfd\n" );return -errno; }
@@ -109,7 +108,7 @@ static int qemu_signal_init(void)#else /* _WIN32 */ -static int qemu_signal_init (void ) +static int qemu_signal_init (Error **errp) {return 0 ; }
@@ -148,7 +147,7 @@ int qemu_init_main_loop(Error **errp)init_clocks (qemu_timer_notify_cb); - ret =qemu_signal_init (); + ret =qemu_signal_init (errp);if (ret) {return ret; }
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH RFC v5 1/7] Fix segmentation fault when qemu_signal_init fails
Quoted 3 lines · Fei Li
Currently, when
qemu_signal_init()fails it only returns a non-zero value but without propagating any Error. But its callers need a non-null err when runserror_report_err(err), or else 0->msg occurs.
The bug is in qemu_init_main_loop():
ret = qemu_signal_init();
if (ret) {
return ret;
}Fails without setting an error, unlike the other failures. Its callers crash then.
Quoted 69 lines
To avoid such segmentation fault, add a new Error parameter to make the call trace to propagate the err to the final caller.
Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- include/qemu/osdep.h | 2 +- util/compatfd.c | 9 ++++++--- util/main-loop.c | 9 ++++----- 3 files changed, 11 insertions(+), 9 deletions(-)include/qemu/osdep.h +1
-1@@ -421,7 +421,7 @@ struct qemu_signalfd_siginfo { additional fields in the future) */ }; -int qemu_signalfd (const sigset_t *mask); +int qemu_signalfd (const sigset_t *mask,Error **errp);void sigaction_invoke (struct sigaction *action,struct qemu_signalfd_siginfo *info);#endif util/compatfd.c +5
-2@@ -16,6 +16,7 @@#include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/thread.h" +#include "qapi/error.h" #include <sys/syscall.h> @@ -65,7 +66,7 @@ static void *sigwait_compat(void *opaque) } } -static int qemu_signalfd_compat (const sigset_t *mask) +static int qemu_signalfd_compat (const sigset_t *mask,Error **errp) {struct sigfd_compat_info *info;QemuThread thread;@@ -73,11 +74,13 @@ static int qemu_signalfd_compat(const sigset_t *mask) info =malloc (sizeof (*info));if (info ==NULL ) { +error_setg (errp,"Failed to allocate signalfd memory" ); errno =ENOMEM ;return -1 ; }if (pipe (fds) ==-1 ) { +error_setg (errp,"Failed to create signalfd pipe" );free (info);return -1 ; }@@ -94,7 +97,7 @@ static int qemu_signalfd_compat(const sigset_t *mask)return fds[0 ]; } -int qemu_signalfd (const sigset_t *mask) +int qemu_signalfd (const sigset_t *mask,Error **errp) {#if defined(CONFIG_SIGNALFD )int ret;
util/compatfd.c int qemu_signalfd(const sigset_t *mask) · line 113
Quoted 6 lines
util/compatfd.c +1
-1@@ -106,5 +109,5 @@ int qemu_signalfd(const sigset_t *mask) }#endif -return qemu_signalfd_compat (mask); +return qemu_signalfd_compat (mask, errp); }
I think this takes the Error conversion too far.
qemu_signalfd() is like the signalfd() system call, only portable, and setting FD_CLOEXEC. In particular, it reports failure just like a system call: it sets errno and returns -1. I'd prefer to keep it that way. Instead...
Quoted 14 lines
util/main-loop.c +1
-1@@ -71,7 +71,7 @@ static void sigfd_handler(void *opaque) } } -static int qemu_signal_init (void ) +static int qemu_signal_init (Error **errp) {int sigfd;sigset_t set;
util/main-loop.c static int qemu_signal_init(void) · line 101
Quoted 10 lines
util/main-loop.c +1
-2@@ -94,9 +94,8 @@ static int qemu_signal_init(void)pthread_sigmask (SIG_BLOCK , &set,NULL );sigdelset (&set,SIG_IPI ); - sigfd =qemu_signalfd (&set); + sigfd =qemu_signalfd (&set, errp);if (sigfd ==-1 ) { -fprintf (stderr,"failed to create signalfd\n" );return -errno; }
... change this function so:
pthread_sigmask(SIG_BLOCK, &set, NULL);
sigdelset(&set, SIG_IPI);
sigfd = qemu_signalfd(&set);
if (sigfd == -1) {
- fprintf(stderr, "failed to create signalfd\n");
+ error_setg_errno(errp, errno, "failed to create signalfd");
return -errno;
}Does this make sense?
Quoted 18 lines
util/main-loop.c +2
-2@@ -109,7 +108,7 @@ static int qemu_signal_init(void)#else /* _WIN32 */ -static int qemu_signal_init (void ) +static int qemu_signal_init (Error **errp) {return 0 ; }@@ -148,7 +147,7 @@ int qemu_init_main_loop(Error **errp)init_clocks (qemu_timer_notify_cb); - ret =qemu_signal_init (); + ret =qemu_signal_init (errp);if (ret) {return ret; }
Re: [Qemu-devel] [PATCH RFC v5 1/7] Fix segmentation fault when qemu_signal_init fails
Quoted 7 lines · Markus Armbruster
Quoted 3 lines · Fei Li
Currently, when
qemu_signal_init()fails it only returns a non-zero value but without propagating any Error. But its callers need a non-null err when runserror_report_err(err), or else 0->msg occurs.The bug is in
qemu_init_main_loop():
Quoted 7 lines
ret = qemu_signal_init(); if (ret) { return ret; }Fails without setting an error, unlike the other failures. Its callers crash then.
Thanks!
Quoted 118 lines
Quoted 69 lines
To avoid such segmentation fault, add a new Error parameter to make the call trace to propagate the err to the final caller.
Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- include/qemu/osdep.h | 2 +- util/compatfd.c | 9 ++++++--- util/main-loop.c | 9 ++++----- 3 files changed, 11 insertions(+), 9 deletions(-)include/qemu/osdep.h +1
-1@@ -421,7 +421,7 @@ struct qemu_signalfd_siginfo { additional fields in the future) */ }; -int qemu_signalfd (const sigset_t *mask); +int qemu_signalfd (const sigset_t *mask,Error **errp);void sigaction_invoke (struct sigaction *action,struct qemu_signalfd_siginfo *info);#endif util/compatfd.c +5
-2@@ -16,6 +16,7 @@#include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/thread.h" +#include "qapi/error.h" #include <sys/syscall.h> @@ -65,7 +66,7 @@ static void *sigwait_compat(void *opaque) } } -static int qemu_signalfd_compat (const sigset_t *mask) +static int qemu_signalfd_compat (const sigset_t *mask,Error **errp) {struct sigfd_compat_info *info;QemuThread thread;@@ -73,11 +74,13 @@ static int qemu_signalfd_compat(const sigset_t *mask) info =malloc (sizeof (*info));if (info ==NULL ) { +error_setg (errp,"Failed to allocate signalfd memory" ); errno =ENOMEM ;return -1 ; }if (pipe (fds) ==-1 ) { +error_setg (errp,"Failed to create signalfd pipe" );free (info);return -1 ; }@@ -94,7 +97,7 @@ static int qemu_signalfd_compat(const sigset_t *mask)return fds[0 ]; } -int qemu_signalfd (const sigset_t *mask) +int qemu_signalfd (const sigset_t *mask,Error **errp) {#if defined(CONFIG_SIGNALFD )int ret;util/compatfd.c int qemu_signalfd(const sigset_t *mask) · line 113
Quoted 6 lines
util/compatfd.c +1
-1@@ -106,5 +109,5 @@ int qemu_signalfd(const sigset_t *mask) }#endif -return qemu_signalfd_compat (mask); +return qemu_signalfd_compat (mask, errp); }I think this takes the Error conversion too far.
qemu_signalfd()is like thesignalfd()system call, only portable, and settingFD_CLOEXEC. In particular, it reports failure just like a system call: it sets errno and returns -1. I'd prefer to keep it that way. Instead...Quoted 14 lines
util/main-loop.c +1
-1@@ -71,7 +71,7 @@ static void sigfd_handler(void *opaque) } } -static int qemu_signal_init (void ) +static int qemu_signal_init (Error **errp) {int sigfd;sigset_t set;util/main-loop.c static int qemu_signal_init(void) · line 101
Quoted 10 lines
util/main-loop.c +1
-2@@ -94,9 +94,8 @@ static int qemu_signal_init(void)pthread_sigmask (SIG_BLOCK , &set,NULL );sigdelset (&set,SIG_IPI ); - sigfd =qemu_signalfd (&set); + sigfd =qemu_signalfd (&set, errp);if (sigfd ==-1 ) { -fprintf (stderr,"failed to create signalfd\n" );return -errno; }... change this function so:
pthread_sigmask(SIG_BLOCK, &set, NULL); sigdelset(&set, SIG_IPI); sigfd = qemu_signalfd(&set); if (sigfd == -1) { - fprintf(stderr, "failed to create signalfd\n"); + error_setg_errno(errp, errno, "failed to create signalfd"); return -errno; }
Quoted 1 line
Does this make sense?
Yes, it looks more concise if we only have this patch, but triggers one errno-set issue after applying patch 7/7, which adds a Error **errp parameter for qemu_thread_create() to let its callers handle the error instead of exit() directly to add the robustness.
For the patch series' current implementation, the modified qemu_thread_create() in 7/7 patch returns a Boolean value to indicate whether it succeeds and set the error reason into the passed errp, and did not set the errno. Actually another similar errno-set issue has been talked in last patch. :)
If we set the errno in future qemu_thread_create(), we need to distinguish the Linux and Windows implementation. For Linux, we can use error_setg_errno() to set errno. But for Windows, I am not sure if we can use
"errno = GetLastError()"
to set errno, as this seems a little weird. Do you have any idea about this?
BTW, if we have a decent errno-set way for Windows, I will adopt your above proposal for this patch.
Have a nice day, thanks for the review :)
Fei
Quoted 19 lines
Quoted 18 lines
util/main-loop.c +2
-2@@ -109,7 +108,7 @@ static int qemu_signal_init(void)#else /* _WIN32 */ -static int qemu_signal_init (void ) +static int qemu_signal_init (Error **errp) {return 0 ; }@@ -148,7 +147,7 @@ int qemu_init_main_loop(Error **errp)init_clocks (qemu_timer_notify_cb); - ret =qemu_signal_init (); + ret =qemu_signal_init (errp);if (ret) {return ret; }
Re: [Qemu-devel] [PATCH RFC v5 1/7] Fix segmentation fault when qemu_signal_init fails
Quoted 8 lines · Fei Li
Quoted 7 lines · Markus Armbruster
Quoted 3 lines · Fei Li
Currently, when
qemu_signal_init()fails it only returns a non-zero value but without propagating any Error. But its callers need a non-null err when runserror_report_err(err), or else 0->msg occurs.The bug is in
qemu_init_main_loop():
Quoted 8 lines
Quoted 7 lines
ret = qemu_signal_init(); if (ret) { return ret; }Fails without setting an error, unlike the other failures. Its callers crash then.
Thanks!
Consider working that into your commit message.
Quoted 107 lines
Quoted 107 lines
Quoted 62 lines
To avoid such segmentation fault, add a new Error parameter to make the call trace to propagate the err to the final caller.
Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- include/qemu/osdep.h | 2 +- util/compatfd.c | 9 ++++++--- util/main-loop.c | 9 ++++----- 3 files changed, 11 insertions(+), 9 deletions(-)include/qemu/osdep.h +1
-0@@ -421,7 +421,7 @@ struct qemu_signalfd_siginfo {additional fields in the future) */ }; -int qemu_signalfd(const sigset_t *mask); +int qemu_signalfd (const sigset_t *mask,Error **errp);void sigaction_invoke (struct sigaction *action,struct qemu_signalfd_siginfo *info);#endif util/compatfd.c +1
-0@@ -16,6 +16,7 @@#include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/thread.h" +#include "qapi/error.h" #include <sys/syscall.h> @@ -65,7 +66,7 @@ static void *sigwait_compat(void *opaque) }} -static int qemu_signalfd_compat(const sigset_t *mask)util/compatfd.c +4
-0+static int qemu_signalfd_compat (const sigset_t *mask,Error **errp) {struct sigfd_compat_info *info;QemuThread thread;@@ -73,11 +74,13 @@ static int qemu_signalfd_compat(const sigset_t *mask) info =malloc (sizeof (*info));if (info ==NULL ) { +error_setg (errp,"Failed to allocate signalfd memory" ); errno =ENOMEM ;return -1 ; }if (pipe (fds) ==-1 ) { +error_setg (errp,"Failed to create signalfd pipe" );free (info);return -1 ; }@@ -94,7 +97,7 @@ static int qemu_signalfd_compat(const sigset_t *mask)return fds[0 ]; } -int qemu_signalfd(const sigset_t *mask) +int qemu_signalfd(const sigset_t *mask, Error **errp) {#if defined(CONFIG_SIGNALFD )int ret;util/compatfd.c int qemu_signalfd(const sigset_t *mask) · line 113
Quoted 5 lines
util/compatfd.c +1
-0@@ -106,5 +109,5 @@ int qemu_signalfd(const sigset_t *mask) }#endif - return qemu_signalfd_compat(mask); +return qemu_signalfd_compat (mask, errp); }I think this takes the Error conversion too far.
qemu_signalfd()is like thesignalfd()system call, only portable, and settingFD_CLOEXEC. In particular, it reports failure just like a system call: it sets errno and returns -1. I'd prefer to keep it that way. Instead...Quoted 13 lines
util/main-loop.c +1
-0@@ -71,7 +71,7 @@ static void sigfd_handler(void *opaque) } } -static int qemu_signal_init(void) +static int qemu_signal_init(Error **errp) {int sigfd;sigset_t set;util/main-loop.c static int qemu_signal_init(void) · line 100
Quoted 9 lines
util/main-loop.c +1
-2@@ -94,9 +94,8 @@ static int qemu_signal_init(void)pthread_sigmask (SIG_BLOCK , &set,NULL );sigdelset (&set,SIG_IPI ); - sigfd =qemu_signalfd (&set); + sigfd =qemu_signalfd (&set, errp);if (sigfd ==-1 ) { -fprintf (stderr,"failed to create signalfd\n" );return -errno; }... change this function so:
pthread_sigmask(SIG_BLOCK, &set, NULL); sigdelset(&set, SIG_IPI); sigfd = qemu_signalfd(&set); if (sigfd == -1) { - fprintf(stderr, "failed to create signalfd\n"); + error_setg_errno(errp, errno, "failed to create signalfd"); return -errno; }
Quoted 7 lines
Quoted 1 line
Does this make sense?
Yes, it looks more concise if we only have this patch, but triggers one errno-set
issue after applying patch 7/7, which adds a Error **errp parameter forqemu_thread_create()to let its callers handle the error instead ofexit()directly
to add the robustness.
I guess you're talking about the qemu_thread_create() in qemu_signalfd_compat(). Correct?
Quoted 13 lines
For the patch series' current implementation, the modified
qemu_thread_create()
in 7/7 patch returns a Boolean value to indicate whether it succeeds and set the
error reason into the passed errp, and did not set the errno. Actually another
similar errno-set issue has been talked in last patch. :) If we set the errno in futureqemu_thread_create(), we need to distinguish the Linux
and Windows implementation. For Linux, we can useerror_setg_errno()to set errno.
But for Windows, I am not sure if we can use
Quoted 1 line
"errno =
GetLastError()"
No, that won't work.
Quoted 4 lines
to set errno, as this seems a little weird. Do you have any idea about this?
BTW, if we have a decent errno-set way for Windows, I will adopt your above proposal for this patch.
According to MS docs, _beginthreadex() sets errno on failure:
If successful, each of these functions returns a handle to the newly created thread; however, if the newly created thread exits too quickly, _beginthread might not return a valid handle. (See the discussion in the Remarks section.) On an error, _beginthread returns -1L, and errno is set to EAGAIN if there are too many threads, to EINVAL if the argument is invalid or the stack size is incorrect, or to EACCES if there are insufficient resources (such as memory). On an error, _beginthreadex returns 0, and errno and _doserrno are set.
https://docs.microsoft.com/cpp/c-runtime-library/reference/beginthread-beginthreadex
Looks like the current code's use of GetLastError() after _beginthreadex() failure is wrong.
Fix that, and both qemu_thread_create() implementations set errno on failure, which in turn lets you make qemu_signalfd_compat() and thus qemu_signalfd() behave sanely regardless of which qemu_thread_create() implementation they use below the hood.
Quoted 17 lines
Have a nice day, thanks for the review :)
FeiQuoted 15 lines
Quoted 14 lines
util/main-loop.c +2
-0@@ -109,7 +108,7 @@ static int qemu_signal_init(void)#else /* _WIN32 */ -static int qemu_signal_init(void) +static int qemu_signal_init(Error **errp) {return 0 ; }@@ -148,7 +147,7 @@ int qemu_init_main_loop(Error **errp)init_clocks (qemu_timer_notify_cb); - ret =qemu_signal_init (); + ret =qemu_signal_init (errp);if (ret) {return ret; }
Re: [Qemu-devel] [PATCH RFC v5 1/7] Fix segmentation fault when qemu_signal_init fails
Quoted 15 lines · Markus Armbruster
Quoted 13 lines · Fei Li
Quoted 12 lines · Markus Armbruster
Quoted 3 lines · Fei Li
Currently, when
qemu_signal_init()fails it only returns a non-zero value but without propagating any Error. But its callers need a non-null err when runserror_report_err(err), or else 0->msg occurs.The bug is in
qemu_init_main_loop():ret = qemu_signal_init(); if (ret) { return ret; }
Quoted 4 lines
Quoted 3 lines
Quoted 2 lines
Fails without setting an error, unlike the other failures. Its callers crash then.
Thanks!
Consider working that into your commit message.
Ok. I'd like to reword as follows:
Currently in qemu_init_main_loop(), qemu_signal_init() fails without setting an error like the other failures. Its callers crash then when runs error_report_err(err).
Quoted 109 lines
Quoted 109 lines
Quoted 109 lines
Quoted 63 lines
To avoid such segmentation fault, add a new Error parameter to make the call trace to propagate the err to the final caller.
Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- include/qemu/osdep.h | 2 +- util/compatfd.c | 9 ++++++--- util/main-loop.c | 9 ++++----- 3 files changed, 11 insertions(+), 9 deletions(-)include/qemu/osdep.h +1
-0@@ -421,7 +421,7 @@ struct qemu_signalfd_siginfo {additional fields in the future) */ }; -int qemu_signalfd(const sigset_t *mask); +int qemu_signalfd (const sigset_t *mask,Error **errp);void sigaction_invoke (struct sigaction *action,struct qemu_signalfd_siginfo *info);#endif util/compatfd.c +1
-0@@ -16,6 +16,7 @@#include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/thread.h" +#include "qapi/error.h" #include <sys/syscall.h> @@ -65,7 +66,7 @@ static void *sigwait_compat(void *opaque) }} -static int qemu_signalfd_compat(const sigset_t *mask)util/compatfd.c +4
-0+static int qemu_signalfd_compat (const sigset_t *mask,Error **errp) {struct sigfd_compat_info *info;QemuThread thread;@@ -73,11 +74,13 @@ static int qemu_signalfd_compat(const sigset_t *mask) info =malloc (sizeof (*info));if (info ==NULL ) { +error_setg (errp,"Failed to allocate signalfd memory" ); errno =ENOMEM ;return -1 ; }if (pipe (fds) ==-1 ) { +error_setg (errp,"Failed to create signalfd pipe" );free (info);return -1 ; }@@ -94,7 +97,7 @@ static int qemu_signalfd_compat(const sigset_t *mask)return fds[0 ]; } -int qemu_signalfd(const sigset_t *mask) +int qemu_signalfd(const sigset_t *mask, Error **errp) {#if defined(CONFIG_SIGNALFD )int ret;util/compatfd.c int qemu_signalfd(const sigset_t *mask) · line 113
Quoted 5 lines
util/compatfd.c +1
-0@@ -106,5 +109,5 @@ int qemu_signalfd(const sigset_t *mask) }#endif - return qemu_signalfd_compat(mask); +return qemu_signalfd_compat (mask, errp); }I think this takes the Error conversion too far.
qemu_signalfd()is like thesignalfd()system call, only portable, and settingFD_CLOEXEC. In particular, it reports failure just like a system call: it sets errno and returns -1. I'd prefer to keep it that way. Instead...Quoted 13 lines
util/main-loop.c +1
-0@@ -71,7 +71,7 @@ static void sigfd_handler(void *opaque) } } -static int qemu_signal_init(void) +static int qemu_signal_init(Error **errp) {int sigfd;sigset_t set;util/main-loop.c static int qemu_signal_init(void) · line 100
Quoted 9 lines
util/main-loop.c +1
-2@@ -94,9 +94,8 @@ static int qemu_signal_init(void)pthread_sigmask (SIG_BLOCK , &set,NULL );sigdelset (&set,SIG_IPI ); - sigfd =qemu_signalfd (&set); + sigfd =qemu_signalfd (&set, errp);if (sigfd ==-1 ) { -fprintf (stderr,"failed to create signalfd\n" );return -errno; }... change this function so:
pthread_sigmask(SIG_BLOCK, &set, NULL); sigdelset(&set, SIG_IPI); sigfd = qemu_signalfd(&set); if (sigfd == -1) { - fprintf(stderr, "failed to create signalfd\n"); + error_setg_errno(errp, errno, "failed to create signalfd"); return -errno; }Does this make sense?
Quoted 8 lines
Quoted 6 lines
Yes, it looks more concise if we only have this patch, but triggers one errno-set
issue after applying patch 7/7, which adds a Error **errp parameter forqemu_thread_create()to let its callers handle the error instead ofexit()directly
to add the robustness.I guess you're talking about the
qemu_thread_create()inqemu_signalfd_compat(). Correct?
Yes.
Quoted 35 lines
Quoted 14 lines
For the patch series' current implementation, the modified
qemu_thread_create()
in 7/7 patch returns a Boolean value to indicate whether it succeeds and set the
error reason into the passed errp, and did not set the errno. Actually another
similar errno-set issue has been talked in last patch. :) If we set the errno in futureqemu_thread_create(), we need to distinguish the Linux
and Windows implementation. For Linux, we can useerror_setg_errno()to set errno.
But for Windows, I am not sure if we can useQuoted 1 line
"errno =
GetLastError()"No, that won't work.
Quoted 4 lines
to set errno, as this seems a little weird. Do you have any idea about this?
BTW, if we have a decent errno-set way for Windows, I will adopt your above proposal for this patch.
According to MS docs,
_beginthreadex()sets errno on failure:If successful, each of these functions returns a handle to the newly created thread; however, if the newly created thread exits too quickly,
_beginthreadmight not return a valid handle. (See the discussion in the Remarks section.) On an error,_beginthreadreturns -1L, and errno is set to EAGAIN if there are too many threads, to EINVAL if the argument is invalid or the stack size is incorrect, or to EACCES if there are insufficient resources (such as memory). On an error,_beginthreadexreturns 0, and errno and_doserrnoare set.https://docs.microsoft.com/cpp/c-runtime-library/reference/beginthread-beginthreadex
Quoted 7 lines
Looks like the current code's use of
GetLastError()after_beginthreadex()failure is wrong.Fix that, and both
qemu_thread_create()implementations set errno on failure, which in turn lets you makeqemu_signalfd_compat()and thusqemu_signalfd()behave sanely regardless of whichqemu_thread_create()implementation they use below the hood.
Thanks for the detail explanation. :)
To fix that, how about replacing the "GetLastError()" with the returned value "hThread" (actually returns 0)? I mean
...
hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine, data, 0, &thread->tid); if (!hThread) {
if (data->mode != QEMU_THREAD_DETACHED) { DeleteCriticalSection(&data->cs);
}
error_setg_win32(errp, hThread,
"failed to create win32_start_routine"); g_free(data);
return false;
}
Have a nice day, thanks
Fei
Quoted 18 lines
Quoted 17 lines
Have a nice day, thanks for the review :)
FeiQuoted 14 lines
Quoted 14 lines
util/main-loop.c +2
-0@@ -109,7 +108,7 @@ static int qemu_signal_init(void)#else /* _WIN32 */ -static int qemu_signal_init(void) +static int qemu_signal_init(Error **errp) {return 0 ; }@@ -148,7 +147,7 @@ int qemu_init_main_loop(Error **errp)init_clocks (qemu_timer_notify_cb); - ret =qemu_signal_init (); + ret =qemu_signal_init (errp);if (ret) {return ret; }
Re: [Qemu-devel] [PATCH RFC v5 1/7] Fix segmentation fault when qemu_signal_init fails
Quoted 18 lines · Fei Li
Quoted 17 lines · Markus Armbruster
Quoted 15 lines · Fei Li
Quoted 14 lines · Markus Armbruster
Quoted 3 lines · Fei Li
Currently, when
qemu_signal_init()fails it only returns a non-zero value but without propagating any Error. But its callers need a non-null err when runserror_report_err(err), or else 0->msg occurs.The bug is in
qemu_init_main_loop():ret = qemu_signal_init(); if (ret) { return ret; }Fails without setting an error, unlike the other failures. Its callers crash then.
Quoted 7 lines
Quoted 2 lines
Quoted 1 line
Thanks!
Consider working that into your commit message.
Ok. I'd like to reword as follows:
Currently inqemu_init_main_loop(),qemu_signal_init()fails without setting an error
like the other failures. Its callers crash then when runserror_report_err(err).
Polishing the English a bit:
When qemu_signal_init() fails in qemu_init_main_loop(), we return without setting an error. Its callers crash then when they try to report the error with error_report_err().
Quoted 160 lines
Quoted 109 lines
Quoted 109 lines
Quoted 109 lines
Quoted 63 lines
To avoid such segmentation fault, add a new Error parameter to make the call trace to propagate the err to the final caller.
Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- include/qemu/osdep.h | 2 +- util/compatfd.c | 9 ++++++--- util/main-loop.c | 9 ++++----- 3 files changed, 11 insertions(+), 9 deletions(-)include/qemu/osdep.h +1
-0@@ -421,7 +421,7 @@ struct qemu_signalfd_siginfo {additional fields in the future) */ }; -int qemu_signalfd(const sigset_t *mask); +int qemu_signalfd (const sigset_t *mask,Error **errp);void sigaction_invoke (struct sigaction *action,struct qemu_signalfd_siginfo *info);#endif util/compatfd.c +1
-0@@ -16,6 +16,7 @@#include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/thread.h" +#include "qapi/error.h" #include <sys/syscall.h> @@ -65,7 +66,7 @@ static void *sigwait_compat(void *opaque) }} -static int qemu_signalfd_compat(const sigset_t *mask)util/compatfd.c +4
-0+static int qemu_signalfd_compat (const sigset_t *mask,Error **errp) {struct sigfd_compat_info *info;QemuThread thread;@@ -73,11 +74,13 @@ static int qemu_signalfd_compat(const sigset_t *mask) info =malloc (sizeof (*info));if (info ==NULL ) { +error_setg (errp,"Failed to allocate signalfd memory" ); errno =ENOMEM ;return -1 ; }if (pipe (fds) ==-1 ) { +error_setg (errp,"Failed to create signalfd pipe" );free (info);return -1 ; }@@ -94,7 +97,7 @@ static int qemu_signalfd_compat(const sigset_t *mask)return fds[0 ]; } -int qemu_signalfd(const sigset_t *mask) +int qemu_signalfd(const sigset_t *mask, Error **errp) {#if defined(CONFIG_SIGNALFD )int ret;util/compatfd.c int qemu_signalfd(const sigset_t *mask) · line 113
Quoted 5 lines
util/compatfd.c +1
-0@@ -106,5 +109,5 @@ int qemu_signalfd(const sigset_t *mask) }#endif - return qemu_signalfd_compat(mask); +return qemu_signalfd_compat (mask, errp); }I think this takes the Error conversion too far.
qemu_signalfd()is like thesignalfd()system call, only portable, and settingFD_CLOEXEC. In particular, it reports failure just like a system call: it sets errno and returns -1. I'd prefer to keep it that way. Instead...Quoted 13 lines
util/main-loop.c +1
-0@@ -71,7 +71,7 @@ static void sigfd_handler(void *opaque) } } -static int qemu_signal_init(void) +static int qemu_signal_init(Error **errp) {int sigfd;sigset_t set;util/main-loop.c static int qemu_signal_init(void) · line 100
Quoted 9 lines
util/main-loop.c +1
-2@@ -94,9 +94,8 @@ static int qemu_signal_init(void)pthread_sigmask (SIG_BLOCK , &set,NULL );sigdelset (&set,SIG_IPI ); - sigfd =qemu_signalfd (&set); + sigfd =qemu_signalfd (&set, errp);if (sigfd ==-1 ) { -fprintf (stderr,"failed to create signalfd\n" );return -errno; }... change this function so:
pthread_sigmask(SIG_BLOCK, &set, NULL); sigdelset(&set, SIG_IPI); sigfd = qemu_signalfd(&set); if (sigfd == -1) { - fprintf(stderr, "failed to create signalfd\n"); + error_setg_errno(errp, errno, "failed to create signalfd"); return -errno; }Does this make sense?
Quoted 8 lines
Quoted 6 lines
Yes, it looks more concise if we only have this patch, but triggers one errno-set
issue after applying patch 7/7, which adds a Error **errp parameter forqemu_thread_create()to let its callers handle the error instead ofexit()directly
to add the robustness.I guess you're talking about the
qemu_thread_create()inqemu_signalfd_compat(). Correct?Yes.
Quoted 35 lines
Quoted 14 lines
For the patch series' current implementation, the modified
qemu_thread_create()
in 7/7 patch returns a Boolean value to indicate whether it succeeds and set the
error reason into the passed errp, and did not set the errno. Actually another
similar errno-set issue has been talked in last patch. :) If we set the errno in futureqemu_thread_create(), we need to distinguish the Linux
and Windows implementation. For Linux, we can useerror_setg_errno()to set errno.
But for Windows, I am not sure if we can useQuoted 1 line
"errno =
GetLastError()"No, that won't work.
Quoted 4 lines
to set errno, as this seems a little weird. Do you have any idea about this?
BTW, if we have a decent errno-set way for Windows, I will adopt your above proposal for this patch.
According to MS docs,
_beginthreadex()sets errno on failure:If successful, each of these functions returns a handle to the newly created thread; however, if the newly created thread exits too quickly,
_beginthreadmight not return a valid handle. (See the discussion in the Remarks section.) On an error,_beginthreadreturns -1L, and errno is set to EAGAIN if there are too many threads, to EINVAL if the argument is invalid or the stack size is incorrect, or to EACCES if there are insufficient resources (such as memory). On an error,_beginthreadexreturns 0, and errno and_doserrnoare set.https://docs.microsoft.com/cpp/c-runtime-library/reference/beginthread-beginthreadex
Quoted 7 lines
Looks like the current code's use of
GetLastError()after_beginthreadex()failure is wrong.Fix that, and both
qemu_thread_create()implementations set errno on failure, which in turn lets you makeqemu_signalfd_compat()and thusqemu_signalfd()behave sanely regardless of whichqemu_thread_create()implementation they use below the hood.
Quoted 15 lines
Thanks for the detail explanation. :)
To fix that, how about replacing the "GetLastError()" with the returned value "hThread" (actually returns 0)? I mean
...
hThread = (HANDLE)_beginthreadex(NULL, 0, win32_start_routine, data, 0, &thread->tid); if (!hThread) {
if (data->mode!=QEMU_THREAD_DETACHED) {DeleteCriticalSection(&data->cs);
}
error_setg_win32(errp, hThread,
"failed to createwin32_start_routine");g_free(data);
return false;
}
No. On failure, _beginthreadex() returns *zero*, not an error code. It also sets errno. That's the error code you need to use:
hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
data, 0, &thread->tid);
if (!hThread) {
error_setg_errno(errp, errno, "can't create thread");
}Except I really wouldn't convert qemu_thread_create() to Error! I'd make it return zero on success, a negative errno code on failure, and leave the Error business to its callers. Basically, replace error_exit(err, ...) by return err.
The caller qemu_signalfd_compat() can then do
ret = qemu_thread_create(&thread, "signalfd_compat",
sigwait_compat, info, QEMU_THREAD_DETACHED);
if (ret < 0) {
errno = ret;
return -1;
}A caller that already has an Error **errp parameter could do
ret = qemu_thread_create(...);
if (ret < 0) {
error_setg_errno(errp, -ret, "<error message goes here>");
}Callers that want to continue aborting on failure simply do
ret = qemu_thread_create(...);
assert(ret >= 0);If that turns out to be too much of a bother, you could create a convenience wrapper for it:
void qemu_thread_create_nofail(QemuThread *thread, const char *name,
void *(*start_routine)(void*),
void *arg, int mode)
{
int err = qemu_thread_create(thread, name, start_routine, arg, mode);
if (err) {
error_exit(err, __func__);
}
}Re: [Qemu-devel] [PATCH RFC v5 1/7] Fix segmentation fault when qemu_signal_init fails
Sorry for the late reply! Omitted this one..
Quoted 27 lines · Markus Armbruster
Quoted 18 lines · Fei Li
Quoted 17 lines · Markus Armbruster
Quoted 15 lines · Fei Li
Quoted 14 lines · Markus Armbruster
Quoted 3 lines · Fei Li
Currently, when
qemu_signal_init()fails it only returns a non-zero value but without propagating any Error. But its callers need a non-null err when runserror_report_err(err), or else 0->msg occurs.The bug is in
qemu_init_main_loop():ret = qemu_signal_init(); if (ret) { return ret; }Fails without setting an error, unlike the other failures. Its callers crash then.
Quoted 7 lines
Quoted 2 lines
Quoted 1 line
Thanks!
Consider working that into your commit message.
Ok. I'd like to reword as follows:
Currently inqemu_init_main_loop(),qemu_signal_init()fails without setting an error
like the other failures. Its callers crash then when runserror_report_err(err).
Quoted 5 lines
Polishing the English a bit:
When
qemu_signal_init()fails inqemu_init_main_loop(), we return without setting an error. Its callers crash then when they try to report the error witherror_report_err().
Thanks. :)
Quoted 173 lines
Quoted 158 lines
Quoted 108 lines
Quoted 108 lines
Quoted 108 lines
Quoted 62 lines
To avoid such segmentation fault, add a new Error parameter to make the call trace to propagate the err to the final caller.
Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- include/qemu/osdep.h | 2 +- util/compatfd.c | 9 ++++++--- util/main-loop.c | 9 ++++----- 3 files changed, 11 insertions(+), 9 deletions(-)include/qemu/osdep.h +1
-0@@ -421,7 +421,7 @@ struct qemu_signalfd_siginfo {additional fields in the future) */ }; -int qemu_signalfd(const sigset_t *mask); +int qemu_signalfd (const sigset_t *mask,Error **errp);void sigaction_invoke (struct sigaction *action,struct qemu_signalfd_siginfo *info);#endif util/compatfd.c +1
-0@@ -16,6 +16,7 @@#include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/thread.h" +#include "qapi/error.h" #include <sys/syscall.h> @@ -65,7 +66,7 @@ static void *sigwait_compat(void *opaque) }}
-static intqemu_signalfd_compat(const sigset_t *mask)util/compatfd.c +4
-0+static int qemu_signalfd_compat (const sigset_t *mask,Error **errp) {struct sigfd_compat_info *info;QemuThread thread;@@ -73,11 +74,13 @@ static int qemu_signalfd_compat(const sigset_t *mask) info =malloc (sizeof (*info));if (info ==NULL ) { +error_setg (errp,"Failed to allocate signalfd memory" ); errno =ENOMEM ;return -1 ; }if (pipe (fds) ==-1 ) { +error_setg (errp,"Failed to create signalfd pipe" );free (info);return -1 ; }@@ -94,7 +97,7 @@ static int qemu_signalfd_compat(const sigset_t *mask)return fds[0 ]; } -int qemu_signalfd(const sigset_t *mask) +int qemu_signalfd(const sigset_t *mask, Error **errp) {#if defined(CONFIG_SIGNALFD )int ret;util/compatfd.c int qemu_signalfd(const sigset_t *mask) · line 113
Quoted 5 lines
util/compatfd.c +1
-0@@ -106,5 +109,5 @@ int qemu_signalfd(const sigset_t *mask) }#endif - return qemu_signalfd_compat(mask); +return qemu_signalfd_compat (mask, errp); }I think this takes the Error conversion too far.
qemu_signalfd()is like thesignalfd()system call, only portable, and settingFD_CLOEXEC. In particular, it reports failure just like a system call: it sets errno and returns -1. I'd prefer to keep it that way. Instead...Quoted 13 lines
util/main-loop.c +1
-0@@ -71,7 +71,7 @@ static void sigfd_handler(void *opaque) } } -static int qemu_signal_init(void) +static int qemu_signal_init(Error **errp) {int sigfd;sigset_t set;util/main-loop.c static int qemu_signal_init(void) · line 100
Quoted 9 lines
util/main-loop.c +1
-2@@ -94,9 +94,8 @@ static int qemu_signal_init(void)pthread_sigmask (SIG_BLOCK , &set,NULL );sigdelset (&set,SIG_IPI ); - sigfd =qemu_signalfd (&set); + sigfd =qemu_signalfd (&set, errp);if (sigfd ==-1 ) { -fprintf (stderr,"failed to create signalfd\n" );return -errno; }... change this function so:
pthread_sigmask(SIG_BLOCK, &set, NULL); sigdelset(&set, SIG_IPI); sigfd = qemu_signalfd(&set); if (sigfd == -1) { - fprintf(stderr, "failed to create signalfd\n"); + error_setg_errno(errp, errno, "failed to create signalfd"); return -errno; }Does this make sense?
Quoted 8 lines
Quoted 6 lines
Yes, it looks more concise if we only have this patch, but triggers one errno-set
issue after applying patch 7/7, which adds a Error **errp parameter forqemu_thread_create()to let its callers handle the error instead ofexit()directly
to add the robustness.I guess you're talking about the
qemu_thread_create()inqemu_signalfd_compat(). Correct?Yes.
Quoted 34 lines
Quoted 13 lines
For the patch series' current implementation, the modified
qemu_thread_create()
in 7/7 patch returns a Boolean value to indicate whether it succeeds and set the
error reason into the passed errp, and did not set the errno. Actually another
similar errno-set issue has been talked in last patch. :) If we set the errno in futureqemu_thread_create(), we need to distinguish the Linux
and Windows implementation. For Linux, we can useerror_setg_errno()to set errno.
But for Windows, I am not sure if we can useQuoted 1 line
"errno =
GetLastError()"No, that won't work.
Quoted 4 lines
to set errno, as this seems a little weird. Do you have any idea about this?
BTW, if we have a decent errno-set way for Windows, I will adopt your above proposal for this patch.
According to MS docs,
_beginthreadex()sets errno on failure:If successful, each of these functions returns a handle to the newly created thread; however, if the newly created thread exits too quickly,
_beginthreadmight not return a valid handle. (See the discussion in the Remarks section.) On an error,_beginthreadreturns -1L, and errno is set to EAGAIN if there are too many threads, to EINVAL if the argument is invalid or the stack size is incorrect, or to EACCES if there are insufficient resources (such as memory). On an error,_beginthreadexreturns 0, and errno and_doserrnoare set.https://docs.microsoft.com/cpp/c-runtime-library/reference/beginthread-beginthreadex
Quoted 7 lines
Looks like the current code's use of
GetLastError()after_beginthreadex()failure is wrong.Fix that, and both
qemu_thread_create()implementations set errno on failure, which in turn lets you makeqemu_signalfd_compat()and thusqemu_signalfd()behave sanely regardless of whichqemu_thread_create()implementation they use below the hood.Quoted 15 lines
Thanks for the detail explanation. :)
To fix that, how about replacing the "GetLastError()" with the returned value "hThread" (actually returns 0)? I mean
...
hThread = (HANDLE)_beginthreadex(NULL, 0, win32_start_routine, data, 0, &thread->tid); if (!hThread) {
if (data->mode!=QEMU_THREAD_DETACHED) {DeleteCriticalSection(&data->cs);
}
error_setg_win32(errp, hThread,
"failed to createwin32_start_routine");g_free(data);
return false;
}
Quoted 8 lines
No. On failure,
_beginthreadex()returns *zero*, not an error code. It also sets errno. That's the error code you need to use:hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine, data, 0, &thread->tid); if (!hThread) { error_setg_errno(errp, errno, "can't create thread"); }
Ok, clearer, we also want the errno message to be printed, along with _beginthreadex() sets the errno's value by default. Thanks.
Quoted 4 lines
Except I really wouldn't convert
qemu_thread_create()to Error! I'd make it return zero on success, a negative errno code on failure, and leave the Error business to its callers. Basically, replaceerror_exit(err, ...)by return err.
Emm, I am afraid not converting to Error means it is a little bit trickier to handle for the callers. Especially for migration callers [see patch 7/7], they have no initial errp passed, thus error_setg_xx() seems less useful. Instead in the caller I choose the error_reportf_err(local_err, ...) to only print the detail error message and return that caller's original failing tag. (But for those callers who already have the errp passed, both "return ret" and "convert qemu_thread_create() to Error" are fine to me.)
Besides, there is only one caller needs the errno value, that is qemu_signal_init():
"return -errno". Other callers do not use errno to indicate if it succeeds.
Thus the current patches choose pass Error to hold the detail error message and return a bool to indicate if the function succeeds.
Would you like to share your reason for not converting this function to Error? [1#begin]
Quoted 8 lines
The caller
qemu_signalfd_compat()can then doret = qemu_thread_create(&thread, "signalfd_compat", sigwait_compat, info, QEMU_THREAD_DETACHED); if (ret < 0) { errno = ret; return -1; }
[1#end]
[2#begin]
Quoted 6 lines
A caller that already has an Error **errp parameter could do
ret = qemu_thread_create(...); if (ret < 0) { error_setg_errno(errp, -ret, "<error message goes here>"); }
[2#end]
[3#begin]
Quoted 4 lines
Callers that want to continue aborting on failure simply do
ret = qemu_thread_create(...); assert(ret >= 0);
[3#end]
Quoted 12 lines
If that turns out to be too much of a bother, you could create a convenience wrapper for it:
void qemu_thread_create_nofail(QemuThread *thread, const char *name, void *(*start_routine)(void*), void *arg, int mode) { int err = qemu_thread_create(thread, name, start_routine, arg, mode); if (err) { error_exit(err, __func__); } }
I am wondering the above qemu_thread_create_nofail is a convenience for "[3#begin] => [3#end]" or "[1#begin] => [3#end]"..
If for "[3#begin] => [3#end]", I'd like to use the xxx_nofail wrapper as the error message is more detailed.
If for "[1#begin] => [3#end]", I'd like to explain more for this patch series: we want our qemu code to be more robust by not making qemu exit(-1) after qemu_thread_create() fails and let the callers handle this. E.g. for hmp/qmp callers, make qemu abort() seems too violent if they fails.
Have a nice day
Fei
Re: [Qemu-devel] [PATCH RFC v5 1/7] Fix segmentation fault when qemu_signal_init fails
Kindly ping. :)
Main discuss whether adding the Error for qemu_thread_create() or not. For details, please see blow:
Quoted 12 lines · Fei Li
Sorry for the late reply! Omitted this one..
Quoted 8 lines · Markus Armbruster
Quoted 6 lines · Fei Li
Quoted 5 lines · Markus Armbruster
Quoted 3 lines · Fei Li
Quoted 2 lines · Markus Armbruster
Fei Li <[email protected]> writes:
...snip...
Quoted 60 lines
Quoted 60 lines
Quoted 42 lines
Quoted 35 lines
Quoted 13 lines
For the patch series' current implementation, the modified
qemu_thread_create()
in 7/7 patch returns a Boolean value to indicate whether it succeeds and set the
error reason into the passed errp, and did not set the errno. Actually another
similar errno-set issue has been talked in last patch. :) If we set the errno in futureqemu_thread_create(), we need to distinguish the Linux
and Windows implementation. For Linux, we can useerror_setg_errno()to set errno.
But for Windows, I am not sure if we can useQuoted 1 line
"errno =
GetLastError()"No, that won't work.
Quoted 4 lines
to set errno, as this seems a little weird. Do you have any idea about this?
BTW, if we have a decent errno-set way for Windows, I will adopt your above proposal for this patch.
According to MS docs,
_beginthreadex()sets errno on failure:If successful, each of these functions returns a handle to the newly created thread; however, if the newly created thread exits too quickly,
_beginthreadmight not return a valid handle. (See the discussion in the Remarks section.) On an error,_beginthreadreturns -1L, and errno is set to EAGAIN if there are too many threads, to EINVAL if the argument is invalid or the stack size is incorrect, or to EACCES if there are insufficient resources (such as memory). On an error,_beginthreadexreturns 0, and errno and_doserrnoare set.https://docs.microsoft.com/cpp/c-runtime-library/reference/beginthread-beginthreadex
Quoted 7 lines
Looks like the current code's use of
GetLastError()after_beginthreadex()failure is wrong.Fix that, and both
qemu_thread_create()implementations set errno on failure, which in turn lets you makeqemu_signalfd_compat()and thusqemu_signalfd()behave sanely regardless of whichqemu_thread_create()implementation they use below the hood.Quoted 15 lines
Thanks for the detail explanation. :)
To fix that, how about replacing the "GetLastError()" with the returned value "hThread" (actually returns 0)? I mean
...
hThread = (HANDLE)_beginthreadex(NULL, 0, win32_start_routine, data, 0, &thread->tid); if (!hThread) {
if (data->mode!=QEMU_THREAD_DETACHED) {DeleteCriticalSection(&data->cs);
}
error_setg_win32(errp, hThread,
"failed to createwin32_start_routine");g_free(data);
return false;
}No. On failure,
_beginthreadex()returns *zero*, not an error code. It also sets errno. That's the error code you need to use:
Quoted 8 lines
Quoted 5 lines
hThread = (HANDLE)
_beginthreadex(NULL, 0, win32_start_routine, data, 0, &thread->tid); if (!hThread) {
error_setg_errno(errp, errno, "can't create thread"); }Ok, clearer, we also want the errno message to be printed, along with
_beginthreadex()sets the errno's value by default. Thanks.
The below are my thoughts about why keeping the Error:
Quoted 64 lines
Quoted 4 lines
Except I really wouldn't convert
qemu_thread_create()to Error! I'd make it return zero on success, a negative errno code on failure, and leave the Error business to its callers. Basically, replaceerror_exit(err, ...)by return err.Emm, I am afraid not converting to Error means it is a little bit trickier to handle for the callers. Especially for migration callers [see patch 7/7], they have no initial errp passed, thus
error_setg_xx()seems less useful. Instead in the caller I choose theerror_reportf_err(local_err, ...)to only print the detail error message and return that caller's original failing tag. (But for those callers who already have the errp passed, both "return ret" and "convertqemu_thread_create()to Error" are fine to me.)Besides, there is only one caller needs the errno value, that is
qemu_signal_init():
"return -errno". Other callers do not use errno to indicate if it succeeds.Thus the current patches choose pass Error to hold the detail error message and return a bool to indicate if the function succeeds.
Would you like to share your reason for not converting this function to Error? [1#begin]
Quoted 8 lines
The caller
qemu_signalfd_compat()can then doret =
qemu_thread_create(&thread, "signalfd_compat", sigwait_compat, info, QEMU_THREAD_DETACHED); if (ret < 0) {
errno = ret;
return -1;
}[1#end]
[2#begin]Quoted 6 lines
A caller that already has an Error **errp parameter could do
ret =
qemu_thread_create(...);
if (ret < 0) {
error_setg_errno(errp, -ret, "<error message goes here>"); }[2#end]
[3#begin]Quoted 4 lines
Callers that want to continue aborting on failure simply do
ret =
qemu_thread_create(...);
assert(ret >= 0);[3#end]
Quoted 12 lines
If that turns out to be too much of a bother, you could create a convenience wrapper for it:
void
qemu_thread_create_nofail(QemuThread *thread, const char *name, void *(*start_routine)(void*), void *arg, int mode)
{
int err =qemu_thread_create(thread, name, start_routine, arg, mode); if (err) {
error_exit(err, __func__);
}
}I am wondering the above
qemu_thread_create_nofailis a convenience for "[3#begin] => [3#end]" or "[1#begin] => [3#end]"..
If for "[3#begin] => [3#end]", I'd like to use thexxx_nofailwrapper as the error message is more detailed.
If for "[1#begin] => [3#end]", I'd like to explain more for this patch series: we want our qemu code to be more robust by not making qemu exit(-1) afterqemu_thread_create()fails and let the callers handle this. E.g. for hmp/qmp callers, make qemuabort()seems too violent if they fails.
Quoted 2 lines
Have a nice day
Fei
Have a nice day, thanks
Fei
RFC PATCH v5 2/7 ui/vnc.c: polish vnc_init_func
In reply to Fei LiAdd a new Error parameter for vnc_display_init() to handle errors in its caller: vnc_init_func(), just like vnc_display_open() does. And let the call trace propagate the Error.
Besides, make vnc_start_worker_thread() return a bool to indicate whether it succeeds instead of returning nothing.
--- include/ui/console.h | 2 +- ui/vnc-jobs.c | 9 ++++++--- ui/vnc-jobs.h | 2 +- ui/vnc.c | 12 +++++++++--- 4 files changed, 17 insertions(+), 8 deletions(-)
include/ui/console.h +1 -1
@@ -453,7 +453,7 @@ void qemu_display_early_init(DisplayOptions *opts);void qemu_display_init (DisplayState *ds,DisplayOptions *opts);/* vnc.c */ -void vnc_display_init (const char *id); +void vnc_display_init (const char *id,Error **errp);void vnc_display_open (const char *id,Error **errp);void vnc_display_add_client (const char *id,int csock,bool skipauth);int vnc_display_password (const char *id,const char *password);
ui/vnc-jobs.c +6 -3
@@ -331,15 +331,18 @@ static bool vnc_worker_thread_running(void)return queue;/* Check global queue */ } -void vnc_start_worker_thread (void ) +bool vnc_start_worker_thread (Error **errp) {VncJobQueue *q; -if (vnc_worker_thread_running ()) -return ; +if (vnc_worker_thread_running ()) { + goto out; + } q =vnc_queue_init ();qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, q,QEMU_THREAD_DETACHED ); queue = q;/* Set global queue */ +out: +return true; }
ui/vnc-jobs.h +1 -1
@@ -37,7 +37,7 @@ void vnc_job_push(VncJob *job);void vnc_jobs_join (VncState *vs);void vnc_jobs_consume_buffer (VncState *vs); -void vnc_start_worker_thread (void ); +bool vnc_start_worker_thread (Error **errp);/* Locks */ static inline int vnc_trylock_display (VncDisplay *vd)
ui/vnc.c +9 -3
@@ -3205,7 +3205,7 @@ static const DisplayChangeListenerOps dcl_ops = { .dpy_cursor_define = vnc_dpy_cursor_define, }; -void vnc_display_init (const char *id) +void vnc_display_init (const char *id,Error **errp) {VncDisplay *vd;
@@ -3235,7 +3235,9 @@ void vnc_display_init(const char *id) vd->connections_limit =32 ;qemu_mutex_init (&vd->mutex); -vnc_start_worker_thread (); +if (!vnc_start_worker_thread (errp)) { +return ; + } vd->dcl.ops = &dcl_ops;register_displaychangelistener (&vd->dcl);
@@ -4079,7 +4081,11 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)char *id = (char *)qemu_opts_id (opts);assert (id); -vnc_display_init (id); +vnc_display_init (id, &local_err); +if (local_err) { +error_reportf_err (local_err,"Failed to init VNC server: " ); +exit (1 ); + }vnc_display_open (id, &local_err);if (local_err !=NULL ) {error_reportf_err (local_err,"Failed to start VNC server: " );
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH RFC v5 2/7] ui/vnc.c: polish vnc_init_func
Quoted 45 lines · Fei Li
Add a new Error parameter for
vnc_display_init()to handle errors in its caller:vnc_init_func(), just likevnc_display_open()does. And let the call trace propagate the Error.Besides, make
vnc_start_worker_thread()return a bool to indicate whether it succeeds instead of returning nothing.Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- include/ui/console.h | 2 +- ui/vnc-jobs.c | 9 ++++++--- ui/vnc-jobs.h | 2 +- ui/vnc.c | 12 +++++++++--- 4 files changed, 17 insertions(+), 8 deletions(-)include/ui/console.h +1
-1@@ -453,7 +453,7 @@ void qemu_display_early_init(DisplayOptions *opts);void qemu_display_init (DisplayState *ds,DisplayOptions *opts);/* vnc.c */ -void vnc_display_init (const char *id); +void vnc_display_init (const char *id,Error **errp);void vnc_display_open (const char *id,Error **errp);void vnc_display_add_client (const char *id,int csock,bool skipauth);int vnc_display_password (const char *id,const char *password);ui/vnc-jobs.c +2
-3@@ -331,15 +331,18 @@ static bool vnc_worker_thread_running(void)return queue;/* Check global queue */ } -void vnc_start_worker_thread (void ) +bool vnc_start_worker_thread (Error **errp) {VncJobQueue *q; -if (vnc_worker_thread_running ()) -return ; +if (vnc_worker_thread_running ()) {
ui/vnc-jobs.c static bool vnc_worker_thread_running(void) · line 348
Quoted 10 lines
ui/vnc-jobs.c +4
-0+ goto out; + } q =vnc_queue_init ();qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, q,QEMU_THREAD_DETACHED ); queue = q;/* Set global queue */ +out: +return true; }
This function cannot fail. Why convert it to Error, and complicate its caller?
Quoted 18 lines
ui/vnc-jobs.h +1
-1@@ -37,7 +37,7 @@ void vnc_job_push(VncJob *job);void vnc_jobs_join (VncState *vs);void vnc_jobs_consume_buffer (VncState *vs); -void vnc_start_worker_thread (void ); +bool vnc_start_worker_thread (Error **errp);/* Locks */ static inline int vnc_trylock_display (VncDisplay *vd)ui/vnc.c +0
-0
ui/vnc.c static const DisplayChangeListenerOps dcl_ops = { · line 3211
Quoted 8 lines
ui/vnc.c +1
-1@@ -3205,7 +3205,7 @@ static const DisplayChangeListenerOps dcl_ops = { .dpy_cursor_define = vnc_dpy_cursor_define, }; -void vnc_display_init (const char *id) +void vnc_display_init (const char *id,Error **errp) {VncDisplay *vd;
if (vnc_display_find(id) != NULL) {
return;
}
vd = g_malloc0(sizeof(*vd));
vd->id = strdup(id);
QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
QTAILQ_INIT(&vd->clients);
vd->expires = TIME_MAX;
if (keyboard_layout) {
trace_vnc_key_map_init(keyboard_layout);
vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
} else {
vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
}
if (!vd->kbd_layout) {
exit(1);Uh, init_keyboard_layout() reports errors to stderr, and the exit(1) here makes them fatal. Okay before this patch, but inappropriate afterwards. I'm afraid you have to convert init_keyboard_layout() to Error first.
}
vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;Quoted 14 lines
ui/vnc.c +3
-1@@ -3235,7 +3235,9 @@ void vnc_display_init(const char *id) vd->connections_limit =32 ;qemu_mutex_init (&vd->mutex); -vnc_start_worker_thread (); +if (!vnc_start_worker_thread (errp)) { +return ; + } vd->dcl.ops = &dcl_ops;register_displaychangelistener (&vd->dcl);@@ -4079,7 +4081,11 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)char *id = (char *)qemu_opts_id (opts);
ui/vnc.c int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp) · line 4091
Quoted 10 lines
ui/vnc.c +5
-1assert (id); -vnc_display_init (id); +vnc_display_init (id, &local_err); +if (local_err) { +error_reportf_err (local_err,"Failed to init VNC server: " ); +exit (1 ); + }vnc_display_open (id, &local_err);if (local_err !=NULL ) {error_reportf_err (local_err,"Failed to start VNC server: " );
Conflicts with my "[PATCH 24/31] vl: Clean up error reporting in vnc_init_func()". Your patch shows that mine is incomplete.
Without my patch, there's no real reason for yours, however. The two should be squashed together.
Re: [Qemu-devel] [PATCH RFC v5 2/7] ui/vnc.c: polish vnc_init_func
Quoted 50 lines · Markus Armbruster
Quoted 48 lines · Fei Li
Add a new Error parameter for
vnc_display_init()to handle errors in its caller:vnc_init_func(), just likevnc_display_open()does. And let the call trace propagate the Error.Besides, make
vnc_start_worker_thread()return a bool to indicate whether it succeeds instead of returning nothing.Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- include/ui/console.h | 2 +- ui/vnc-jobs.c | 9 ++++++--- ui/vnc-jobs.h | 2 +- ui/vnc.c | 12 +++++++++--- 4 files changed, 17 insertions(+), 8 deletions(-)include/ui/console.h +1
-1@@ -453,7 +453,7 @@ void qemu_display_early_init(DisplayOptions *opts);void qemu_display_init (DisplayState *ds,DisplayOptions *opts);/* vnc.c */ -void vnc_display_init (const char *id); +void vnc_display_init (const char *id,Error **errp);void vnc_display_open (const char *id,Error **errp);void vnc_display_add_client (const char *id,int csock,bool skipauth);int vnc_display_password (const char *id,const char *password);ui/vnc-jobs.c +4
-3@@ -331,15 +331,18 @@ static bool vnc_worker_thread_running(void)return queue;/* Check global queue */ } -void vnc_start_worker_thread (void ) +bool vnc_start_worker_thread (Error **errp) {VncJobQueue *q; -if (vnc_worker_thread_running ()) -return ; +if (vnc_worker_thread_running ()) { + goto out; + }
Quoted 9 lines
ui/vnc-jobs.c static bool vnc_worker_thread_running(void) · line 348
Quoted 7 lines
ui/vnc-jobs.c +2
-0q =vnc_queue_init ();qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, q,QEMU_THREAD_DETACHED ); queue = q;/* Set global queue */ +out: +return true; }This function cannot fail. Why convert it to Error, and complicate its caller?
[Issue1]
Actually, this is to pave the way for patch 7/7, in case qemu_thread_create() fails. Patch 7/7 is long enough, thus I wrote the patch 1/2/3 separately to mainly connects the broken errp for callers who initially have the errp.
[I am back... If the other codes in this patches be squashed, maybe merge [Issue1] into patch 7/7 looks more intuitive.]
Quoted 47 lines
Quoted 18 lines
ui/vnc-jobs.h +1
-1@@ -37,7 +37,7 @@ void vnc_job_push(VncJob *job);void vnc_jobs_join (VncState *vs);void vnc_jobs_consume_buffer (VncState *vs); -void vnc_start_worker_thread (void ); +bool vnc_start_worker_thread (Error **errp);/* Locks */ static inline int vnc_trylock_display (VncDisplay *vd)ui/vnc.c +0
-0ui/vnc.c static const DisplayChangeListenerOps dcl_ops = { · line 3211
Quoted 8 lines
ui/vnc.c +1
-1@@ -3205,7 +3205,7 @@ static const DisplayChangeListenerOps dcl_ops = { .dpy_cursor_define = vnc_dpy_cursor_define, }; -void vnc_display_init (const char *id) +void vnc_display_init (const char *id,Error **errp) {VncDisplay *vd;if (vnc_display_find(id) != NULL) { return; } vd = g_malloc0(sizeof(*vd)); vd->id = strdup(id); QTAILQ_INSERT_TAIL(&vnc_displays, vd, next); QTAILQ_INIT(&vd->clients); vd->expires = TIME_MAX; if (keyboard_layout) { trace_vnc_key_map_init(keyboard_layout); vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); } else { vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us"); } if (!vd->kbd_layout) { exit(1);
Quoted 4 lines
Uh,
init_keyboard_layout()reports errors to stderr, and the exit(1) here makes them fatal. Okay before this patch, but inappropriate afterwards. I'm afraid you have to convertinit_keyboard_layout()to Error first.
[Issue2]
Right. But I notice the returned kbd_layout_t *kbd_layout is a static value and also will be used by others, how about passing the errp parameter to init_keyboard_layout() as follows? And for its other callers, just pass NULL.
@@ -3222,13 +3222,13 @@ void vnc_display_init(const char *id, Error **errp)
if (keyboard_layout) {
trace_vnc_key_map_init(keyboard_layout);
- vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); + vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout, errp); } else {
- vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us"); + vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us", errp); }
if (!vd->kbd_layout) {
- exit(1);
+ return;
}
Quoted 31 lines
} vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;Quoted 14 lines
ui/vnc.c +3
-1@@ -3235,7 +3235,9 @@ void vnc_display_init(const char *id) vd->connections_limit =32 ;qemu_mutex_init (&vd->mutex); -vnc_start_worker_thread (); +if (!vnc_start_worker_thread (errp)) { +return ; + } vd->dcl.ops = &dcl_ops;register_displaychangelistener (&vd->dcl);@@ -4079,7 +4081,11 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)char *id = (char *)qemu_opts_id (opts);ui/vnc.c int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp) · line 4091
Quoted 10 lines
ui/vnc.c +5
-1assert (id); -vnc_display_init (id); +vnc_display_init (id, &local_err); +if (local_err) { +error_reportf_err (local_err,"Failed to init VNC server: " ); +exit (1 ); + }vnc_display_open (id, &local_err);if (local_err !=NULL ) {error_reportf_err (local_err,"Failed to start VNC server: " );Conflicts with my "[PATCH 24/31] vl: Clean up error reporting in
vnc_init_func()". Your patch shows that mine is incomplete.
Quoted 2 lines
Without my patch, there's no real reason for yours, however. The two should be squashed together.
Ah, I noticed your patch 24/31. OK, let's squash. Should I write a new patch by
- updating to error_propagate(...) if vnc_display_init() fails &&
- modifying [Issue2] ?
Or you do this in your original patch?
BTW, for your patch 24/31, the updated passed errp for vnc_init_func is &error_fatal, then the system will exit(1) when running error_propagate(...) which calls error_handle_fatal(...). This means the following two lines will not be touched. But if we want the following prepended error message, could we move it earlier than the error_propagare? I mean:
if (local_err != NULL) {
- error_reportf_err(local_err, "Failed to start VNC server: "); - exit(1);
+ error_prepend(&local_err, "Failed to start VNC server: "); + error_propagate(errp, local_err);
+ return -1;
}
Have a nice day
Fei
Re: [Qemu-devel] [PATCH RFC v5 2/7] ui/vnc.c: polish vnc_init_func
Quoted 125 lines · Fei Li
Quoted 47 lines · Markus Armbruster
Quoted 45 lines · Fei Li
Add a new Error parameter for
vnc_display_init()to handle errors in its caller:vnc_init_func(), just likevnc_display_open()does. And let the call trace propagate the Error.Besides, make
vnc_start_worker_thread()return a bool to indicate whether it succeeds instead of returning nothing.Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- include/ui/console.h | 2 +- ui/vnc-jobs.c | 9 ++++++--- ui/vnc-jobs.h | 2 +- ui/vnc.c | 12 +++++++++--- 4 files changed, 17 insertions(+), 8 deletions(-)include/ui/console.h +1
-1@@ -453,7 +453,7 @@ void qemu_display_early_init(DisplayOptions *opts);void qemu_display_init (DisplayState *ds,DisplayOptions *opts);/* vnc.c */ -void vnc_display_init (const char *id); +void vnc_display_init (const char *id,Error **errp);void vnc_display_open (const char *id,Error **errp);void vnc_display_add_client (const char *id,int csock,bool skipauth);int vnc_display_password (const char *id,const char *password);ui/vnc-jobs.c +4
-1@@ -331,15 +331,18 @@ static bool vnc_worker_thread_running(void)return queue;/* Check global queue */ } -void vnc_start_worker_thread(void) +bool vnc_start_worker_thread(Error **errp) {VncJobQueue *q; - if (vnc_worker_thread_running()) - return ; +if (vnc_worker_thread_running ()) { + goto out; + } q =vnc_queue_init ();Quoted 8 lines
ui/vnc-jobs.c static bool vnc_worker_thread_running(void) · line 348
Quoted 6 lines
ui/vnc-jobs.c +2
-0qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, q,QEMU_THREAD_DETACHED ); queue = q;/* Set global queue */ +out: +return true; }This function cannot fail. Why convert it to Error, and complicate its caller?
[Issue1]
Actually, this is to pave the way for patch 7/7, in caseqemu_thread_create()fails.
Patch 7/7 is long enough, thus I wrote the patch 1/2/3 separately to mainly connects the broken errp for callers who initially have the errp.[I am back... If the other codes in this patches be squashed, maybe merge [Issue1]
into patch 7/7 looks more intuitive.]Quoted 44 lines
Quoted 16 lines
ui/vnc-jobs.h +1
-1@@ -37,7 +37,7 @@ void vnc_job_push(VncJob *job);void vnc_jobs_join (VncState *vs);void vnc_jobs_consume_buffer (VncState *vs); -void vnc_start_worker_thread (void ); +bool vnc_start_worker_thread (Error **errp);/* Locks */ static inline int vnc_trylock_display (VncDisplay *vd)ui/vnc.c +0
-0ui/vnc.c static const DisplayChangeListenerOps dcl_ops = { · line 3211
Quoted 7 lines
ui/vnc.c +1
-0@@ -3205,7 +3205,7 @@ static const DisplayChangeListenerOps dcl_ops = { .dpy_cursor_define = vnc_dpy_cursor_define, }; -void vnc_display_init(const char *id) +void vnc_display_init(const char *id, Error **errp) {VncDisplay *vd;if (vnc_display_find(id) != NULL) { return; } vd = g_malloc0(sizeof(*vd)); vd->id = strdup(id); QTAILQ_INSERT_TAIL(&vnc_displays, vd, next); QTAILQ_INIT(&vd->clients); vd->expires = TIME_MAX; if (keyboard_layout) { trace_vnc_key_map_init(keyboard_layout); vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); } else { vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us"); } if (!vd->kbd_layout) { exit(1);Quoted 4 lines
Uh,
init_keyboard_layout()reports errors to stderr, and the exit(1) here makes them fatal. Okay before this patch, but inappropriate afterwards. I'm afraid you have to convertinit_keyboard_layout()to Error first.[Issue2]
Right. But I notice the returnedkbd_layout_t*kbd_layoutis a static value and also
will be used by others, how about passing the errp parameter toinit_keyboard_layout()
as follows? And for its other callers, just pass NULL.(quoted diff) +0
-1@@ -3222,13 +3222,13 @@ void vnc_display_init(const char *id, Error **errp) if (keyboard_layout) { trace_vnc_key_map_init(keyboard_layout); - vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
Review void vnc_display_init(const char *id, Error **errp) · line 3232
Quoted 10 lines
(quoted diff) +3
-2+ vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout, errp); } else { - vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us"); + vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us", errp); } if (!vd->kbd_layout) { - exit(1); + return; }
Sounds good to me, except you should pass &error_fatal instead of NULL to preserve "report error and exit" semantics.
Quoted 28 lines
Quoted 28 lines
} vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;Quoted 11 lines
ui/vnc.c +3
-1@@ -3235,7 +3235,9 @@ void vnc_display_init(const char *id) vd->connections_limit =32 ;qemu_mutex_init (&vd->mutex); -vnc_start_worker_thread (); +if (!vnc_start_worker_thread (errp)) { +return ; + } vd->dcl.ops = &dcl_ops;register_displaychangelistener (&vd->dcl);@@ -4079,7 +4081,11 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)char *id = (char *)qemu_opts_id (opts);ui/vnc.c int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp) · line 4090
Quoted 10 lines
ui/vnc.c +5
-1assert (id); -vnc_display_init (id); +vnc_display_init (id, &local_err); +if (local_err) { +error_reportf_err (local_err,"Failed to init VNC server: " ); +exit (1 ); + }vnc_display_open (id, &local_err);if (local_err !=NULL ) {error_reportf_err (local_err,"Failed to start VNC server: " );Conflicts with my "[PATCH 24/31] vl: Clean up error reporting in
vnc_init_func()". Your patch shows that mine is incomplete.
Quoted 8 lines
Quoted 2 lines
Without my patch, there's no real reason for yours, however. The two should be squashed together.
Ah, I noticed your patch 24/31. OK, let's squash. Should I write a new patch by
- updating toerror_propagate(...)ifvnc_display_init()fails &&
- modifying [Issue2] ?
Or you do this in your original patch?
If you send a v2 along that lines, I'll probably pick your patch into my series. Should work even in case your series gets merged first.
Quoted 9 lines
BTW, for your patch 24/31, the updated passed errp for
vnc_init_funcis&error_fatal,
then the system will exit(1) when runningerror_propagate(...)which callserror_handle_fatal(...). This means the following two lines will not be touched.
But if we want the following prepended error message, could we move it earlier than
theerror_propagare? I mean:
Quoted 7 lines
if (
local_err!= NULL) {
-error_reportf_err(local_err, "Failed to start VNC server: "); - exit(1);
+error_prepend(&local_err, "Failed to start VNC server: "); +error_propagate(errp, local_err);
+ return -1;
}
Both
error_propagate(errp, local_err);
error_prepend(errp, "Failed to start VNC server: ");and
error_prepend(&local_err, "Failed to start VNC server: ");
error_propagate(errp, local_err);work. The former is slightly more efficient when errp is null. But you're right, it fails to include the "Failed to start VNC server: " prefix with &error_fatal. Thus, the latter is preferrable.
Re: [Qemu-devel] [PATCH RFC v5 2/7] ui/vnc.c: polish vnc_init_func
Quoted 133 lines · Markus Armbruster
Quoted 131 lines · Fei Li
Quoted 47 lines · Markus Armbruster
Quoted 45 lines · Fei Li
Add a new Error parameter for
vnc_display_init()to handle errors in its caller:vnc_init_func(), just likevnc_display_open()does. And let the call trace propagate the Error.Besides, make
vnc_start_worker_thread()return a bool to indicate whether it succeeds instead of returning nothing.Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- include/ui/console.h | 2 +- ui/vnc-jobs.c | 9 ++++++--- ui/vnc-jobs.h | 2 +- ui/vnc.c | 12 +++++++++--- 4 files changed, 17 insertions(+), 8 deletions(-)include/ui/console.h +1
-1@@ -453,7 +453,7 @@ void qemu_display_early_init(DisplayOptions *opts);void qemu_display_init (DisplayState *ds,DisplayOptions *opts);/* vnc.c */ -void vnc_display_init (const char *id); +void vnc_display_init (const char *id,Error **errp);void vnc_display_open (const char *id,Error **errp);void vnc_display_add_client (const char *id,int csock,bool skipauth);int vnc_display_password (const char *id,const char *password);ui/vnc-jobs.c +4
-1@@ -331,15 +331,18 @@ static bool vnc_worker_thread_running(void)return queue;/* Check global queue */ } -void vnc_start_worker_thread(void) +bool vnc_start_worker_thread(Error **errp) {VncJobQueue *q; - if (vnc_worker_thread_running()) - return ; +if (vnc_worker_thread_running ()) { + goto out; + } q =vnc_queue_init ();Quoted 8 lines
ui/vnc-jobs.c static bool vnc_worker_thread_running(void) · line 348
Quoted 6 lines
ui/vnc-jobs.c +2
-0qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, q,QEMU_THREAD_DETACHED ); queue = q;/* Set global queue */ +out: +return true; }This function cannot fail. Why convert it to Error, and complicate its caller?
[Issue1]
Actually, this is to pave the way for patch 7/7, in caseqemu_thread_create()fails.
Patch 7/7 is long enough, thus I wrote the patch 1/2/3 separately to mainly connects the broken errp for callers who initially have the errp.[I am back... If the other codes in this patches be squashed, maybe merge [Issue1]
into patch 7/7 looks more intuitive.]Quoted 44 lines
Quoted 16 lines
ui/vnc-jobs.h +1
-1@@ -37,7 +37,7 @@ void vnc_job_push(VncJob *job);void vnc_jobs_join (VncState *vs);void vnc_jobs_consume_buffer (VncState *vs); -void vnc_start_worker_thread (void ); +bool vnc_start_worker_thread (Error **errp);/* Locks */ static inline int vnc_trylock_display (VncDisplay *vd)ui/vnc.c +0
-0ui/vnc.c static const DisplayChangeListenerOps dcl_ops = { · line 3211
Quoted 7 lines
ui/vnc.c +1
-0@@ -3205,7 +3205,7 @@ static const DisplayChangeListenerOps dcl_ops = { .dpy_cursor_define = vnc_dpy_cursor_define, }; -void vnc_display_init(const char *id) +void vnc_display_init(const char *id, Error **errp) {VncDisplay *vd;if (vnc_display_find(id) != NULL) { return; } vd = g_malloc0(sizeof(*vd)); vd->id = strdup(id); QTAILQ_INSERT_TAIL(&vnc_displays, vd, next); QTAILQ_INIT(&vd->clients); vd->expires = TIME_MAX; if (keyboard_layout) { trace_vnc_key_map_init(keyboard_layout); vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); } else { vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us"); } if (!vd->kbd_layout) { exit(1);Quoted 4 lines
Uh,
init_keyboard_layout()reports errors to stderr, and the exit(1) here makes them fatal. Okay before this patch, but inappropriate afterwards. I'm afraid you have to convertinit_keyboard_layout()to Error first.[Issue2]
Right. But I notice the returnedkbd_layout_t*kbd_layoutis a static value and also
will be used by others, how about passing the errp parameter toinit_keyboard_layout()
as follows? And for its other callers, just pass NULL.(quoted diff) +2
-2@@ -3222,13 +3222,13 @@ void vnc_display_init(const char *id, Error **errp) if (keyboard_layout) { trace_vnc_key_map_init(keyboard_layout); - vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); + vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout, errp); } else { - vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us"); + vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us", errp); }
Quoted 6 lines
Review void vnc_display_init(const char *id, Error **errp) · line 3232
Quoted 4 lines
(quoted diff) +1
-1if (!vd->kbd_layout) { - exit(1); + return; }Sounds good to me, except you should pass
&error_fatalinstead of NULL to preserve "report error and exit" semantics.
Yes, you are right. I should pass &error_fatal and let the following error_setg() handle this.
@@ -94,7 +94,7 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, f = filename ? fopen(filename, "r") : NULL;
g_free(filename);
if (!f) {
- fprintf(stderr, "Could not read keymap file: '%s'\n", language); + error_setg(errp, "could not read keymap file: '%s'\n", language); return NULL;
}
Quoted 30 lines
Quoted 30 lines
(quoted diff) +0
-0> }Quoted 28 lines
vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;Quoted 11 lines
ui/vnc.c +3
-1@@ -3235,7 +3235,9 @@ void vnc_display_init(const char *id) vd->connections_limit =32 ;qemu_mutex_init (&vd->mutex); -vnc_start_worker_thread (); +if (!vnc_start_worker_thread (errp)) { +return ; + } vd->dcl.ops = &dcl_ops;register_displaychangelistener (&vd->dcl);@@ -4079,7 +4081,11 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)char *id = (char *)qemu_opts_id (opts);ui/vnc.c int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp) · line 4090
Quoted 10 lines
ui/vnc.c +5
-1assert (id); -vnc_display_init (id); +vnc_display_init (id, &local_err); +if (local_err) { +error_reportf_err (local_err,"Failed to init VNC server: " ); +exit (1 ); + }vnc_display_open (id, &local_err);if (local_err !=NULL ) {error_reportf_err (local_err,"Failed to start VNC server: " );Conflicts with my "[PATCH 24/31] vl: Clean up error reporting in
vnc_init_func()". Your patch shows that mine is incomplete.Without my patch, there's no real reason for yours, however. The two should be squashed together.
Quoted 8 lines
Quoted 6 lines
Ah, I noticed your patch 24/31. OK, let's squash. Should I write a new patch by
- updating toerror_propagate(...)ifvnc_display_init()fails &&
- modifying [Issue2] ?
Or you do this in your original patch?If you send a v2 along that lines, I'll probably pick your patch into my series. Should work even in case your series gets merged first.
Good idea. I will send a separate v2 patch which also include the above change mentioned in [Issue1].
Quoted 22 lines
Quoted 10 lines
BTW, for your patch 24/31, the updated passed errp for
vnc_init_funcis&error_fatal,
then the system will exit(1) when runningerror_propagate(...)which callserror_handle_fatal(...). This means the following two lines will not be touched.
But if we want the following prepended error message, could we move it earlier than
theerror_propagare? I mean:Quoted 7 lines
if (
local_err!= NULL) {
-error_reportf_err(local_err, "Failed to start VNC server: "); - exit(1);
+error_prepend(&local_err, "Failed to start VNC server: "); +error_propagate(errp, local_err);
+ return -1;
}Both
error_propagate(errp, local_err); error_prepend(errp, "Failed to start VNC server: ");
Quoted 10 lines
and
error_prepend(&local_err, "Failed to start VNC server: "); error_propagate(errp, local_err);work. The former is slightly more efficient when errp is null. But you're right, it fails to include the "Failed to start VNC server: " prefix with
&error_fatal. Thus, the latter is preferrable.
Have a nice day, thanks
Fei
Re: [Qemu-devel] [PATCH RFC v5 2/7] ui/vnc.c: polish vnc_init_func
Quoted 197 lines · Fei Li
Quoted 138 lines · Markus Armbruster
Quoted 136 lines · Fei Li
Quoted 48 lines · Markus Armbruster
Quoted 46 lines · Fei Li
Add a new Error parameter for
vnc_display_init()to handle errors in its caller:vnc_init_func(), just likevnc_display_open()does. And let the call trace propagate the Error.Besides, make
vnc_start_worker_thread()return a bool to indicate whether it succeeds instead of returning nothing.Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>---
include/ui/console.h| 2 +-
ui/vnc-jobs.c | 9 ++++++---
ui/vnc-jobs.h | 2 +-
ui/vnc.c | 12 +++++++++---4 files changed, 17 insertions(+), 8 deletions(-)include/ui/console.h +1
-1@@ -453,7 +453,7 @@ void qemu_display_early_init(DisplayOptions *opts); void qemu_display_init(DisplayState *ds, DisplayOptions *opts); /* vnc.c */ -void vnc_display_init (const char *id); +void vnc_display_init (const char *id,Error **errp); void vnc_display_open(const char *id, Error **errp); void vnc_display_add_client(const char *id, int csock, bool skipauth); int vnc_display_password(const char *id, const char *password);ui/vnc-jobs.c +0
-0@@ -331,15 +331,18 @@ static bool vnc_worker_thread_running(void)return queue; /* Check global queue */
}
-voidvnc_start_worker_thread(void)
+boolvnc_start_worker_thread(Error **errp)
{
VncJobQueue *q;
- if (vnc_worker_thread_running())
- return ;
+ if (vnc_worker_thread_running()) {
+ goto out;
+ }
q =vnc_queue_init();Quoted 8 lines
Quoted 6 lines
qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q, QEMU_THREAD_DETACHED);
queue = q; /* Set global queue */
+out:
+ return true;
}This function cannot fail. Why convert it to Error, and complicate its caller?
[Issue1]
Actually, this is to pave the way for patch 7/7, in caseqemu_thread_create()fails.
Patch 7/7 is long enough, thus I wrote the patch 1/2/3 separately to mainly connects the broken errp for callers who initially have the errp.[I am back... If the other codes in this patches be squashed, maybe merge [Issue1]
into patch 7/7 looks more intuitive.]Quoted 41 lines
Quoted 16 lines
ui/vnc-jobs.h +1
-1@@ -37,7 +37,7 @@ void vnc_job_push(VncJob *job); void vnc_jobs_join(VncState *vs); void vnc_jobs_consume_buffer(VncState *vs); -void vnc_start_worker_thread (void ); +bool vnc_start_worker_thread (Error **errp); /* Locks */ static inline int vnc_trylock_display(VncDisplay *vd)ui/vnc.c +0
-0ui/vnc.c static const DisplayChangeListenerOps · line 3211
Quoted 7 lines
ui/vnc.c +1
-0@@ -3205,7 +3205,7 @@ static const DisplayChangeListenerOps dcl_ops = { .dpy_cursor_define = vnc_dpy_cursor_define, }; -void vnc_display_init(const char *id) +void vnc_display_init(const char *id, Error **errp) { VncDisplay *vd;if (
vnc_display_find(id)!= NULL) {
return;
}
vd = g_malloc0(sizeof(*vd));
vd->id= strdup(id);QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
QTAILQ_INIT(&vd->clients);
vd->expires=TIME_MAX;if (
keyboard_layout) {trace_vnc_key_map_init(keyboard_layout);
vd->kbd_layout=init_keyboard_layout(name2keysym, keyboard_layout); } else {
vd->kbd_layout=init_keyboard_layout(name2keysym, "en-us"); }Quoted 7 lines
if (!vd->kbd_layout) {
exit(1);Uh,
init_keyboard_layout()reports errors to stderr, and the exit(1) here makes them fatal. Okay before this patch, but inappropriate afterwards. I'm afraid you have to convertinit_keyboard_layout()to Error first.[Issue2]
Right. But I notice the returnedkbd_layout_t*kbd_layoutis a static value and also
will be used by others, how about passing the errp parameter toinit_keyboard_layout()
as follows? And for its other callers, just pass NULL.(quoted diff) +2
-2@@ -3222,13 +3222,13 @@ void vnc_display_init(const char *id, Error **errp) if (keyboard_layout) { trace_vnc_key_map_init(keyboard_layout); - vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); + vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout, errp); } else { - vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us"); + vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us", errp); }Quoted 6 lines
Quoted 4 lines
(quoted diff) +1
-1if (!vd->kbd_layout) { - exit(1); + return;}
Sounds good to me, except you should pass
&error_fatalinstead of NULL to preserve "report error and exit" semantics.Yes, you are right. I should pass
&error_fataland let the followingerror_setg()handle this.(quoted diff) +1
-1@@ -94,7 +94,7 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table, f = filename ? fopen(filename, "r") : NULL; g_free(filename); if (!f) { - fprintf(stderr, "Could not read keymap file: '%s'\n", language); + error_setg(errp, "could not read keymap file: '%s'\n", language); return NULL;}
Quoted 37 lines
Quoted 37 lines
Quoted 29 lines
}
vd->share_policy=VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;Quoted 12 lines
ui/vnc.c +3
-1@@ -3235,7 +3235,9 @@ void vnc_display_init(const char *id) vd->connections_limit = 32; qemu_mutex_init(&vd->mutex); - vnc_start_worker_thread(); + if (!vnc_start_worker_thread(errp)) { + return; + } vd->dcl.ops = &dcl_ops; register_displaychangelistener(&vd->dcl);@@ -4079,7 +4081,11 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp) char *id = (char *)qemu_opts_id(opts);ui/vnc.c int vnc_init_func(void *opaque, QemuOpts · line 4091
Quoted 10 lines
ui/vnc.c +5
-1assert(id); - vnc_display_init(id); + vnc_display_init(id, &local_err); + if (local_err) { + error_reportf_err(local_err, "Failed to init VNC server: "); + exit(1); + } vnc_display_open(id, &local_err); if (local_err != NULL) { error_reportf_err(local_err, "Failed to start VNC server: ");Conflicts with my "[PATCH 24/31] vl: Clean up error reporting in vnc_init_func()". Your patch shows that mine is incomplete.
Quoted 2 lines
Without my patch, there's no real reason for yours, however. The two should be squashed together.
Ah, I noticed your patch 24/31. OK, let's squash. Should I write a new patch by
- updating toerror_propagate(...)ifvnc_display_init()fails &&
- modifying [Issue2] ?
Or you do this in your original patch?
Quoted 4 lines
Quoted 2 lines
If you send a v2 along that lines, I'll probably pick your patch into my series. Should work even in case your series gets merged first.
Good idea. I will send a separate v2 patch which also include the above change mentioned in [Issue1].
After thinking twice, I think move the above change mentioned in [Issue1] to patch 7/7 is better. Thus my next separate v2 will not include it.
Quoted 37 lines
Quoted 22 lines
Quoted 10 lines
BTW, for your patch 24/31, the updated passed errp for
vnc_init_funcis&error_fatal,
then the system will exit(1) when runningerror_propagate(...)which callserror_handle_fatal(...). This means the following two lines will not be touched.
But if we want the following prepended error message, could we move it earlier than
theerror_propagare? I mean:Quoted 7 lines
if (
local_err!= NULL) {
-error_reportf_err(local_err, "Failed to start VNC server: "); - exit(1);
+error_prepend(&local_err, "Failed to start VNC server: "); +error_propagate(errp, local_err);
+ return -1;
}Both
error_propagate(errp, local_err);error_prepend(errp, "Failed to start VNC server: ");Quoted 10 lines
and
error_prepend(&local_err, "Failed to start VNC server: ");error_propagate(errp, local_err);work. The former is slightly more efficient when errp is null. But you're right, it fails to include the "Failed to start VNC server: " prefix with &error_fatal. Thus, the latter is preferrable.
Have a nice day, thanks
Fei
RFC PATCH v5 3/7 qemu_init_vcpu: add a new Error parameter to propagate
In reply to Fei LiThe caller of qemu_init_vcpu() already passed the **errp to handle errors. In view of this, add a new Error parameter to the following call trace to propagate the error and let the further caller check it.
Besides, make qemu_init_vcpu() return a Boolean value to let its callers know whether it succeeds.
--- accel/tcg/user-exec-stub.c | 2 +- cpus.c | 34 +++++++++++++++++++++------------- include/qom/cpu.h | 2 +- target/alpha/cpu.c | 4 +++- target/arm/cpu.c | 4 +++- target/cris/cpu.c | 4 +++- target/hppa/cpu.c | 4 +++- target/i386/cpu.c | 4 +++- target/lm32/cpu.c | 4 +++- target/m68k/cpu.c | 4 +++- target/microblaze/cpu.c | 4 +++- target/mips/cpu.c | 4 +++- target/moxie/cpu.c | 4 +++- target/nios2/cpu.c | 4 +++- target/openrisc/cpu.c | 4 +++- target/ppc/translate_init.inc.c | 4 +++- target/riscv/cpu.c | 4 +++- target/s390x/cpu.c | 4 +++- target/sh4/cpu.c | 4 +++- target/sparc/cpu.c | 4 +++- target/tilegx/cpu.c | 4 +++- target/tricore/cpu.c | 4 +++- target/unicore32/cpu.c | 4 +++- target/xtensa/cpu.c | 4 +++- 24 files changed, 86 insertions(+), 36 deletions(-)
accel/tcg/user-exec-stub.c +1 -1
@@ -10,7 +10,7 @@ void cpu_resume(CPUState *cpu) { } -void qemu_init_vcpu (CPUState *cpu) +bool qemu_init_vcpu (CPUState *cpu,Error **errp) { }
cpus.c +21 -13
@@ -1918,7 +1918,7 @@ void cpu_remove_sync(CPUState *cpu)/* For temporary buffers for forming a name */ #define VCPU_THREAD_NAME_SIZE 16 -static void qemu_tcg_init_vcpu (CPUState *cpu) +static void qemu_tcg_init_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];static QemuCond *single_tcg_halt_cond;
@@ -1974,7 +1974,7 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) } } -static void qemu_hax_start_vcpu (CPUState *cpu) +static void qemu_hax_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];
@@ -1991,7 +1991,7 @@ static void qemu_hax_start_vcpu(CPUState *cpu)#endif } -static void qemu_kvm_start_vcpu (CPUState *cpu) +static void qemu_kvm_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];
@@ -2004,7 +2004,7 @@ static void qemu_kvm_start_vcpu(CPUState *cpu) cpu, QEMU_THREAD_JOINABLE); } -static void qemu_hvf_start_vcpu (CPUState *cpu) +static void qemu_hvf_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];
@@ -2022,7 +2022,7 @@ static void qemu_hvf_start_vcpu(CPUState *cpu) cpu, QEMU_THREAD_JOINABLE); } -static void qemu_whpx_start_vcpu (CPUState *cpu) +static void qemu_whpx_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];
@@ -2038,7 +2038,7 @@ static void qemu_whpx_start_vcpu(CPUState *cpu)#endif } -static void qemu_dummy_start_vcpu (CPUState *cpu) +static void qemu_dummy_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];
@@ -2051,11 +2051,12 @@ static void qemu_dummy_start_vcpu(CPUState *cpu) QEMU_THREAD_JOINABLE); } -void qemu_init_vcpu (CPUState *cpu) +bool qemu_init_vcpu (CPUState *cpu,Error **errp) { cpu->nr_cores = smp_cores; cpu->nr_threads = smp_threads; cpu->stopped = true; +Error *local_err =NULL ;if (!cpu->as) {/* If the target cpu hasn't set up any address spaces itself,
@@ -2066,22 +2067,29 @@ void qemu_init_vcpu(CPUState *cpu) }if (kvm_enabled ()) { -qemu_kvm_start_vcpu (cpu); +qemu_kvm_start_vcpu (cpu, &local_err); }else if (hax_enabled ()) { -qemu_hax_start_vcpu (cpu); +qemu_hax_start_vcpu (cpu, &local_err); }else if (hvf_enabled ()) { -qemu_hvf_start_vcpu (cpu); +qemu_hvf_start_vcpu (cpu, &local_err); }else if (tcg_enabled ()) { -qemu_tcg_init_vcpu (cpu); +qemu_tcg_init_vcpu (cpu, &local_err); }else if (whpx_enabled ()) { -qemu_whpx_start_vcpu (cpu); +qemu_whpx_start_vcpu (cpu, &local_err); }else { -qemu_dummy_start_vcpu (cpu); +qemu_dummy_start_vcpu (cpu, &local_err); + } + +if (local_err) { +error_propagate (errp, local_err); +return false; }while (!cpu->created) {qemu_cond_wait (&qemu_cpu_cond, &qemu_global_mutex); } + +return true; }void cpu_stop_current (void )
include/qom/cpu.h +1 -1
@@ -1012,7 +1012,7 @@ void end_exclusive(void);* * Initializes a vCPU. */ -void qemu_init_vcpu (CPUState *cpu); +bool qemu_init_vcpu (CPUState *cpu,Error **errp);#define SSTEP_ENABLE 0x1/* Enable simulated HW single stepping */ #define SSTEP_NOIRQ 0x2/* Do not use IRQ while single stepping */
target/alpha/cpu.c +3 -1
@@ -66,7 +66,9 @@ static void alpha_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } acc->parent_realize (dev, errp); }
target/arm/cpu.c +3 -1
@@ -1038,7 +1038,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) }#endif -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); acc->parent_realize (dev, errp);
target/cris/cpu.c +3 -1
@@ -140,7 +140,9 @@ static void cris_cpu_realizefn(DeviceState *dev, Error **errp) }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } ccc->parent_realize (dev, errp); }
target/hppa/cpu.c +3 -1
@@ -98,7 +98,9 @@ static void hppa_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } acc->parent_realize (dev, errp);#ifndef CONFIG_USER_ONLY
target/i386/cpu.c +3 -1
@@ -5112,7 +5112,9 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) }#endif -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }/* * Most Intel and certain AMD CPUs support hyperthreading. Even though QEMU
target/lm32/cpu.c +3 -1
@@ -139,7 +139,9 @@ static void lm32_cpu_realizefn(DeviceState *dev, Error **errp)cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } lcc->parent_realize (dev, errp); }
target/m68k/cpu.c +3 -1
@@ -231,7 +231,9 @@ static void m68k_cpu_realizefn(DeviceState *dev, Error **errp)m68k_cpu_init_gdb (cpu);cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } mcc->parent_realize (dev, errp); }
target/microblaze/cpu.c +3 -1
@@ -161,7 +161,9 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } env->pvr.regs[0 ] =PVR0_USE_EXC_MASK \ |PVR0_USE_ICACHE_MASK \
target/mips/cpu.c +3 -1
@@ -136,7 +136,9 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp)cpu_mips_realize_env (&cpu->env);cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } mcc->parent_realize (dev, errp); }
target/moxie/cpu.c +3 -1
@@ -66,7 +66,9 @@ static void moxie_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); mcc->parent_realize (dev, errp);
target/nios2/cpu.c +3 -1
@@ -94,7 +94,9 @@ static void nios2_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); ncc->parent_realize (dev, errp);
target/openrisc/cpu.c +3 -1
@@ -83,7 +83,9 @@ static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); occ->parent_realize (dev, errp);
target/ppc/translate_init.inc.c +3 -1
@@ -9694,7 +9694,9 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp) 32, "power-vsx.xml", 0); } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { + goto unrealize; + } pcc->parent_realize (dev, errp);
target/riscv/cpu.c +3 -1
@@ -303,7 +303,9 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); mcc->parent_realize (dev, errp);
target/s390x/cpu.c +3 -1
@@ -222,7 +222,9 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)qemu_register_reset (s390_cpu_machine_reset_cb, cpu);#endif s390_cpu_gdb_init (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }/* * KVM requires the initial CPU reset ioctl to be executed on the target
target/sh4/cpu.c +3 -1
@@ -196,7 +196,9 @@ static void superh_cpu_realizefn(DeviceState *dev, Error **errp) }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } scc->parent_realize (dev, errp); }
target/sparc/cpu.c +3 -1
@@ -773,7 +773,9 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } scc->parent_realize (dev, errp); }
target/tilegx/cpu.c +3 -1
@@ -92,7 +92,9 @@ static void tilegx_cpu_realizefn(DeviceState *dev, Error **errp) }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } tcc->parent_realize (dev, errp); }
target/tricore/cpu.c +3 -1
@@ -96,7 +96,9 @@ static void tricore_cpu_realizefn(DeviceState *dev, Error **errp)set_feature (env,TRICORE_FEATURE_13 ); }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } tcc->parent_realize (dev, errp); }
target/unicore32/cpu.c +3 -1
@@ -96,7 +96,9 @@ static void uc32_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } ucc->parent_realize (dev, errp); }
target/xtensa/cpu.c +3 -1
@@ -131,7 +131,9 @@ static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) cs->gdb_num_regs = xcc->config->gdb_regmap.num_regs; -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } xcc->parent_realize (dev, errp); }
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH RFC v5 3/7] qemu_init_vcpu: add a new Error parameter to propagate
Quoted 1 line · Fei Li
The caller of
qemu_init_vcpu()already passed the **errp to handle
Which caller? There are many. Or do you mean "The callers"?
Quoted 2 lines
errors. In view of this, add a new Error parameter to the following call trace to propagate the error and let the further caller check it.
Which "call trace"?
Quoted 37 lines
Besides, make
qemu_init_vcpu()return a Boolean value to let its callers know whether it succeeds.Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- accel/tcg/user-exec-stub.c | 2 +- cpus.c | 34 +++++++++++++++++++++------------- include/qom/cpu.h | 2 +- target/alpha/cpu.c | 4 +++- target/arm/cpu.c | 4 +++- target/cris/cpu.c | 4 +++- target/hppa/cpu.c | 4 +++- target/i386/cpu.c | 4 +++- target/lm32/cpu.c | 4 +++- target/m68k/cpu.c | 4 +++- target/microblaze/cpu.c | 4 +++- target/mips/cpu.c | 4 +++- target/moxie/cpu.c | 4 +++- target/nios2/cpu.c | 4 +++- target/openrisc/cpu.c | 4 +++- target/ppc/translate_init.inc.c | 4 +++- target/riscv/cpu.c | 4 +++- target/s390x/cpu.c | 4 +++- target/sh4/cpu.c | 4 +++- target/sparc/cpu.c | 4 +++- target/tilegx/cpu.c | 4 +++- target/tricore/cpu.c | 4 +++- target/unicore32/cpu.c | 4 +++- target/xtensa/cpu.c | 4 +++- 24 files changed, 86 insertions(+), 36 deletions(-)accel/tcg/user-exec-stub.c +0
-0
accel/tcg/user-exec-stub.c void cpu_resume(CPUState *cpu) · line 14
Quoted 6 lines
accel/tcg/user-exec-stub.c +1
-1@@ -10,7 +10,7 @@ void cpu_resume(CPUState *cpu) { } -void qemu_init_vcpu (CPUState *cpu) +bool qemu_init_vcpu (CPUState *cpu,Error **errp) {
You need to return a value here. Sure you compile-tested this?
Quoted 428 lines
accel/tcg/user-exec-stub.c +0
-0}cpus.c +21
-13@@ -1918,7 +1918,7 @@ void cpu_remove_sync(CPUState *cpu)/* For temporary buffers for forming a name */ #define VCPU_THREAD_NAME_SIZE 16 -static void qemu_tcg_init_vcpu (CPUState *cpu) +static void qemu_tcg_init_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];static QemuCond *single_tcg_halt_cond;@@ -1974,7 +1974,7 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) } } -static void qemu_hax_start_vcpu (CPUState *cpu) +static void qemu_hax_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];@@ -1991,7 +1991,7 @@ static void qemu_hax_start_vcpu(CPUState *cpu)#endif } -static void qemu_kvm_start_vcpu (CPUState *cpu) +static void qemu_kvm_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];@@ -2004,7 +2004,7 @@ static void qemu_kvm_start_vcpu(CPUState *cpu) cpu, QEMU_THREAD_JOINABLE); } -static void qemu_hvf_start_vcpu (CPUState *cpu) +static void qemu_hvf_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];@@ -2022,7 +2022,7 @@ static void qemu_hvf_start_vcpu(CPUState *cpu) cpu, QEMU_THREAD_JOINABLE); } -static void qemu_whpx_start_vcpu (CPUState *cpu) +static void qemu_whpx_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];@@ -2038,7 +2038,7 @@ static void qemu_whpx_start_vcpu(CPUState *cpu)#endif } -static void qemu_dummy_start_vcpu (CPUState *cpu) +static void qemu_dummy_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];@@ -2051,11 +2051,12 @@ static void qemu_dummy_start_vcpu(CPUState *cpu) QEMU_THREAD_JOINABLE); } -void qemu_init_vcpu (CPUState *cpu) +bool qemu_init_vcpu (CPUState *cpu,Error **errp) { cpu->nr_cores = smp_cores; cpu->nr_threads = smp_threads; cpu->stopped = true; +Error *local_err =NULL ;if (!cpu->as) {/* If the target cpu hasn't set up any address spaces itself, @@ -2066,22 +2067,29 @@ void qemu_init_vcpu(CPUState *cpu) }if (kvm_enabled ()) { -qemu_kvm_start_vcpu (cpu); +qemu_kvm_start_vcpu (cpu, &local_err); }else if (hax_enabled ()) { -qemu_hax_start_vcpu (cpu); +qemu_hax_start_vcpu (cpu, &local_err); }else if (hvf_enabled ()) { -qemu_hvf_start_vcpu (cpu); +qemu_hvf_start_vcpu (cpu, &local_err); }else if (tcg_enabled ()) { -qemu_tcg_init_vcpu (cpu); +qemu_tcg_init_vcpu (cpu, &local_err); }else if (whpx_enabled ()) { -qemu_whpx_start_vcpu (cpu); +qemu_whpx_start_vcpu (cpu, &local_err); }else { -qemu_dummy_start_vcpu (cpu); +qemu_dummy_start_vcpu (cpu, &local_err); + } + +if (local_err) { +error_propagate (errp, local_err); +return false; }while (!cpu->created) {qemu_cond_wait (&qemu_cpu_cond, &qemu_global_mutex); } + +return true; }void cpu_stop_current (void )include/qom/cpu.h +1
-1@@ -1012,7 +1012,7 @@ void end_exclusive(void);* * Initializes a vCPU. */ -void qemu_init_vcpu (CPUState *cpu); +bool qemu_init_vcpu (CPUState *cpu,Error **errp);#define SSTEP_ENABLE 0x1/* Enable simulated HW single stepping */ #define SSTEP_NOIRQ 0x2/* Do not use IRQ while single stepping */ target/alpha/cpu.c +3
-1@@ -66,7 +66,9 @@ static void alpha_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } acc->parent_realize (dev, errp); }target/arm/cpu.c +3
-1@@ -1038,7 +1038,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) }#endif -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); acc->parent_realize (dev, errp);target/cris/cpu.c +3
-1@@ -140,7 +140,9 @@ static void cris_cpu_realizefn(DeviceState *dev, Error **errp) }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } ccc->parent_realize (dev, errp); }target/hppa/cpu.c +3
-1@@ -98,7 +98,9 @@ static void hppa_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } acc->parent_realize (dev, errp);#ifndef CONFIG_USER_ONLY target/i386/cpu.c +3
-1@@ -5112,7 +5112,9 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) }#endif -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }/* * Most Intel and certain AMD CPUs support hyperthreading. Even though QEMU target/lm32/cpu.c +3
-1@@ -139,7 +139,9 @@ static void lm32_cpu_realizefn(DeviceState *dev, Error **errp)cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } lcc->parent_realize (dev, errp); }target/m68k/cpu.c +3
-1@@ -231,7 +231,9 @@ static void m68k_cpu_realizefn(DeviceState *dev, Error **errp)m68k_cpu_init_gdb (cpu);cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } mcc->parent_realize (dev, errp); }target/microblaze/cpu.c +3
-1@@ -161,7 +161,9 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } env->pvr.regs[0 ] =PVR0_USE_EXC_MASK \ |PVR0_USE_ICACHE_MASK \target/mips/cpu.c +3
-1@@ -136,7 +136,9 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp)cpu_mips_realize_env (&cpu->env);cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } mcc->parent_realize (dev, errp); }target/moxie/cpu.c +3
-1@@ -66,7 +66,9 @@ static void moxie_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); mcc->parent_realize (dev, errp);target/nios2/cpu.c +3
-1@@ -94,7 +94,9 @@ static void nios2_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); ncc->parent_realize (dev, errp);target/openrisc/cpu.c +3
-1@@ -83,7 +83,9 @@ static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); occ->parent_realize (dev, errp);target/ppc/translate_init.inc.c +3
-1@@ -9694,7 +9694,9 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp) 32, "power-vsx.xml", 0); } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { + goto unrealize; + } pcc->parent_realize (dev, errp);target/riscv/cpu.c +3
-1@@ -303,7 +303,9 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); mcc->parent_realize (dev, errp);target/s390x/cpu.c +3
-1@@ -222,7 +222,9 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)qemu_register_reset (s390_cpu_machine_reset_cb, cpu);#endif s390_cpu_gdb_init (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }/* * KVM requires the initial CPU reset ioctl to be executed on the target target/sh4/cpu.c +3
-1@@ -196,7 +196,9 @@ static void superh_cpu_realizefn(DeviceState *dev, Error **errp) }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } scc->parent_realize (dev, errp); }target/sparc/cpu.c +3
-1@@ -773,7 +773,9 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } scc->parent_realize (dev, errp); }target/tilegx/cpu.c +3
-1@@ -92,7 +92,9 @@ static void tilegx_cpu_realizefn(DeviceState *dev, Error **errp) }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } tcc->parent_realize (dev, errp); }target/tricore/cpu.c +3
-1@@ -96,7 +96,9 @@ static void tricore_cpu_realizefn(DeviceState *dev, Error **errp)set_feature (env,TRICORE_FEATURE_13 ); }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } tcc->parent_realize (dev, errp); }target/unicore32/cpu.c +3
-1@@ -96,7 +96,9 @@ static void uc32_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } ucc->parent_realize (dev, errp); }target/xtensa/cpu.c +0
-0
target/xtensa/cpu.c static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) · line 139
Quoted 10 lines
target/xtensa/cpu.c +3
-1@@ -131,7 +131,9 @@ static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) cs->gdb_num_regs = xcc->config->gdb_regmap.num_regs; -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } xcc->parent_realize (dev, errp); }
I see how you changed the code to pass an Error from the qemu_FOO_start_vcpu() through qemu_init_vcpu() to its callers. I can't see how such errors can be created. Without a way to create any, the patch is pointless. What am I missing?
Re: [Qemu-devel] [PATCH RFC v5 3/7] qemu_init_vcpu: add a new Error parameter to propagate
Quoted 4 lines · Markus Armbruster
Quoted 1 line · Fei Li
The caller of
qemu_init_vcpu()already passed the **errp to handleWhich caller? There are many. Or do you mean "The callers"?
Oh, sorry, I mean "The callers" :)
Quoted 4 lines
Quoted 3 lines
errors. In view of this, add a new Error parameter to the following call trace to propagate the error and let the further caller check it.
Which "call trace"?
Actually, I want to say all functions called by qemu_init_vcpu()..
Quoted 41 lines
Quoted 41 lines
Besides, make
qemu_init_vcpu()return a Boolean value to let its callers know whether it succeeds.Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- accel/tcg/user-exec-stub.c | 2 +- cpus.c | 34 +++++++++++++++++++++------------- include/qom/cpu.h | 2 +- target/alpha/cpu.c | 4 +++- target/arm/cpu.c | 4 +++- target/cris/cpu.c | 4 +++- target/hppa/cpu.c | 4 +++- target/i386/cpu.c | 4 +++- target/lm32/cpu.c | 4 +++- target/m68k/cpu.c | 4 +++- target/microblaze/cpu.c | 4 +++- target/mips/cpu.c | 4 +++- target/moxie/cpu.c | 4 +++- target/nios2/cpu.c | 4 +++- target/openrisc/cpu.c | 4 +++- target/ppc/translate_init.inc.c | 4 +++- target/riscv/cpu.c | 4 +++- target/s390x/cpu.c | 4 +++- target/sh4/cpu.c | 4 +++- target/sparc/cpu.c | 4 +++- target/tilegx/cpu.c | 4 +++- target/tricore/cpu.c | 4 +++- target/unicore32/cpu.c | 4 +++- target/xtensa/cpu.c | 4 +++- 24 files changed, 86 insertions(+), 36 deletions(-)accel/tcg/user-exec-stub.c +0
-0@@ -10,7 +10,7 @@ void cpu_resume(CPUState *cpu) { }
Quoted 4 lines
accel/tcg/user-exec-stub.c void cpu_resume(CPUState *cpu) · line 14
Quoted 3 lines
accel/tcg/user-exec-stub.c +1
-1-void qemu_init_vcpu (CPUState *cpu) +bool qemu_init_vcpu (CPUState *cpu,Error **errp) {You need to return a value here. Sure you compile-tested this?
Oops! I forget the TCG case.. The return true should be added. Thanks for pointing this out!
Quoted 437 lines
Quoted 437 lines
accel/tcg/user-exec-stub.c +0
-0}cpus.c +21
-13@@ -1918,7 +1918,7 @@ void cpu_remove_sync(CPUState *cpu)/* For temporary buffers for forming a name */ #define VCPU_THREAD_NAME_SIZE 16 -static void qemu_tcg_init_vcpu (CPUState *cpu) +static void qemu_tcg_init_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];static QemuCond *single_tcg_halt_cond;@@ -1974,7 +1974,7 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) } } -static void qemu_hax_start_vcpu (CPUState *cpu) +static void qemu_hax_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];@@ -1991,7 +1991,7 @@ static void qemu_hax_start_vcpu(CPUState *cpu)#endif } -static void qemu_kvm_start_vcpu (CPUState *cpu) +static void qemu_kvm_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];@@ -2004,7 +2004,7 @@ static void qemu_kvm_start_vcpu(CPUState *cpu) cpu, QEMU_THREAD_JOINABLE); } -static void qemu_hvf_start_vcpu (CPUState *cpu) +static void qemu_hvf_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];@@ -2022,7 +2022,7 @@ static void qemu_hvf_start_vcpu(CPUState *cpu) cpu, QEMU_THREAD_JOINABLE); } -static void qemu_whpx_start_vcpu (CPUState *cpu) +static void qemu_whpx_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];@@ -2038,7 +2038,7 @@ static void qemu_whpx_start_vcpu(CPUState *cpu)#endif } -static void qemu_dummy_start_vcpu (CPUState *cpu) +static void qemu_dummy_start_vcpu (CPUState *cpu,Error **errp) {char thread_name[VCPU_THREAD_NAME_SIZE ];@@ -2051,11 +2051,12 @@ static void qemu_dummy_start_vcpu(CPUState *cpu) QEMU_THREAD_JOINABLE); } -void qemu_init_vcpu (CPUState *cpu) +bool qemu_init_vcpu (CPUState *cpu,Error **errp) { cpu->nr_cores = smp_cores; cpu->nr_threads = smp_threads; cpu->stopped = true; +Error *local_err =NULL ;if (!cpu->as) {/* If the target cpu hasn't set up any address spaces itself, @@ -2066,22 +2067,29 @@ void qemu_init_vcpu(CPUState *cpu) }if (kvm_enabled ()) { -qemu_kvm_start_vcpu (cpu); +qemu_kvm_start_vcpu (cpu, &local_err); }else if (hax_enabled ()) { -qemu_hax_start_vcpu (cpu); +qemu_hax_start_vcpu (cpu, &local_err); }else if (hvf_enabled ()) { -qemu_hvf_start_vcpu (cpu); +qemu_hvf_start_vcpu (cpu, &local_err); }else if (tcg_enabled ()) { -qemu_tcg_init_vcpu (cpu); +qemu_tcg_init_vcpu (cpu, &local_err); }else if (whpx_enabled ()) { -qemu_whpx_start_vcpu (cpu); +qemu_whpx_start_vcpu (cpu, &local_err); }else { -qemu_dummy_start_vcpu (cpu); +qemu_dummy_start_vcpu (cpu, &local_err); + } + +if (local_err) { +error_propagate (errp, local_err); +return false; }while (!cpu->created) {qemu_cond_wait (&qemu_cpu_cond, &qemu_global_mutex); } + +return true; }void cpu_stop_current (void )include/qom/cpu.h +1
-1@@ -1012,7 +1012,7 @@ void end_exclusive(void);* * Initializes a vCPU. */ -void qemu_init_vcpu (CPUState *cpu); +bool qemu_init_vcpu (CPUState *cpu,Error **errp);#define SSTEP_ENABLE 0x1/* Enable simulated HW single stepping */ #define SSTEP_NOIRQ 0x2/* Do not use IRQ while single stepping */ target/alpha/cpu.c +3
-1@@ -66,7 +66,9 @@ static void alpha_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } acc->parent_realize (dev, errp); }target/arm/cpu.c +3
-1@@ -1038,7 +1038,9 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) }#endif -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); acc->parent_realize (dev, errp);target/cris/cpu.c +3
-1@@ -140,7 +140,9 @@ static void cris_cpu_realizefn(DeviceState *dev, Error **errp) }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } ccc->parent_realize (dev, errp); }target/hppa/cpu.c +3
-1@@ -98,7 +98,9 @@ static void hppa_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } acc->parent_realize (dev, errp);#ifndef CONFIG_USER_ONLY target/i386/cpu.c +3
-1@@ -5112,7 +5112,9 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) }#endif -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }/* * Most Intel and certain AMD CPUs support hyperthreading. Even though QEMU target/lm32/cpu.c +3
-1@@ -139,7 +139,9 @@ static void lm32_cpu_realizefn(DeviceState *dev, Error **errp)cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } lcc->parent_realize (dev, errp); }target/m68k/cpu.c +3
-1@@ -231,7 +231,9 @@ static void m68k_cpu_realizefn(DeviceState *dev, Error **errp)m68k_cpu_init_gdb (cpu);cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } mcc->parent_realize (dev, errp); }target/microblaze/cpu.c +3
-1@@ -161,7 +161,9 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } env->pvr.regs[0 ] =PVR0_USE_EXC_MASK \ |PVR0_USE_ICACHE_MASK \target/mips/cpu.c +3
-1@@ -136,7 +136,9 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp)cpu_mips_realize_env (&cpu->env);cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } mcc->parent_realize (dev, errp); }target/moxie/cpu.c +3
-1@@ -66,7 +66,9 @@ static void moxie_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); mcc->parent_realize (dev, errp);target/nios2/cpu.c +3
-1@@ -94,7 +94,9 @@ static void nios2_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); ncc->parent_realize (dev, errp);target/openrisc/cpu.c +3
-1@@ -83,7 +83,9 @@ static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); occ->parent_realize (dev, errp);target/ppc/translate_init.inc.c +3
-1@@ -9694,7 +9694,9 @@ static void ppc_cpu_realize(DeviceState *dev, Error **errp) 32, "power-vsx.xml", 0); } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { + goto unrealize; + } pcc->parent_realize (dev, errp);target/riscv/cpu.c +3
-1@@ -303,7 +303,9 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }cpu_reset (cs); mcc->parent_realize (dev, errp);target/s390x/cpu.c +3
-1@@ -222,7 +222,9 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)qemu_register_reset (s390_cpu_machine_reset_cb, cpu);#endif s390_cpu_gdb_init (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }/* * KVM requires the initial CPU reset ioctl to be executed on the target target/sh4/cpu.c +3
-1@@ -196,7 +196,9 @@ static void superh_cpu_realizefn(DeviceState *dev, Error **errp) }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } scc->parent_realize (dev, errp); }target/sparc/cpu.c +3
-1@@ -773,7 +773,9 @@ static void sparc_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } scc->parent_realize (dev, errp); }target/tilegx/cpu.c +3
-1@@ -92,7 +92,9 @@ static void tilegx_cpu_realizefn(DeviceState *dev, Error **errp) }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } tcc->parent_realize (dev, errp); }target/tricore/cpu.c +3
-1@@ -96,7 +96,9 @@ static void tricore_cpu_realizefn(DeviceState *dev, Error **errp)set_feature (env,TRICORE_FEATURE_13 ); }cpu_reset (cs); -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } tcc->parent_realize (dev, errp); }target/unicore32/cpu.c +3
-1@@ -96,7 +96,9 @@ static void uc32_cpu_realizefn(DeviceState *dev, Error **errp)return ; } -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + } ucc->parent_realize (dev, errp); }target/xtensa/cpu.c +3
-1@@ -131,7 +131,9 @@ static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) cs->gdb_num_regs = xcc->config->gdb_regmap.num_regs; -qemu_init_vcpu (cs); +if (!qemu_init_vcpu (cs, errp)) { +return ; + }
Quoted 6 lines
target/xtensa/cpu.c static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) · line 139
Quoted 2 lines
target/xtensa/cpu.c +0
-0xcc->parent_realize (dev, errp); }I see how you changed the code to pass an Error from the
qemu_FOO_start_vcpu()throughqemu_init_vcpu()to its callers. I can't see how such errors can be created. Without a way to create any, the patch is pointless. What am I missing?
This patch is also the pre-patch for the updated qemu_thread_create() in patch 7/7 just as I explained in patch 2/7 [Issue1].
Have a nice day, thanks
Fei
Re: [Qemu-devel] [PATCH RFC v5 3/7] qemu_init_vcpu: add a new Error parameter to propagate
Quoted 55 lines · Fei Li
Quoted 4 lines · Markus Armbruster
Quoted 1 line · Fei Li
The caller of
qemu_init_vcpu()already passed the **errp to handleWhich caller? There are many. Or do you mean "The callers"?
Oh, sorry, I mean "The callers" :)
Quoted 4 lines
Quoted 3 lines
errors. In view of this, add a new Error parameter to the following call trace to propagate the error and let the further caller check it.
Which "call trace"?
Actually, I want to say all functions called by
qemu_init_vcpu()..Quoted 33 lines
Quoted 33 lines
Besides, make
qemu_init_vcpu()return a Boolean value to let its callers know whether it succeeds.Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- accel/tcg/user-exec-stub.c | 2 +- cpus.c | 34 +++++++++++++++++++++------------- include/qom/cpu.h | 2 +- target/alpha/cpu.c | 4 +++- target/arm/cpu.c | 4 +++- target/cris/cpu.c | 4 +++- target/hppa/cpu.c | 4 +++- target/i386/cpu.c | 4 +++- target/lm32/cpu.c | 4 +++- target/m68k/cpu.c | 4 +++- target/microblaze/cpu.c | 4 +++- target/mips/cpu.c | 4 +++- target/moxie/cpu.c | 4 +++- target/nios2/cpu.c | 4 +++- target/openrisc/cpu.c | 4 +++- target/ppc/translate_init.inc.c | 4 +++- target/riscv/cpu.c | 4 +++- target/s390x/cpu.c | 4 +++- target/sh4/cpu.c | 4 +++- target/sparc/cpu.c | 4 +++- target/tilegx/cpu.c | 4 +++- target/tricore/cpu.c | 4 +++- target/unicore32/cpu.c | 4 +++- target/xtensa/cpu.c | 4 +++- 24 files changed, 86 insertions(+), 36 deletions(-)Quoted 11 lines
accel/tcg/user-exec-stub.c void cpu_resume(CPUState *cpu) · line 14
Quoted 10 lines
accel/tcg/user-exec-stub.c +1
-0@@ -10,7 +10,7 @@ void cpu_resume(CPUState *cpu) { } -void qemu_init_vcpu(CPUState *cpu) +bool qemu_init_vcpu (CPUState *cpu,Error **errp) {You need to return a value here. Sure you compile-tested this?
Quoted 2 lines
Oops! I forget the TCG case.. The
return trueshould be added. Thanks for pointing this out!
You're welcome.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
accel/tcg/user-exec-stub.c +0
-0} diff --git a/cpus.c b/cpus.c
[...]
Quoted 7 lines
Quoted 4 lines
I see how you changed the code to pass an Error from the
qemu_FOO_start_vcpu()throughqemu_init_vcpu()to its callers. I can't see how such errors can be created. Without a way to create any, the patch is pointless. What am I missing?This patch is also the pre-patch for the updated
qemu_thread_create()in patch 7/7
just as I explained in patch 2/7 [Issue1].
Patches that make little sense on their own, but pave the way for a later patch are okay. But they should explain that purpose in their commit message.
Re: [Qemu-devel] [PATCH RFC v5 3/7] qemu_init_vcpu: add a new Error parameter to propagate
Quoted 66 lines · Markus Armbruster
Quoted 53 lines · Fei Li
Quoted 4 lines · Markus Armbruster
Quoted 1 line · Fei Li
The caller of
qemu_init_vcpu()already passed the **errp to handleWhich caller? There are many. Or do you mean "The callers"?
Oh, sorry, I mean "The callers" :)
Quoted 3 lines
Quoted 2 lines
errors. In view of this, add a new Error parameter to the following call trace to propagate the error and let the further caller check it.
Which "call trace"?
Actually, I want to say all functions called by
qemu_init_vcpu()..Quoted 32 lines
Quoted 32 lines
Besides, make
qemu_init_vcpu()return a Boolean value to let its callers know whether it succeeds.Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- accel/tcg/user-exec-stub.c | 2 +- cpus.c | 34 +++++++++++++++++++++------------- include/qom/cpu.h | 2 +- target/alpha/cpu.c | 4 +++- target/arm/cpu.c | 4 +++- target/cris/cpu.c | 4 +++- target/hppa/cpu.c | 4 +++- target/i386/cpu.c | 4 +++- target/lm32/cpu.c | 4 +++- target/m68k/cpu.c | 4 +++- target/microblaze/cpu.c | 4 +++- target/mips/cpu.c | 4 +++- target/moxie/cpu.c | 4 +++- target/nios2/cpu.c | 4 +++- target/openrisc/cpu.c | 4 +++- target/ppc/translate_init.inc.c | 4 +++- target/riscv/cpu.c | 4 +++- target/s390x/cpu.c | 4 +++- target/sh4/cpu.c | 4 +++- target/sparc/cpu.c | 4 +++- target/tilegx/cpu.c | 4 +++- target/tricore/cpu.c | 4 +++- target/unicore32/cpu.c | 4 +++- target/xtensa/cpu.c | 4 +++- 24 files changed, 86 insertions(+), 36 deletions(-)Quoted 11 lines
accel/tcg/user-exec-stub.c void cpu_resume(CPUState *cpu) · line 14
Quoted 10 lines
accel/tcg/user-exec-stub.c +1
-0@@ -10,7 +10,7 @@ void cpu_resume(CPUState *cpu) { } -void qemu_init_vcpu(CPUState *cpu) +bool qemu_init_vcpu (CPUState *cpu,Error **errp) {You need to return a value here. Sure you compile-tested this?
Quoted 2 lines
Oops! I forget the TCG case.. The
return trueshould be added. Thanks for pointing this out!You're welcome.
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
accel/tcg/user-exec-stub.c +0
-0} diff --git a/cpus.c b/cpus.c[...]
Quoted 4 lines
Quoted 4 lines
I see how you changed the code to pass an Error from the
qemu_FOO_start_vcpu()throughqemu_init_vcpu()to its callers. I can't see how such errors can be created. Without a way to create any, the patch is pointless. What am I missing?
Quoted 6 lines
Quoted 3 lines
This patch is also the pre-patch for the updated
qemu_thread_create()in patch 7/7
just as I explained in patch 2/7 [Issue1].Patches that make little sense on their own, but pave the way for a later patch are okay. But they should explain that purpose in their commit message.
Right. Thanks for the advice, will amend the commit message in next version.
Have a nice day
Fei
RFC PATCH v5 4/7 qemu_thread_join: fix segmentation fault
In reply to Fei LiTo avoid the segmentation fault in qemu_thread_join(), just directly return when the QemuThread *thread failed to be created in either qemu-thread-posix.c or qemu-thread-win32.c.
--- util/qemu-thread-posix.c | 3 +++ util/qemu-thread-win32.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-)
util/qemu-thread-posix.c +3 -0
@@ -562,6 +562,9 @@ void *qemu_thread_join(QemuThread *thread)int err;void *ret; +if (!thread->thread) { +return NULL ; + } err =pthread_join (thread->thread, &ret);if (err) {error_exit (err, __func__);
util/qemu-thread-win32.c +1 -1
@@ -366,7 +366,7 @@ void *qemu_thread_join(QemuThread *thread)HANDLE handle; data = thread->data; -if (data->mode ==QEMU_THREAD_DETACHED ) { +if (data ==NULL || data->mode ==QEMU_THREAD_DETACHED ) {return NULL ; }
Signature · 1 line
2.13.7
RFC PATCH v5 5/7 migration: fix the multifd code
In reply to Fei LiWhen multifd is used during migration, if there is an error before the destination receives all new channels, the destination does not exit but keeps waiting in our current code. However, a segmentaion fault will occur in the source when multifd_save_cleanup() is called again as the multifd_send_state has been freed earlier in the first error handling. This can happen when migrate_fd_connect() fails and multifd_fd_cleanup() is called, and then multifd_new_send_channel_ async() fails and multifd_save_cleanup() is called again.
If the QIOChannel *c of multifd_recv_state->params[i] (p->c) is not initialized, there is no need to close the channel. Or else a segmentation fault will occur in multifd_recv_terminate_threads() when multifd_recv_initial_packet() fails.
--- migration/ram.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
migration/ram.c +16 -6
@@ -907,6 +907,11 @@ static void multifd_send_terminate_threads(Error *err) } } +/* in case multifd_send_state has been freed earlier */ +if (!multifd_send_state) { +return ; + } +for (i =0 ; i <migrate_multifd_channels (); i++) {MultiFDSendParams *p = &multifd_send_state->params[i];
@@ -922,7 +927,7 @@ int multifd_save_cleanup(Error **errp)int i;int ret =0 ; -if (!migrate_use_multifd ()) { +if (!migrate_use_multifd () || !multifd_send_state) {return 0 ; }multifd_send_terminate_threads (NULL );
@@ -1131,7 +1136,7 @@ struct {uint64_t packet_num; } *multifd_recv_state; -static void multifd_recv_terminate_threads (Error *err) +static void multifd_recv_terminate_threads (Error *err,bool channel) {int i;
@@ -1145,6 +1150,11 @@ static void multifd_recv_terminate_threads(Error *err) } } +/* in case p->c is not initialized */ +if (!channel) { +return ; + } +for (i =0 ; i <migrate_multifd_channels (); i++) {MultiFDRecvParams *p = &multifd_recv_state->params[i];
@@ -1166,7 +1176,7 @@ int multifd_load_cleanup(Error **errp)if (!migrate_use_multifd ()) {return 0 ; } -multifd_recv_terminate_threads (NULL ); +multifd_recv_terminate_threads (NULL , true);for (i =0 ; i <migrate_multifd_channels (); i++) {MultiFDRecvParams *p = &multifd_recv_state->params[i];
@@ -1269,7 +1279,7 @@ static void *multifd_recv_thread(void *opaque) }if (local_err) { -multifd_recv_terminate_threads (local_err); +multifd_recv_terminate_threads (local_err, true); }qemu_mutex_lock (&p->mutex); p->running = false;
@@ -1331,7 +1341,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc) id =multifd_recv_initial_packet (ioc, &local_err);if (id <0 ) { -multifd_recv_terminate_threads (local_err); +multifd_recv_terminate_threads (local_err, false);return false; }
@@ -1339,7 +1349,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc)if (p->c !=NULL ) {error_setg (&local_err,"multifd: received id '%d' already setup'" , id); -multifd_recv_terminate_threads (local_err); +multifd_recv_terminate_threads (local_err, true);return false; } p->c = ioc;
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH RFC v5 5/7] migration: fix the multifd code
Quoted 3 lines · Fei Li
When multifd is used during migration, if there is an error before the destination receives all new channels, the destination does not exit but keeps waiting in our current code. However, a segmentaion
segmentation
Quoted 52 lines
fault will occur in the source when
multifd_save_cleanup()is called again as themultifd_send_statehas been freed earlier in the first error handling. This can happen whenmigrate_fd_connect()fails andmultifd_fd_cleanup()is called, and thenmultifd_new_send_channel_async()fails andmultifd_save_cleanup()is called again.If the QIOChannel *c of multifd_recv_state->params[i] (
p->c) is not initialized, there is no need to close the channel. Or else a segmentation fault will occur inmultifd_recv_terminate_threads()whenmultifd_recv_initial_packet()fails.Signed-off-by Fei Li <[email protected]>--- migration/ram.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)migration/ram.c +7
-2@@ -907,6 +907,11 @@ static void multifd_send_terminate_threads(Error *err) } } +/* in case multifd_send_state has been freed earlier */ +if (!multifd_send_state) { +return ; + } +for (i =0 ; i <migrate_multifd_channels (); i++) {MultiFDSendParams *p = &multifd_send_state->params[i];@@ -922,7 +927,7 @@ int multifd_save_cleanup(Error **errp)int i;int ret =0 ; -if (!migrate_use_multifd ()) { +if (!migrate_use_multifd () || !multifd_send_state) {return 0 ; }multifd_send_terminate_threads (NULL );@@ -1131,7 +1136,7 @@ struct {uint64_t packet_num; } *multifd_recv_state; -static void multifd_recv_terminate_threads (Error *err) +static void multifd_recv_terminate_threads (Error *err,bool channel) {int i;@@ -1145,6 +1150,11 @@ static void multifd_recv_terminate_threads(Error *err) }
migration/ram.c static void multifd_recv_terminate_threads(Error *err) · line 1160
Quoted 10 lines
migration/ram.c +5
-0} +/* in case p->c is not initialized */ +if (!channel) { +return ; + } +for (i =0 ; i <migrate_multifd_channels (); i++) {MultiFDRecvParams *p = &multifd_recv_state->params[i];
The function does one thing always, another thing only when its argument @channel is true, and ...
Quoted 28 lines
migration/ram.c +3
-3@@ -1166,7 +1176,7 @@ int multifd_load_cleanup(Error **errp)if (!migrate_use_multifd ()) {return 0 ; } -multifd_recv_terminate_threads (NULL ); +multifd_recv_terminate_threads (NULL , true);for (i =0 ; i <migrate_multifd_channels (); i++) {MultiFDRecvParams *p = &multifd_recv_state->params[i];@@ -1269,7 +1279,7 @@ static void *multifd_recv_thread(void *opaque) }if (local_err) { -multifd_recv_terminate_threads (local_err); +multifd_recv_terminate_threads (local_err, true); }qemu_mutex_lock (&p->mutex); p->running = false;@@ -1331,7 +1341,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc) id =multifd_recv_initial_packet (ioc, &local_err);if (id <0 ) { -multifd_recv_terminate_threads (local_err); +multifd_recv_terminate_threads (local_err, false);return false; }
migration/ram.c bool multifd_recv_new_channel(QIOChannel *ioc) · line 1355
Quoted 8 lines
migration/ram.c +1
-1@@ -1339,7 +1349,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc)if (p->c !=NULL ) {error_setg (&local_err,"multifd: received id '%d' already setup'" , id); -multifd_recv_terminate_threads (local_err); +multifd_recv_terminate_threads (local_err, true);return false; } p->c = ioc;
... all callers pass literal true or false. Should we split the function into its two parts, and call the second half only in the places where its needed? Matter of taste, I guess. The maintainers may have an opinion.
RFC PATCH v5 6/7 migration: fix some error handling
In reply to Fei LiAdd error handling for qemu_ram_foreach_migratable_block() when it fails.
Always call migrate_set_error() to set the error state without relying on whether multifd_save_cleanup() succeeds. As the passed &local_err is never used in multifd_save_cleanup(), remove it.
--- migration/migration.c | 5 +---- migration/postcopy-ram.c | 3 +++ migration/ram.c | 7 +++---- migration/ram.h | 2 +- 4 files changed, 8 insertions(+), 9 deletions(-)
migration/migration.c +1 -4
@@ -1341,7 +1341,6 @@ static void migrate_fd_cleanup(void *opaque)qemu_savevm_state_cleanup ();if (s->to_dst_file) { -Error *local_err =NULL ;QEMUFile *tmp;trace_migrate_fd_cleanup ();
@@ -1352,9 +1351,7 @@ static void migrate_fd_cleanup(void *opaque) }qemu_mutex_lock_iothread (); -if (multifd_save_cleanup (&local_err) !=0 ) { -error_report_err (local_err); - } +multifd_save_cleanup ();qemu_mutex_lock (&s->qemu_file_lock); tmp = s->to_dst_file; s->to_dst_file =NULL ;
migration/postcopy-ram.c +3 -0
@@ -1116,6 +1116,9 @@ int postcopy_ram_enable_notify(MigrationIncomingState *mis)/* Mark so that we get notified of accesses to unwritten areas */ if (qemu_ram_foreach_migratable_block (ram_block_enable_notify, mis)) { +error_report ("ram_block_enable_notify failed" ); +close (mis->userfault_event_fd); +close (mis->userfault_fd);return -1 ; }
migration/ram.c +3 -4
@@ -922,7 +922,7 @@ static void multifd_send_terminate_threads(Error *err) } } -int multifd_save_cleanup (Error **errp) +int multifd_save_cleanup (void ) {int i;int ret =0 ;
@@ -1076,9 +1076,8 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque)Error *local_err =NULL ;if (qio_task_propagate_error (task, &local_err)) { -if (multifd_save_cleanup (&local_err) !=0 ) { -migrate_set_error (migrate_get_current (), local_err); - } +multifd_save_cleanup (); +migrate_set_error (migrate_get_current (), local_err); }else { p->c =QIO_CHANNEL (sioc);qio_channel_set_delay (p->c, false);
migration/ram.h +1 -1
@@ -43,7 +43,7 @@ uint64_t ram_bytes_remaining(void);uint64_t ram_bytes_total (void );int multifd_save_setup (void ); -int multifd_save_cleanup (Error **errp); +int multifd_save_cleanup (void );int multifd_load_setup (void );int multifd_load_cleanup (Error **errp);bool multifd_recv_all_channels_created (void );
Signature · 1 line
2.13.7
RFC PATCH v5 7/7 qemu_thread_create: propagate the error to callers to handle
In reply to Fei LiMake qemu_thread_create() return a Boolean to indicate if it succeeds rather than failing with an error. And add an Error parameter to hold the error message and let the callers handle it.
--- cpus.c | 45 +++++++++++++++++++++++++++-------------- dump.c | 6 ++++-- hw/misc/edu.c | 6 ++++-- hw/ppc/spapr_hcall.c | 10 +++++++-- hw/rdma/rdma_backend.c | 4 +++- hw/usb/ccid-card-emulated.c | 13 ++++++++---- include/qemu/thread.h | 4 ++-- io/task.c | 3 ++- iothread.c | 16 ++++++++++----- migration/migration.c | 49 +++++++++++++++++++++++++++++++-------------- migration/postcopy-ram.c | 14 +++++++++++-- migration/ram.c | 39 +++++++++++++++++++++++++++--------- migration/savevm.c | 11 +++++++--- tests/atomic_add-bench.c | 3 ++- tests/iothread.c | 2 +- tests/qht-bench.c | 3 ++- tests/rcutorture.c | 3 ++- tests/test-aio.c | 2 +- tests/test-rcu-list.c | 3 ++- ui/vnc-jobs.c | 8 ++++++-- util/compatfd.c | 9 +++++++-- util/main-loop.c | 2 +- util/oslib-posix.c | 17 ++++++++++++---- util/qemu-thread-posix.c | 22 ++++++++++++-------- util/qemu-thread-win32.c | 16 +++++++++++---- util/rcu.c | 3 ++- util/thread-pool.c | 4 +++- 27 files changed, 224 insertions(+), 93 deletions(-)
cpus.c +30 -15
@@ -1948,15 +1948,20 @@ static void qemu_tcg_init_vcpu(CPUState *cpu, Error **errp)snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/TCG" , cpu->cpu_index); -qemu_thread_create (cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (cpu->thread, thread_name, + qemu_tcg_cpu_thread_fn, cpu, +QEMU_THREAD_JOINABLE , errp)) { +return ; + } }else {/* share a single thread for all cpus with TCG */ snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"ALL CPUs/TCG" ); -qemu_thread_create (cpu->thread, thread_name, - qemu_tcg_rr_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (cpu->thread, thread_name, + qemu_tcg_rr_cpu_thread_fn, cpu, +QEMU_THREAD_JOINABLE , errp)) { +return ; + } single_tcg_halt_cond = cpu->halt_cond; single_tcg_cpu_thread = cpu->thread;
@@ -1984,8 +1989,10 @@ static void qemu_hax_start_vcpu(CPUState *cpu, Error **errp)snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/HAX" , cpu->cpu_index); -qemu_thread_create (cpu->thread, thread_name, qemu_hax_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (cpu->thread, thread_name, qemu_hax_cpu_thread_fn, + cpu,QEMU_THREAD_JOINABLE , errp)) { +return ; + }#ifdef _WIN32 cpu->hThread =qemu_thread_get_handle (cpu->thread);#endif
@@ -2000,8 +2007,10 @@ static void qemu_kvm_start_vcpu(CPUState *cpu, Error **errp)qemu_cond_init (cpu->halt_cond);snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/KVM" , cpu->cpu_index); -qemu_thread_create (cpu->thread, thread_name, qemu_kvm_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (cpu->thread, thread_name, qemu_kvm_cpu_thread_fn, + cpu,QEMU_THREAD_JOINABLE , errp)) { +/* keep 'if' here in case there is further error handling logic */ + } }static void qemu_hvf_start_vcpu (CPUState *cpu,Error **errp)
@@ -2018,8 +2027,10 @@ static void qemu_hvf_start_vcpu(CPUState *cpu, Error **errp)snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/HVF" , cpu->cpu_index); -qemu_thread_create (cpu->thread, thread_name, qemu_hvf_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (cpu->thread, thread_name, qemu_hvf_cpu_thread_fn, + cpu,QEMU_THREAD_JOINABLE , errp)) { +/* keep 'if' here in case there is further error handling logic */ + } }static void qemu_whpx_start_vcpu (CPUState *cpu,Error **errp)
@@ -2031,8 +2042,10 @@ static void qemu_whpx_start_vcpu(CPUState *cpu, Error **errp)qemu_cond_init (cpu->halt_cond);snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/WHPX" , cpu->cpu_index); -qemu_thread_create (cpu->thread, thread_name, qemu_whpx_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (cpu->thread, thread_name, qemu_whpx_cpu_thread_fn, + cpu,QEMU_THREAD_JOINABLE , errp)) { +return ; + }#ifdef _WIN32 cpu->hThread =qemu_thread_get_handle (cpu->thread);#endif
@@ -2047,8 +2060,10 @@ static void qemu_dummy_start_vcpu(CPUState *cpu, Error **errp)qemu_cond_init (cpu->halt_cond);snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/DUMMY" , cpu->cpu_index); -qemu_thread_create (cpu->thread, thread_name, qemu_dummy_cpu_thread_fn, cpu, -QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (cpu->thread, thread_name, qemu_dummy_cpu_thread_fn, + cpu,QEMU_THREAD_JOINABLE , errp)) { +/* keep 'if' here in case there is further error handling logic */ + } }bool qemu_init_vcpu (CPUState *cpu,Error **errp)
dump.c +4 -2
@@ -2020,8 +2020,10 @@ void qmp_dump_guest_memory(bool paging, const char *file,if (detach_p) {/* detached dump */ s->detached = true; -qemu_thread_create (&s->dump_thread,"dump_thread" , dump_thread, - s,QEMU_THREAD_DETACHED ); +if (!qemu_thread_create (&s->dump_thread,"dump_thread" , dump_thread, + s,QEMU_THREAD_DETACHED , errp)) { +/* keep 'if' here in case there is further error handling logic */ + } }else {/* sync dump */ dump_process (s, errp);
hw/misc/edu.c +4 -2
@@ -355,8 +355,10 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp)qemu_mutex_init (&edu->thr_mutex);qemu_cond_init (&edu->thr_cond); -qemu_thread_create (&edu->thread,"edu" , edu_fact_thread, - edu,QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (&edu->thread,"edu" , edu_fact_thread, + edu,QEMU_THREAD_JOINABLE , errp)) { +return ; + }memory_region_init_io (&edu->mmio,OBJECT (edu), &edu_mmio_ops, edu,"edu-mmio" ,1 * MiB);
hw/ppc/spapr_hcall.c +8 -2
@@ -478,6 +478,7 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,sPAPRPendingHPT *pending = spapr->pending_hpt;uint64_t current_ram_size;int rc; +Error *local_err =NULL ;if (spapr->resize_hpt ==SPAPR_RESIZE_HPT_DISABLED ) {return H_AUTHORITY ;
@@ -538,8 +539,13 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, pending->shift = shift; pending->ret =H_HARDWARE ; -qemu_thread_create (&pending->thread,"sPAPR HPT prepare" , - hpt_prepare_thread, pending,QEMU_THREAD_DETACHED ); +if (!qemu_thread_create (&pending->thread,"sPAPR HPT prepare" , + hpt_prepare_thread, pending, +QEMU_THREAD_DETACHED , &local_err)) { +error_reportf_err (local_err,"failed to create hpt_prepare_thread: " ); +g_free (pending); +return H_RESOURCE ; + } spapr->pending_hpt = pending;
hw/rdma/rdma_backend.c +3 -1
@@ -164,8 +164,10 @@ static void start_comp_thread(RdmaBackendDev *backend_dev)snprintf (thread_name,sizeof (thread_name),"rdma_comp_%s" ,ibv_get_device_name (backend_dev->ib_dev)); backend_dev->comp_thread.run = true; +/* FIXME: let the further caller handle the error instead of abort() here */ qemu_thread_create (&backend_dev->comp_thread.thread, thread_name, - comp_handler_thread, backend_dev,QEMU_THREAD_DETACHED ); + comp_handler_thread, backend_dev, +QEMU_THREAD_DETACHED , &error_abort); } void rdma_backend_register_comp_handler(void (*handler)(int status,
hw/usb/ccid-card-emulated.c +9 -4
@@ -538,10 +538,15 @@ static void emulated_realize(CCIDCardState *base, Error **errp)error_setg (errp,"%s: failed to initialize vcard" ,TYPE_EMULATED_CCID );return ; } -qemu_thread_create (&card->event_thread_id,"ccid/event" , event_thread, - card,QEMU_THREAD_JOINABLE ); -qemu_thread_create (&card->apdu_thread_id,"ccid/apdu" , handle_apdu_thread, - card,QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (&card->event_thread_id,"ccid/event" , event_thread, + card,QEMU_THREAD_JOINABLE , errp)) { +return ; + } +if (!qemu_thread_create (&card->apdu_thread_id,"ccid/apdu" , + handle_apdu_thread, card, +QEMU_THREAD_JOINABLE , errp)) { +/* keep 'if' here in case there is further error handling logic */ + } }static void emulated_unrealize (CCIDCardState *base,Error **errp)
include/qemu/thread.h +2 -2
@@ -152,9 +152,9 @@ void qemu_event_reset(QemuEvent *ev);void qemu_event_wait (QemuEvent *ev);void qemu_event_destroy (QemuEvent *ev); -void qemu_thread_create (QemuThread *thread,const char *name, +bool qemu_thread_create (QemuThread *thread,const char *name,void *(*start_routine)(void *), -void *arg,int mode); +void *arg,int mode,Error **errp);void *qemu_thread_join (QemuThread *thread);void qemu_thread_get_self (QemuThread *thread);bool qemu_thread_is_self (QemuThread *thread);
io/task.c +2 -1
@@ -149,7 +149,8 @@ void qio_task_run_in_thread(QIOTask *task,"io-task-worker" , qio_task_thread_worker, data, - QEMU_THREAD_DETACHED); +QEMU_THREAD_DETACHED , + &error_abort); }
iothread.c +11 -5
@@ -161,9 +161,7 @@ static void iothread_complete(UserCreatable *obj, Error **errp) &local_error);if (local_error) {error_propagate (errp, local_error); -aio_context_unref (iothread->ctx); - iothread->ctx =NULL ; -return ; + goto fail; }qemu_mutex_init (&iothread->init_done_lock);
@@ -175,8 +173,12 @@ static void iothread_complete(UserCreatable *obj, Error **errp)*/ name =object_get_canonical_path_component (OBJECT (obj)); thread_name =g_strdup_printf ("IO %s" , name); -qemu_thread_create (&iothread->thread, thread_name, iothread_run, - iothread,QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (&iothread->thread, thread_name, iothread_run, + iothread,QEMU_THREAD_JOINABLE , errp)) { +g_free (thread_name); +g_free (name); + goto fail; + }g_free (thread_name);g_free (name);
@@ -187,6 +189,10 @@ static void iothread_complete(UserCreatable *obj, Error **errp) &iothread->init_done_lock); }qemu_mutex_unlock (&iothread->init_done_lock); +return ; +fail: +aio_context_unref (iothread->ctx); + iothread->ctx =NULL ; } typedef struct {
migration/migration.c +34 -15
90 lines not on this page · raw message
migration/postcopy-ram.c +12 -2
@@ -1082,6 +1082,8 @@ retry:int postcopy_ram_enable_notify (MigrationIncomingState *mis) { +Error *local_err =NULL ; +/* Open the fd for the kernel to give us userfaults */ mis->userfault_fd =syscall (__NR_userfaultfd,O_CLOEXEC |O_NONBLOCK );if (mis->userfault_fd ==-1 ) {
@@ -1108,8 +1110,16 @@ int postcopy_ram_enable_notify(MigrationIncomingState *mis) }qemu_sem_init (&mis->fault_thread_sem,0 ); -qemu_thread_create (&mis->fault_thread,"postcopy/fault" , - postcopy_ram_fault_thread, mis,QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (&mis->fault_thread,"postcopy/fault" , + postcopy_ram_fault_thread, mis, +QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err, +"failed to create postcopy_ram_fault_thread: " ); +close (mis->userfault_event_fd); +close (mis->userfault_fd); +qemu_sem_destroy (&mis->fault_thread_sem); +return -1 ; + }qemu_sem_wait (&mis->fault_thread_sem);qemu_sem_destroy (&mis->fault_thread_sem); mis->have_fault_thread = true;
migration/ram.c +29 -10
@@ -473,6 +473,7 @@ static void compress_threads_save_cleanup(void)static int compress_threads_save_setup (void ) {int i, thread_count; +Error *local_err =NULL ;if (!migrate_use_compression ()) {return 0 ;
@@ -502,9 +503,12 @@ static int compress_threads_save_setup(void) comp_param[i].quit = false;qemu_mutex_init (&comp_param[i].mutex);qemu_cond_init (&comp_param[i].cond); -qemu_thread_create (compress_threads + i,"compress" , - do_data_compress, comp_param + i, -QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (compress_threads + i,"compress" , + do_data_compress, comp_param + i, +QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err,"failed to create do_data_compress: " ); + goto exit; + } }return 0 ;
@@ -1082,8 +1086,14 @@ static void multifd_new_send_channel_async(QIOTask *task, gpointer opaque) p->c =QIO_CHANNEL (sioc);qio_channel_set_delay (p->c, false); p->running = true; -qemu_thread_create (&p->thread, p->name, multifd_send_thread, p, -QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (&p->thread, p->name, multifd_send_thread, p, +QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err, +"failed to create multifd_send_thread: " ); +multifd_save_cleanup (); +migrate_set_error (migrate_get_current (), local_err); +return ; + }atomic_inc (&multifd_send_state->count); }
@@ -1357,8 +1367,12 @@ bool multifd_recv_new_channel(QIOChannel *ioc) p->num_packets =1 ; p->running = true; -qemu_thread_create (&p->thread, p->name, multifd_recv_thread, p, -QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (&p->thread, p->name, multifd_recv_thread, + p,QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err,"failed to create multifd_recv_thread: " ); +multifd_recv_terminate_threads (local_err, true); +return false; + }atomic_inc (&multifd_recv_state->count);return multifd_recv_state->count ==migrate_multifd_channels (); }
@@ -3600,6 +3614,7 @@ static void compress_threads_load_cleanup(void)static int compress_threads_load_setup (QEMUFile *f) {int i, thread_count; +Error *local_err =NULL ;if (!migrate_use_compression ()) {return 0 ;
@@ -3621,9 +3636,13 @@ static int compress_threads_load_setup(QEMUFile *f)qemu_cond_init (&decomp_param[i].cond); decomp_param[i].done = true; decomp_param[i].quit = false; -qemu_thread_create (decompress_threads + i,"decompress" , - do_data_decompress, decomp_param + i, -QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (decompress_threads + i,"decompress" , + do_data_decompress, decomp_param + i, +QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err, +"failed to create do_data_decompress: " ); + goto exit; + } }return 0 ; exit:
migration/savevm.c +8 -3
@@ -1728,9 +1728,14 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis) mis->have_listen_thread = true;/* Start up the listening thread and wait for it to signal ready */ qemu_sem_init (&mis->listen_thread_sem,0 ); -qemu_thread_create (&mis->listen_thread,"postcopy/listen" , - postcopy_ram_listen_thread,NULL , -QEMU_THREAD_DETACHED ); +if (!qemu_thread_create (&mis->listen_thread,"postcopy/listen" , + postcopy_ram_listen_thread,NULL , +QEMU_THREAD_DETACHED , &local_err)) { +error_reportf_err (local_err, +"failed to create postcopy_ram_listen_thread: " ); +qemu_sem_destroy (&mis->listen_thread_sem); +return -1 ; + }qemu_sem_wait (&mis->listen_thread_sem);qemu_sem_destroy (&mis->listen_thread_sem);
tests/atomic_add-bench.c +2 -1
@@ -2,6 +2,7 @@#include "qemu/thread.h" #include "qemu/host-utils.h" #include "qemu/processor.h" +#include "qapi/error.h" struct thread_info {uint64_t r;
@@ -110,7 +111,7 @@ static void create_threads(void) info->r = (i +1 ) ^time (NULL );qemu_thread_create (&threads[i],NULL , thread_func, info, -QEMU_THREAD_JOINABLE ); +QEMU_THREAD_JOINABLE , &error_abort); } }
tests/iothread.c +1 -1
@@ -73,7 +73,7 @@ IOThread *iothread_new(void)qemu_mutex_init (&iothread->init_done_lock);qemu_cond_init (&iothread->init_done_cond);qemu_thread_create (&iothread->thread,NULL , iothread_run, - iothread,QEMU_THREAD_JOINABLE ); + iothread,QEMU_THREAD_JOINABLE , &error_abort);/* Wait for initialization to complete */ qemu_mutex_lock (&iothread->init_done_lock);
tests/qht-bench.c +2 -1
@@ -9,6 +9,7 @@#include "qemu/atomic.h" #include "qemu/qht.h" #include "qemu/rcu.h" +#include "qapi/error.h" #include "exec/tb-hash-xx.h" struct thread_stats {
@@ -247,7 +248,7 @@ th_create_n(QemuThread **threads, struct thread_info **infos, const char *name,prepare_thread_info (&info[i], offset + i); info[i].func = func;qemu_thread_create (&th[i], name, thread_func, &info[i], -QEMU_THREAD_JOINABLE ); +QEMU_THREAD_JOINABLE , &error_abort); } }
tests/rcutorture.c +2 -1
@@ -64,6 +64,7 @@#include "qemu/atomic.h" #include "qemu/rcu.h" #include "qemu/thread.h" +#include "qapi/error.h" long long n_reads =0LL ;long n_updates =0L ;
@@ -90,7 +91,7 @@ static void create_thread(void *(*func)(void *))exit (-1 ); }qemu_thread_create (&threads[n_threads],"test" , func, &data[n_threads], -QEMU_THREAD_JOINABLE ); +QEMU_THREAD_JOINABLE , &error_abort); n_threads++; }
tests/test-aio.c +1 -1
@@ -154,7 +154,7 @@ static void test_acquire(void)qemu_thread_create (&thread,"test_acquire_thread" , test_acquire_thread, - &data,QEMU_THREAD_JOINABLE ); + &data,QEMU_THREAD_JOINABLE , &error_abort);/* Block in aio_poll(), let other thread kick us and acquire context */ aio_context_acquire (ctx);
tests/test-rcu-list.c +2 -1
@@ -25,6 +25,7 @@#include "qemu/rcu.h" #include "qemu/thread.h" #include "qemu/rcu_queue.h" +#include "qapi/error.h" /* * Test variables.
@@ -68,7 +69,7 @@ static void create_thread(void *(*func)(void *))exit (-1 ); }qemu_thread_create (&threads[n_threads],"test" , func, &data[n_threads], -QEMU_THREAD_JOINABLE ); +QEMU_THREAD_JOINABLE , &error_abort); n_threads++; }
ui/vnc-jobs.c +6 -2
@@ -31,6 +31,7 @@#include "vnc-jobs.h" #include "qemu/sockets.h" #include "qemu/main-loop.h" +#include "qapi/error.h" #include "block/aio.h" /*
@@ -340,8 +341,11 @@ bool vnc_start_worker_thread(Error **errp) } q =vnc_queue_init (); -qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, q, -QEMU_THREAD_DETACHED ); +if (!qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, + q,QEMU_THREAD_DETACHED , errp)) { +vnc_queue_clear (q); +return false; + } queue = q;/* Set global queue */ out:return true;
util/compatfd.c +7 -2
@@ -91,8 +91,13 @@ static int qemu_signalfd_compat(const sigset_t *mask, Error **errp)memcpy (&info->mask, mask,sizeof (*mask)); info->fd = fds[1 ]; -qemu_thread_create (&thread,"signalfd_compat" , sigwait_compat, info, -QEMU_THREAD_DETACHED ); +if (!qemu_thread_create (&thread,"signalfd_compat" , sigwait_compat, + info,QEMU_THREAD_DETACHED , errp)) { +close (fds[0 ]); +close (fds[1 ]); +free (info); +return -1 ; + }return fds[0 ]; }
util/main-loop.c +1 -1
@@ -96,7 +96,7 @@ static int qemu_signal_init(Error **errp)sigdelset (&set,SIG_IPI ); sigfd =qemu_signalfd (&set, errp);if (sigfd ==-1 ) { -return -errno; +return -1 ; }fcntl_setfl (sigfd,O_NONBLOCK );
util/oslib-posix.c +13 -4
@@ -437,9 +437,12 @@ static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages,size_t size_per_thread;char *addr = area;int i =0 ; +int started_thread =0 ; +Error *local_err =NULL ; memset_thread_failed = false; memset_num_threads =get_memset_num_threads (smp_cpus); + started_thread = memset_num_threads; memset_thread =g_new0 (MemsetThread, memset_num_threads); numpages_per_thread = (numpages / memset_num_threads); size_per_thread = (hpagesize * numpages_per_thread);
@@ -448,13 +451,19 @@ static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, memset_thread[i].numpages = (i == (memset_num_threads -1 )) ? numpages : numpages_per_thread; memset_thread[i].hpagesize = hpagesize; -qemu_thread_create (&memset_thread[i].pgthread,"touch_pages" , - do_touch_pages, &memset_thread[i], -QEMU_THREAD_JOINABLE ); +if (!qemu_thread_create (&memset_thread[i].pgthread,"touch_pages" , + do_touch_pages, &memset_thread[i], +QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err,"failed to create do_touch_pages: " ); + memset_thread_failed = true; + started_thread = i; + goto out; + } addr += size_per_thread; numpages -= numpages_per_thread; } -for (i =0 ; i < memset_num_threads; i++) { +out: +for (i =0 ; i < started_thread; i++) {qemu_thread_join (&memset_thread[i].pgthread); }g_free (memset_thread);
util/qemu-thread-posix.c +14 -8
@@ -15,6 +15,7 @@#include "qemu/atomic.h" #include "qemu/notify.h" #include "qemu-thread-common.h" +#include "qapi/error.h" static bool name_threads;
@@ -504,9 +505,9 @@ static void *qemu_thread_start(void *args)return start_routine (arg); } -void qemu_thread_create (QemuThread *thread,const char *name, -void *(*start_routine)(void *), -void *arg,int mode) +bool qemu_thread_create (QemuThread *thread,const char *name, +void *(*start_routine)(void *), +void *arg,int mode,Error **errp) {sigset_t set, oldset;int err;
@@ -515,7 +516,8 @@ void qemu_thread_create(QemuThread *thread, const char *name, err =pthread_attr_init (&attr);if (err) { -error_exit (err, __func__); +error_setg (errp,"pthread_attr_init failed: %s" ,strerror (err)); +return false; }if (mode ==QEMU_THREAD_DETACHED ) {
@@ -530,16 +532,20 @@ void qemu_thread_create(QemuThread *thread, const char *name, qemu_thread_args->name =g_strdup (name); qemu_thread_args->start_routine = start_routine; qemu_thread_args->arg = arg; - err =pthread_create (&thread->thread, &attr, qemu_thread_start, qemu_thread_args); - -if (err) -error_exit (err, __func__); +if (err) { +error_setg (errp,"pthread_create failed: %s" ,strerror (err)); +pthread_attr_destroy (&attr); +g_free (qemu_thread_args->name); +g_free (qemu_thread_args); +return false; + }pthread_sigmask (SIG_SETMASK , &oldset,NULL );pthread_attr_destroy (&attr); +return true; }void qemu_thread_get_self (QemuThread *thread)
util/qemu-thread-win32.c +12 -4
@@ -20,6 +20,7 @@#include "qemu/thread.h" #include "qemu/notify.h" #include "qemu-thread-common.h" +#include "qapi/error.h" #include <process.h> static bool name_threads;
@@ -388,9 +389,9 @@ void *qemu_thread_join(QemuThread *thread)return ret; } -void qemu_thread_create (QemuThread *thread,const char *name, -void *(*start_routine)(void *), -void *arg,int mode) +bool qemu_thread_create (QemuThread *thread,const char *name, +void *(*start_routine)(void *), +void *arg,int mode,Error **errp) {HANDLE hThread;struct QemuThreadData *data;
@@ -409,10 +410,17 @@ void qemu_thread_create(QemuThread *thread, const char *name, hThread = (HANDLE )_beginthreadex (NULL ,0 , win32_start_routine, data,0 , &thread->tid);if (!hThread) { -error_exit (GetLastError (), __func__); +if (data->mode !=QEMU_THREAD_DETACHED ) { +DeleteCriticalSection (&data->cs); + } +error_setg_win32 (errp,GetLastError (), +"failed to create win32_start_routine" ); +g_free (data); +return false; }CloseHandle (hThread); thread->data = data; +return true; }void qemu_thread_get_self (QemuThread *thread)
util/rcu.c +2 -1
@@ -32,6 +32,7 @@#include "qemu/atomic.h" #include "qemu/thread.h" #include "qemu/main-loop.h" +#include "qapi/error.h" #if defined(CONFIG_MALLOC_TRIM )#include <malloc.h> #endif
@@ -325,7 +326,7 @@ static void rcu_init_complete(void)* must have been quiescent even after forking, just recreate it. */ qemu_thread_create (&thread,"call_rcu" , call_rcu_thread, -NULL ,QEMU_THREAD_DETACHED ); +NULL ,QEMU_THREAD_DETACHED , &error_abort);rcu_register_thread (); }
util/thread-pool.c +3 -1
@@ -22,6 +22,7 @@#include "trace.h" #include "block/thread-pool.h" #include "qemu/main-loop.h" +#include "qapi/error.h" static void do_spawn_thread (ThreadPool *pool);
@@ -132,7 +133,8 @@ static void do_spawn_thread(ThreadPool *pool) pool->new_threads--; pool->pending_threads++; -qemu_thread_create (&t,"worker" , worker_thread, pool,QEMU_THREAD_DETACHED ); +qemu_thread_create (&t,"worker" , worker_thread, pool, +QEMU_THREAD_DETACHED , &error_abort); }static void spawn_thread_bh_fn (void *opaque)
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH RFC v5 7/7] qemu_thread_create: propagate the error to callers to handle
Quoted 6 lines · Fei Li
Make
qemu_thread_create()return a Boolean to indicate if it succeeds rather than failing with an error. And add an Error parameter to hold the error message and let the callers handle it.Signed-off-by Fei Li <[email protected]>---
[...]
Quoted 26 lines
util/qemu-thread-posix.c +4
-3@@ -15,6 +15,7 @@#include "qemu/atomic.h" #include "qemu/notify.h" #include "qemu-thread-common.h" +#include "qapi/error.h" static bool name_threads;@@ -504,9 +505,9 @@ static void *qemu_thread_start(void *args)return start_routine (arg); } -void qemu_thread_create (QemuThread *thread,const char *name, -void *(*start_routine)(void *), -void *arg,int mode) +bool qemu_thread_create (QemuThread *thread,const char *name, +void *(*start_routine)(void *), +void *arg,int mode,Error **errp) {sigset_t set, oldset;int err;
util/qemu-thread-posix.c void qemu_thread_create(QemuThread *thread, const char *name, · line 520
Quoted 6 lines
util/qemu-thread-posix.c +2
-1@@ -515,7 +516,8 @@ void qemu_thread_create(QemuThread *thread, const char *name, err =pthread_attr_init (&attr);if (err) { -error_exit (err, __func__); +error_setg (errp,"pthread_attr_init failed: %s" ,strerror (err)); +return false;
The commit message claims this function was "failing with an error". Not true; error_exit() abort()s. It exit()ed until commit 53380ac37f2, v1.0. The name error_exit() became misleading then. The bad name is not this patch's problem, but its commit message needs to be corrected.
util/qemu-thread-posix.c void qemu_thread_create(QemuThread *thread, const char *name, · line 523
Quoted 3 lines
util/qemu-thread-posix.c +0
-0}if (mode ==QEMU_THREAD_DETACHED ) {
[...]
I think David Gilbert added the bite-sized task you took on. David, please review.
Re: [Qemu-devel] [PATCH RFC v5 7/7] qemu_thread_create: propagate the error to callers to handle
Quoted 36 lines · Markus Armbruster
Quoted 6 lines · Fei Li
Make
qemu_thread_create()return a Boolean to indicate if it succeeds rather than failing with an error. And add an Error parameter to hold the error message and let the callers handle it.Signed-off-by Fei Li <[email protected]>---
[...]
Quoted 27 lines
util/qemu-thread-posix.c +4
-3@@ -15,6 +15,7 @@#include "qemu/atomic.h" #include "qemu/notify.h" #include "qemu-thread-common.h" +#include "qapi/error.h" static bool name_threads;@@ -504,9 +505,9 @@ static void *qemu_thread_start(void *args)return start_routine (arg); } -void qemu_thread_create (QemuThread *thread,const char *name, -void *(*start_routine)(void *), -void *arg,int mode) +bool qemu_thread_create (QemuThread *thread,const char *name, +void *(*start_routine)(void *), +void *arg,int mode,Error **errp) {sigset_t set, oldset;int err;@@ -515,7 +516,8 @@ void qemu_thread_create(QemuThread *thread, const char *name,
Quoted 9 lines
util/qemu-thread-posix.c void qemu_thread_create(QemuThread *thread, const char *name, · line 520
Quoted 5 lines
util/qemu-thread-posix.c +2
-1err =pthread_attr_init (&attr);if (err) { -error_exit (err, __func__); +error_setg (errp,"pthread_attr_init failed: %s" ,strerror (err)); +return false;The commit message claims this function was "failing with an error". Not true;
error_exit()abort()s. It exit()ed until commit53380ac37f2, v1.0. The nameerror_exit()became misleading then. The bad name is not this patch's problem, but its commit message needs to be corrected.
Ok, thanks. I will amend the message to "instead of abort() directly"
Quoted 9 lines
util/qemu-thread-posix.c void qemu_thread_create(QemuThread *thread, const char *name, · line 523
Quoted 4 lines
util/qemu-thread-posix.c +0
-0}if (mode ==QEMU_THREAD_DETACHED ) {[...]
I think David Gilbert added the bite-sized task you took on. David, please review.
Thanks!
Have a nice day
Fei