qemu_thread_create: propagate the error to callers to handle
v9 cover qemu_thread_create: propagate the error to callers to handle
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 and the last patch fixes some segmentation faults occured
during the debugging. The 6/7 patch modifies theqemu_thread_create() by passing &error_abort and makes it return a
bool to all direct callers to indicate if it succeeds. The next 9
patches will improve on &error_abort for callers who can handle more
properly. The middle four fix some migration issues.
BTW, I am leaving my current company now, and will use "Fei Li <[email protected]>" to continue with this patch series.
Please help to review, thanks a lot! :)
v9:
- To ease the review and involve the appropriate maintainers, split the previous 6/7 patch into 10 patches: the 6/16 patch passes the &error_abort to qemu_thread_create() everywhere, and the next 9 patches will improve on &error_abort for callers who need.
- Add a new patch 5/7 to unify error handling for process_incoming_migration_co().
- Merge the previous 2/7 to current 7/16 to collaboratively handle for qemu_X_start_vcpu and for the qemu_init_vpcu in each arch.
- Add comment for multifd_recv_new_channel() in current patch 2/7.
v8:
- Remove previous two patches trying to fix the multifd issue on the source side, as we are still waiting for maintainer's opinions.
- Use atomic_read to get multifd_recv_state->count in patch 3/7.
- Get three more "Reviewed-by:".
v7:
- Split the previous multifd-migration into two patches: the src and the dst. For the dst, only dump the error instead of quitting.
- Safely do the cleanup for postcopy_ram_enable_notify().
- Split the previous migration-error-handling patch into two patches.
v6:
- Add a new migration-multifd related patch. BTW, delete the previous vnc related patch as it has been upstreamed.
- Use error_setg_errno() to set the errno when qemu_thread_create() fails for both Linux and Windows implementation.
- Optimize the first patch, less codes are needed
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
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 (16):
Fix segmentation fault when qemu_signal_init fails
migration: fix the multifd code when receiving less channels
migration: remove unused &local_err parameter in multifd_save_cleanup
migration: add more error handling for postcopy_ram_enable_notify
migration: unify error handling for process_incoming_migration_co
qemu_thread: Make qemu_thread_create() handle errors properly
qemu_thread: supplement error handling for qemu_X_start_vcpu
qemu_thread: supplement error handling for qmp_dump_guest_memory
qemu_thread: supplement error handling for pci_edu_realize
qemu_thread: supplement error handling for h_resize_hpt_prepare
qemu_thread: supplement error handling for emulated_realize
qemu_thread: supplement error handling for
iothread_complete/qemu_signalfd_compat
qemu_thread: supplement error handling for migration
qemu_thread: supplement error handling for vnc_start_worker_thread
qemu_thread: supplement error handling for touch_all_pages
qemu_thread_join: fix segmentation fault
accel/tcg/user-exec-stub.c | 3 +- cpus.c | 79 ++++++++++++++++++++++++++--------------- dump.c | 6 ++-- hw/misc/edu.c | 7 ++-- hw/ppc/spapr_hcall.c | 10 ++++-- hw/rdma/rdma_backend.c | 3 +- hw/usb/ccid-card-emulated.c | 14 +++++--- include/qemu/thread.h | 4 +-- include/qom/cpu.h | 2 +- io/task.c | 3 +- iothread.c | 16 ++++++--- migration/channel.c | 11 +++--- migration/migration.c | 68 ++++++++++++++++++++++------------- migration/migration.h | 2 +- migration/postcopy-ram.c | 15 ++++++-- migration/ram.c | 68 ++++++++++++++++++++++++----------- migration/ram.h | 4 +-- migration/savevm.c | 12 +++++-- 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 | 4 ++- util/compatfd.c | 11 ++++-- util/main-loop.c | 8 ++--- util/oslib-posix.c | 24 ++++++++----- util/qemu-thread-posix.c | 30 ++++++++++++---- util/qemu-thread-win32.c | 18 +++++++--- util/rcu.c | 3 +- util/thread-pool.c | 4 ++- 55 files changed, 378 insertions(+), 170 deletions(-)
Signature · 1 line
2.13.7
PATCH v9 1/16 Fix segmentation fault when qemu_signal_init fails
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().
To avoid such segmentation fault, add a new Error parameter to make the call trace to propagate the err to the final caller.
--- util/main-loop.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
util/main-loop.c +4 -4
@@ -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;
@@ -96,7 +96,7 @@ static int qemu_signal_init(void)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; }
@@ -109,7 +109,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 +148,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
PATCH v9 2/16 migration: fix the multifd code when receiving less channels
In reply to Fei LiIn our current code, when multifd is used during migration, if there is an error before the destination receives all new channels, the source keeps running, however the destination does not exit but keeps waiting until the source is killed deliberately.
Fix this by dumping the specific error and let users decide whether to quit from the destination side when failing to receive packet via some channel. And update the comment for multifd_recv_new_channel().
--- migration/channel.c | 11 ++++++----- migration/migration.c | 9 +++++++-- migration/migration.h | 2 +- migration/ram.c | 17 ++++++++++++++--- migration/ram.h | 2 +- 5 files changed, 29 insertions(+), 12 deletions(-)
migration/channel.c +6 -5
@@ -30,6 +30,7 @@void migration_channel_process_incoming (QIOChannel *ioc) {MigrationState *s =migrate_get_current (); +Error *local_err =NULL ;trace_migration_set_incoming_channel ( ioc,object_get_typename (OBJECT (ioc)));
@@ -38,13 +39,13 @@ void migration_channel_process_incoming(QIOChannel *ioc) *s->parameters.tls_creds && !object_dynamic_cast(OBJECT(ioc), TYPE_QIO_CHANNEL_TLS)) { - Error *local_err = NULL; migration_tls_channel_process_incoming(s, ioc, &local_err); -if (local_err) { -error_report_err (local_err); - } } else { -migration_ioc_process_incoming (ioc); +migration_ioc_process_incoming (ioc, &local_err); + } + +if (local_err) { +error_report_err (local_err); } }
migration/migration.c +7 -2
@@ -541,7 +541,7 @@ void migration_fd_process_incoming(QEMUFile *f)migration_incoming_process (); } -void migration_ioc_process_incoming (QIOChannel *ioc) +void migration_ioc_process_incoming (QIOChannel *ioc,Error **errp) {MigrationIncomingState *mis =migration_incoming_get_current ();bool start_migration;
@@ -563,9 +563,14 @@ void migration_ioc_process_incoming(QIOChannel *ioc)*/ start_migration = !migrate_use_multifd (); }else { +Error *local_err =NULL ;/* Multiple connections */ assert (migrate_use_multifd ()); - start_migration =multifd_recv_new_channel (ioc); + start_migration =multifd_recv_new_channel (ioc, &local_err); +if (local_err) { +error_propagate (errp, local_err); +return ; + } }if (start_migration) {
migration/migration.h +1 -1
@@ -229,7 +229,7 @@ struct MigrationStatevoid migrate_set_state (int *state,int old_state,int new_state);void migration_fd_process_incoming (QEMUFile *f); -void migration_ioc_process_incoming (QIOChannel *ioc); +void migration_ioc_process_incoming (QIOChannel *ioc,Error **errp);void migration_incoming_process (void );bool migration_has_all_channels (void );
migration/ram.c +14 -3
@@ -1322,8 +1322,13 @@ bool multifd_recv_all_channels_created(void)return thread_count ==atomic_read (&multifd_recv_state->count); } -/* Return true if multifd is ready for the migration, otherwise false */ -bool multifd_recv_new_channel (QIOChannel *ioc) +/* +* Try to receive all multifd channels to get ready for the migration. +* - Return true and do not set @errp when correctly receving all channels; +* - Return false and do not set @errp when correctly receiving the current one; +* - Return false and set @errp when failing to receive the current channel. +*/ +bool multifd_recv_new_channel (QIOChannel *ioc,Error **errp) {MultiFDRecvParams *p;Error *local_err =NULL ;
@@ -1332,6 +1337,10 @@ bool multifd_recv_new_channel(QIOChannel *ioc) id =multifd_recv_initial_packet (ioc, &local_err);if (id <0 ) {multifd_recv_terminate_threads (local_err); +error_propagate_prepend (errp, local_err, +"failed to receive packet" +" via multifd channel %d: " , +atomic_read (&multifd_recv_state->count));return false; }
@@ -1340,6 +1349,7 @@ bool multifd_recv_new_channel(QIOChannel *ioc)error_setg (&local_err,"multifd: received id '%d' already setup'" , id);multifd_recv_terminate_threads (local_err); +error_propagate (errp, local_err);return false; } p->c = ioc;
@@ -1351,7 +1361,8 @@ bool multifd_recv_new_channel(QIOChannel *ioc)qemu_thread_create (&p->thread, p->name, multifd_recv_thread, p,QEMU_THREAD_JOINABLE );atomic_inc (&multifd_recv_state->count); -return multifd_recv_state->count ==migrate_multifd_channels (); +return atomic_read (&multifd_recv_state->count) == +migrate_multifd_channels (); }/**
migration/ram.h +1 -1
@@ -47,7 +47,7 @@ int multifd_save_cleanup(Error **errp);int multifd_load_setup (void );int multifd_load_cleanup (Error **errp);bool multifd_recv_all_channels_created (void ); -bool multifd_recv_new_channel (QIOChannel *ioc); +bool multifd_recv_new_channel (QIOChannel *ioc,Error **errp);uint64_t ram_pagesize_summary (void );int ram_save_queue_pages (const char *rbname,ram_addr_t start,ram_addr_t len);
Signature · 1 line
2.13.7
PATCH v9 3/16 migration: remove unused &local_err parameter in multifd_save_cleanup
In reply to Fei LiAlways 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. And make the function be: void multifd_save_cleanup(void).
--- migration/migration.c | 5 +---- migration/ram.c | 11 ++++------- migration/ram.h | 2 +- 3 files changed, 6 insertions(+), 12 deletions(-)
migration/migration.c +1 -4
@@ -1386,7 +1386,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 ();
@@ -1397,9 +1396,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/ram.c +4 -7
@@ -917,13 +917,12 @@ static void multifd_send_terminate_threads(Error *err) } } -int multifd_save_cleanup (Error **errp) +void multifd_save_cleanup (void ) {int i; -int ret =0 ;if (!migrate_use_multifd ()) { -return 0 ; +return ; }multifd_send_terminate_threads (NULL );for (i =0 ; i <migrate_multifd_channels (); i++) {
@@ -953,7 +952,6 @@ int multifd_save_cleanup(Error **errp) multifd_send_state->pages =NULL ;g_free (multifd_send_state); multifd_send_state =NULL ; -return ret; }static void multifd_send_sync_main (void )
@@ -1071,9 +1069,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); - } +migrate_set_error (migrate_get_current (), local_err); +multifd_save_cleanup (); }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); +void 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
Re: [Qemu-devel] [PATCH for-4.0 v9 03/16] migration: remove unused &local_err parameter in multifd_save_cleanup
Quoted 8 lines · Fei Li
Always call
migrate_set_error()to set the error state without relying on whethermultifd_save_cleanup()succeeds. As the passed&local_erris never used inmultifd_save_cleanup(), remove it. And make the function be: voidmultifd_save_cleanup(void).Cc Dr. David Alan Gilbert <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Juan Quintela <[email protected]>
The commit message is confusing. Suggest:
migration: multifd_save_cleanup() can't fail, simplify
multifd_save_cleanup() takes an Error ** argument and returns an error code even though it can't actually fail. Its callers dutifully check for failure. Remove the useless argument and return value, and simplify the callers.
I think multifd_load_cleanup() has exactly the same issue. Should we clean it up, too? Juan, what do you think?
Re: [Qemu-devel] [PATCH for-4.0 v9 03/16] migration: remove unused &local_err parameter in multifd_save_cleanup
Quoted 15 lines · 在 2019年1月8日,00:50,Markus Armbruster <[email protected]> 写道:
Quoted 8 lines · Fei Li
Always call
migrate_set_error()to set the error state without relying on whethermultifd_save_cleanup()succeeds. As the passed&local_erris never used inmultifd_save_cleanup(), remove it. And make the function be: voidmultifd_save_cleanup(void).Cc Dr. David Alan Gilbert <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Juan Quintela <[email protected]>
Quoted 8 lines
The commit message is confusing. Suggest:
migration:
multifd_save_cleanup()can't fail, simplify
multifd_save_cleanup()takes an Error ** argument and returns an error code even though it can't actually fail. Its callers dutifully check for failure. Remove the useless argument and return value, and simplify the callers.
Nice, thanks for the clearer comment. :)
Have a nice day
Fei
Quoted 3 lines
I think
multifd_load_cleanup()has exactly the same issue. Should we clean it up, too? Juan, what do you think?
PATCH v9 4/16 migration: add more error handling for postcopy_ram_enable_notify
In reply to Fei LiCall postcopy_ram_incoming_cleanup() to do the cleanup when postcopy_ram_enable_notify fails. Besides, report the error message when qemu_ram_foreach_migratable_block() fails.
--- migration/postcopy-ram.c | 1 + migration/savevm.c | 1 + 2 files changed, 2 insertions(+)
migration/postcopy-ram.c +1 -0
@@ -1117,6 +1117,7 @@ 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" );return -1 ; }
migration/savevm.c +1 -0
@@ -1729,6 +1729,7 @@ static int loadvm_postcopy_handle_listen(MigrationIncomingState *mis)*/ if (migrate_postcopy_ram ()) {if (postcopy_ram_enable_notify (mis)) { +postcopy_ram_incoming_cleanup (mis);return -1 ; } }
Signature · 1 line
2.13.7
PATCH v9 5/16 migration: unify error handling for process_incoming_migration_co
In reply to Fei LiIn the current code, if process_incoming_migration_co() fails we do the same error handing: set the error state, close the source file, do the cleanup for multifd, and then exit(EXIT_FAILURE). To make the code clearer, add a "goto fail" to unify the error handling.
--- migration/migration.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
migration/migration.c +13 -13
@@ -438,15 +438,13 @@ static void process_incoming_migration_co(void *opaque)/* Make sure all file formats flush their mutable metadata */ bdrv_invalidate_cache_all (&local_err);if (local_err) { -migrate_set_state (&mis->state,MIGRATION_STATUS_ACTIVE , -MIGRATION_STATUS_FAILED );error_report_err (local_err); -exit (EXIT_FAILURE ); + goto fail; }if (colo_init_ram_cache () <0 ) {error_report ("Init ram cache failed" ); -exit (EXIT_FAILURE ); + goto fail; } qemu_thread_create(&mis->colo_incoming_thread, "COLO incoming",
@@ -461,20 +459,22 @@ static void process_incoming_migration_co(void *opaque) }if (ret <0 ) { -Error *local_err =NULL ; - -migrate_set_state (&mis->state,MIGRATION_STATUS_ACTIVE , -MIGRATION_STATUS_FAILED );error_report ("load of migration failed: %s" ,strerror (-ret)); -qemu_fclose (mis->from_src_file); -if (multifd_load_cleanup (&local_err) !=0 ) { -error_report_err (local_err); - } -exit (EXIT_FAILURE ); + goto fail; } mis->bh =qemu_bh_new (process_incoming_migration_bh, mis);qemu_bh_schedule (mis->bh); mis->migration_incoming_co =NULL ; +return ; +fail: + local_err =NULL ; +migrate_set_state (&mis->state,MIGRATION_STATUS_ACTIVE , +MIGRATION_STATUS_FAILED ); +qemu_fclose (mis->from_src_file); +if (multifd_load_cleanup (&local_err) !=0 ) { +error_report_err (local_err); + } +exit (EXIT_FAILURE ); }static void migration_incoming_setup (QEMUFile *f)
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH for-4.0 v9 05/16] migration: unify error handling for process_incoming_migration_co
Quoted 57 lines · * Fei Li ([email protected]) wrote:
In the current code, if
process_incoming_migration_co()fails we do the same error handing: set the error state, close the source file, do the cleanup for multifd, and thenexit(EXIT_FAILURE). To make the code clearer, add a "goto fail" to unify the error handling.Cc Markus Armbruster <[email protected]>Cc Dr. David Alan Gilbert <[email protected]>Cc Peter Xu <[email protected]>Signed-off-by Fei Li <[email protected]>--- migration/migration.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)migration/migration.c +6
-13@@ -438,15 +438,13 @@ static void process_incoming_migration_co(void *opaque)/* Make sure all file formats flush their mutable metadata */ bdrv_invalidate_cache_all (&local_err);if (local_err) { -migrate_set_state (&mis->state,MIGRATION_STATUS_ACTIVE , -MIGRATION_STATUS_FAILED );error_report_err (local_err); -exit (EXIT_FAILURE ); + goto fail; }if (colo_init_ram_cache () <0 ) {error_report ("Init ram cache failed" ); -exit (EXIT_FAILURE ); + goto fail; } qemu_thread_create(&mis->colo_incoming_thread, "COLO incoming",@@ -461,20 +459,22 @@ static void process_incoming_migration_co(void *opaque) }if (ret <0 ) { -Error *local_err =NULL ; - -migrate_set_state (&mis->state,MIGRATION_STATUS_ACTIVE , -MIGRATION_STATUS_FAILED );error_report ("load of migration failed: %s" ,strerror (-ret)); -qemu_fclose (mis->from_src_file); -if (multifd_load_cleanup (&local_err) !=0 ) { -error_report_err (local_err); - } -exit (EXIT_FAILURE ); + goto fail; } mis->bh =qemu_bh_new (process_incoming_migration_bh, mis);qemu_bh_schedule (mis->bh); mis->migration_incoming_co =NULL ; +return ; +fail: + local_err =NULL ;
migration/migration.c static void process_incoming_migration_co(void *opaque) · line 480
Quoted 10 lines
migration/migration.c +7
-0+migrate_set_state (&mis->state,MIGRATION_STATUS_ACTIVE , +MIGRATION_STATUS_FAILED ); +qemu_fclose (mis->from_src_file); +if (multifd_load_cleanup (&local_err) !=0 ) { +error_report_err (local_err); + } +exit (EXIT_FAILURE ); }static void migration_incoming_setup (QEMUFile *f)
OK, so this is really unifying the normal error case and the two colo-incoming error cases; so I think that's fine.
Quoted 3 lines
Signature · 1 line
2.13.7
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [PATCH for-4.0 v9 05/16] migration: unify error handling for process_incoming_migration_co
Quoted 67 lines · Dr. David Alan Gilbert
Quoted 66 lines · * Fei Li ([email protected]) wrote:
In the current code, if
process_incoming_migration_co()fails we do the same error handing: set the error state, close the source file, do the cleanup for multifd, and thenexit(EXIT_FAILURE). To make the code clearer, add a "goto fail" to unify the error handling.Cc Markus Armbruster <[email protected]>Cc Dr. David Alan Gilbert <[email protected]>Cc Peter Xu <[email protected]>Signed-off-by Fei Li <[email protected]>--- migration/migration.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)migration/migration.c +13
-13@@ -438,15 +438,13 @@ static void process_incoming_migration_co(void *opaque)/* Make sure all file formats flush their mutable metadata */ bdrv_invalidate_cache_all (&local_err);if (local_err) { -migrate_set_state (&mis->state,MIGRATION_STATUS_ACTIVE , -MIGRATION_STATUS_FAILED );error_report_err (local_err); -exit (EXIT_FAILURE ); + goto fail; }if (colo_init_ram_cache () <0 ) {error_report ("Init ram cache failed" ); -exit (EXIT_FAILURE ); + goto fail; } qemu_thread_create(&mis->colo_incoming_thread, "COLO incoming",@@ -461,20 +459,22 @@ static void process_incoming_migration_co(void *opaque) }if (ret <0 ) { -Error *local_err =NULL ; - -migrate_set_state (&mis->state,MIGRATION_STATUS_ACTIVE , -MIGRATION_STATUS_FAILED );error_report ("load of migration failed: %s" ,strerror (-ret)); -qemu_fclose (mis->from_src_file); -if (multifd_load_cleanup (&local_err) !=0 ) { -error_report_err (local_err); - } -exit (EXIT_FAILURE ); + goto fail; } mis->bh =qemu_bh_new (process_incoming_migration_bh, mis);qemu_bh_schedule (mis->bh); mis->migration_incoming_co =NULL ; +return ; +fail: + local_err =NULL ; +migrate_set_state (&mis->state,MIGRATION_STATUS_ACTIVE , +MIGRATION_STATUS_FAILED ); +qemu_fclose (mis->from_src_file); +if (multifd_load_cleanup (&local_err) !=0 ) { +error_report_err (local_err); + } +exit (EXIT_FAILURE ); }
Quoted 6 lines
migration/migration.c static void process_incoming_migration_co(void *opaque) · line 480
Quoted 1 line
migration/migration.c +0
-0static void migration_incoming_setup (QEMUFile *f)OK, so this is really unifying the normal error case and the two colo-incoming error cases; so I think that's fine.
Reviewed-by Dr. David Alan Gilbert <[email protected]>
Thanks for the review :)
Fei
Quoted 6 lines
Quoted 4 lines
Signature · 2 lines
-- 2.13.7--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
PATCH v9 6/16 qemu_thread: Make qemu_thread_create() handle errors properly
In reply to Fei Liqemu_thread_create() abort()s on error. Not nice. Give it a return value and an Error ** argument, so it can return success/failure.
Considering qemu_thread_create() is quite widely used in qemu, split this into two steps: this patch passes the &error_abort to qemu_thread_create() everywhere, and the next 9 patches will improve on &error_abort for callers who need.
--- cpus.c | 23 +++++++++++++++-------- dump.c | 3 ++- hw/misc/edu.c | 4 +++- hw/ppc/spapr_hcall.c | 4 +++- hw/rdma/rdma_backend.c | 3 ++- hw/usb/ccid-card-emulated.c | 5 +++-- include/qemu/thread.h | 4 ++-- io/task.c | 3 ++- iothread.c | 3 ++- migration/migration.c | 11 ++++++++--- migration/postcopy-ram.c | 4 +++- migration/ram.c | 12 ++++++++---- migration/savevm.c | 3 ++- 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 | 6 ++++-- util/compatfd.c | 6 ++++-- util/oslib-posix.c | 3 ++- util/qemu-thread-posix.c | 27 ++++++++++++++++++++------- util/qemu-thread-win32.c | 16 ++++++++++++---- util/rcu.c | 3 ++- util/thread-pool.c | 4 +++- 26 files changed, 112 insertions(+), 51 deletions(-)
cpus.c +15 -8
@@ -1961,15 +1961,17 @@ static void qemu_tcg_init_vcpu(CPUState *cpu)snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/TCG" , cpu->cpu_index); +/* TODO: let the callers handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort); }else {/* share a single thread for all cpus with TCG */ snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"ALL CPUs/TCG" ); +/* TODO: let the callers handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_tcg_rr_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort); single_tcg_halt_cond = cpu->halt_cond; single_tcg_cpu_thread = cpu->thread;
@@ -1997,8 +1999,9 @@ static void qemu_hax_start_vcpu(CPUState *cpu)snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/HAX" , cpu->cpu_index); +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_hax_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort);#ifdef _WIN32 cpu->hThread =qemu_thread_get_handle (cpu->thread);#endif
@@ -2013,8 +2016,9 @@ static void qemu_kvm_start_vcpu(CPUState *cpu)qemu_cond_init (cpu->halt_cond);snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/KVM" , cpu->cpu_index); +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_kvm_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort); }static void qemu_hvf_start_vcpu (CPUState *cpu)
@@ -2031,8 +2035,9 @@ static void qemu_hvf_start_vcpu(CPUState *cpu)snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/HVF" , cpu->cpu_index); +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_hvf_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort); }static void qemu_whpx_start_vcpu (CPUState *cpu)
@@ -2044,8 +2049,9 @@ static void qemu_whpx_start_vcpu(CPUState *cpu)qemu_cond_init (cpu->halt_cond);snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/WHPX" , cpu->cpu_index); +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_whpx_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort);#ifdef _WIN32 cpu->hThread =qemu_thread_get_handle (cpu->thread);#endif
@@ -2060,8 +2066,9 @@ static void qemu_dummy_start_vcpu(CPUState *cpu)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 ); +/* TODO: let the further caller handle the error instead of abort() here */ +qemu_thread_create (cpu->thread, thread_name, qemu_dummy_cpu_thread_fn, + cpu,QEMU_THREAD_JOINABLE , &error_abort); }void qemu_init_vcpu (CPUState *cpu)
dump.c +2 -1
@@ -2020,8 +2020,9 @@ void qmp_dump_guest_memory(bool paging, const char *file,if (detach_p) {/* detached dump */ s->detached = true; +/* TODO: let the further caller handle the error instead of abort() */ qemu_thread_create (&s->dump_thread,"dump_thread" , dump_thread, - s,QEMU_THREAD_DETACHED ); + s,QEMU_THREAD_DETACHED , &error_abort); }else {/* sync dump */ dump_process (s, errp);
hw/misc/edu.c +3 -1
@@ -28,6 +28,7 @@#include "hw/pci/msi.h" #include "qemu/timer.h" #include "qemu/main-loop.h" /* iothread mutex */ +#include "qapi/error.h" #include "qapi/visitor.h" #define TYPE_PCI_EDU_DEVICE "edu"
@@ -355,8 +356,9 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp)qemu_mutex_init (&edu->thr_mutex);qemu_cond_init (&edu->thr_cond); +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (&edu->thread,"edu" , edu_fact_thread, - edu,QEMU_THREAD_JOINABLE ); + edu,QEMU_THREAD_JOINABLE , &error_abort);memory_region_init_io (&edu->mmio,OBJECT (edu), &edu_mmio_ops, edu,"edu-mmio" ,1 * MiB);
hw/ppc/spapr_hcall.c +3 -1
@@ -538,8 +538,10 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, pending->shift = shift; pending->ret =H_HARDWARE ; +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (&pending->thread,"sPAPR HPT prepare" , - hpt_prepare_thread, pending,QEMU_THREAD_DETACHED ); + hpt_prepare_thread, pending, +QEMU_THREAD_DETACHED , &error_abort); spapr->pending_hpt = pending;
hw/rdma/rdma_backend.c +2 -1
@@ -263,7 +263,8 @@ static void start_comp_thread(RdmaBackendDev *backend_dev) ibv_get_device_name(backend_dev->ib_dev)); backend_dev->comp_thread.run = true;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)(void *ctx,
hw/usb/ccid-card-emulated.c +3 -2
@@ -544,10 +544,11 @@ static void emulated_realize(CCIDCardState *base, Error **errp)error_setg (errp,"%s: failed to initialize vcard" ,TYPE_EMULATED_CCID ); goto out2; } +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (&card->event_thread_id,"ccid/event" , event_thread, - card,QEMU_THREAD_JOINABLE ); + card,QEMU_THREAD_JOINABLE , &error_abort);qemu_thread_create (&card->apdu_thread_id,"ccid/apdu" , handle_apdu_thread, - card,QEMU_THREAD_JOINABLE ); + card,QEMU_THREAD_JOINABLE , &error_abort); out2:clean_event_notifier (card);
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 +2 -1
@@ -178,8 +178,9 @@ static void iothread_complete(UserCreatable *obj, Error **errp)*/ name =object_get_canonical_path_component (OBJECT (obj)); thread_name =g_strdup_printf ("IO %s" , name); +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (&iothread->thread, thread_name, iothread_run, - iothread,QEMU_THREAD_JOINABLE ); + iothread,QEMU_THREAD_JOINABLE , &error_abort);g_free (thread_name);g_free (name);
migration/migration.c +8 -3
@@ -447,8 +447,10 @@ static void process_incoming_migration_co(void *opaque) goto fail; } +/* TODO: let the further caller handle the error instead of abort() */ qemu_thread_create (&mis->colo_incoming_thread,"COLO incoming" , - colo_process_incoming_thread, mis,QEMU_THREAD_JOINABLE ); + colo_process_incoming_thread, mis, +QEMU_THREAD_JOINABLE , &error_abort); mis->have_colo_incoming_thread = true;qemu_coroutine_yield ();
@@ -2358,8 +2360,10 @@ static int open_return_path_on_source(MigrationState *ms,return 0 ; } +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (&ms->rp_state.rp_thread,"return path" , - source_return_path_thread, ms,QEMU_THREAD_JOINABLE ); + source_return_path_thread, ms, +QEMU_THREAD_JOINABLE , &error_abort);trace_open_return_path_on_source_continue ();
@@ -3189,8 +3193,9 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)migrate_fd_cleanup (s);return ; } +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (&s->thread,"live_migration" , migration_thread, s, -QEMU_THREAD_JOINABLE ); +QEMU_THREAD_JOINABLE , &error_abort); s->migration_thread_running = true; }
migration/postcopy-ram.c +3 -1
@@ -1109,8 +1109,10 @@ int postcopy_ram_enable_notify(MigrationIncomingState *mis) }qemu_sem_init (&mis->fault_thread_sem,0 ); +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (&mis->fault_thread,"postcopy/fault" , - postcopy_ram_fault_thread, mis,QEMU_THREAD_JOINABLE ); + postcopy_ram_fault_thread, mis, +QEMU_THREAD_JOINABLE , &error_abort);qemu_sem_wait (&mis->fault_thread_sem);qemu_sem_destroy (&mis->fault_thread_sem); mis->have_fault_thread = true;
migration/ram.c +8 -4
@@ -502,9 +502,10 @@ 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); +/* TODO: let the further caller handle the error instead of abort() */ qemu_thread_create (compress_threads + i,"compress" , do_data_compress, comp_param + i, -QEMU_THREAD_JOINABLE ); +QEMU_THREAD_JOINABLE , &error_abort); }return 0 ;
@@ -1075,8 +1076,9 @@ 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; +/* TODO: let the further caller handle the error instead of abort() */ qemu_thread_create (&p->thread, p->name, multifd_send_thread, p, -QEMU_THREAD_JOINABLE ); +QEMU_THREAD_JOINABLE , &error_abort);atomic_inc (&multifd_send_state->count); }
@@ -1355,8 +1357,9 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) p->num_packets =1 ; p->running = true; +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (&p->thread, p->name, multifd_recv_thread, p, -QEMU_THREAD_JOINABLE ); +QEMU_THREAD_JOINABLE , &error_abort);atomic_inc (&multifd_recv_state->count);return atomic_read (&multifd_recv_state->count) ==migrate_multifd_channels ();
@@ -3643,9 +3646,10 @@ 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; +/* TODO: let the further caller handle the error instead of abort() */ qemu_thread_create (decompress_threads + i,"decompress" , do_data_decompress, decomp_param + i, -QEMU_THREAD_JOINABLE ); +QEMU_THREAD_JOINABLE , &error_abort); }return 0 ; exit:
migration/savevm.c +2 -1
@@ -1747,9 +1747,10 @@ 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 ); +/* TODO: let the further caller handle the error instead of abort() here */ qemu_thread_create (&mis->listen_thread,"postcopy/listen" , postcopy_ram_listen_thread,NULL , -QEMU_THREAD_DETACHED ); +QEMU_THREAD_DETACHED , &error_abort);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
@@ -10,6 +10,7 @@#include "qemu/qht.h" #include "qemu/rcu.h" #include "qemu/xxhash.h" +#include "qapi/error.h" struct thread_stats {size_t rd;
@@ -248,7 +249,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 +4 -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" /*
@@ -339,7 +340,8 @@ void vnc_start_worker_thread(void)return ; q =vnc_queue_init (); -qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, q, -QEMU_THREAD_DETACHED ); +/* TODO: let the further caller handle the error instead of abort() here */ +qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, + q,QEMU_THREAD_DETACHED , &error_abort); queue = q;/* Set global queue */ }
util/compatfd.c +4 -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>
@@ -88,8 +89,9 @@ static int qemu_signalfd_compat(const sigset_t *mask)memcpy (&info->mask, mask,sizeof (*mask)); info->fd = fds[1 ]; -qemu_thread_create (&thread,"signalfd_compat" , sigwait_compat, info, -QEMU_THREAD_DETACHED ); +/* TODO: let the further caller handle the error instead of abort() here */ +qemu_thread_create (&thread,"signalfd_compat" , sigwait_compat, + info,QEMU_THREAD_DETACHED , &error_abort);return fds[0 ]; }
util/oslib-posix.c +2 -1
@@ -448,9 +448,10 @@ 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; +/* TODO: let the callers handle the error instead of abort() here */ qemu_thread_create (&memset_thread[i].pgthread,"touch_pages" , do_touch_pages, &memset_thread[i], -QEMU_THREAD_JOINABLE ); +QEMU_THREAD_JOINABLE , &error_abort); addr += size_per_thread; numpages -= numpages_per_thread; }
util/qemu-thread-posix.c +20 -7
@@ -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;
@@ -500,9 +501,13 @@ static void *qemu_thread_start(void *args)return r; } -void qemu_thread_create (QemuThread *thread,const char *name, -void *(*start_routine)(void *), -void *arg,int mode) +/* +* Return a boolean: true/false to indicate whether it succeeds. +* If fails, propagate the error to Error **errp and set the errno. +*/ +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;
@@ -511,7 +516,9 @@ void qemu_thread_create(QemuThread *thread, const char *name, err =pthread_attr_init (&attr);if (err) { -error_exit (err, __func__); + errno = err; +error_setg_errno (errp, errno,"pthread_attr_init failed" ); +return false; }if (mode ==QEMU_THREAD_DETACHED ) {
@@ -529,13 +536,19 @@ void qemu_thread_create(QemuThread *thread, const char *name, err =pthread_create (&thread->thread, &attr, qemu_thread_start, qemu_thread_args); - -if (err) -error_exit (err, __func__); +if (err) { + errno = err; +error_setg_errno (errp, errno,"pthread_create failed" ); +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_errno (errp, errno, +"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 for-4.0 v9 06/16] qemu_thread: Make qemu_thread_create() handle errors properly
Quoted 11 lines · Fei Li
qemu_thread_create()abort()s on error. Not nice. Give it a return value and an Error ** argument, so it can return success/failure.Considering
qemu_thread_create()is quite widely used in qemu, split this into two steps: this patch passes the&error_aborttoqemu_thread_create()everywhere, and the next 9 patches will improve on&error_abortfor callers who need.Cc Markus Armbruster <[email protected]>Cc Paolo Bonzini <[email protected]>Signed-off-by Fei Li <[email protected]>
The commit message's title promises more than the patch delivers. Suggest:
qemu_thread: Make qemu_thread_create() take Error ** argument
The rest of the commit message is fine.
Quoted 43 lines
--- cpus.c | 23 +++++++++++++++-------- dump.c | 3 ++- hw/misc/edu.c | 4 +++- hw/ppc/spapr_hcall.c | 4 +++- hw/rdma/rdma_backend.c | 3 ++- hw/usb/ccid-card-emulated.c | 5 +++-- include/qemu/thread.h | 4 ++-- io/task.c | 3 ++- iothread.c | 3 ++- migration/migration.c | 11 ++++++++--- migration/postcopy-ram.c | 4 +++- migration/ram.c | 12 ++++++++---- migration/savevm.c | 3 ++- 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 | 6 ++++-- util/compatfd.c | 6 ++++-- util/oslib-posix.c | 3 ++- util/qemu-thread-posix.c | 27 ++++++++++++++++++++------- util/qemu-thread-win32.c | 16 ++++++++++++---- util/rcu.c | 3 ++- util/thread-pool.c | 4 +++- 26 files changed, 112 insertions(+), 51 deletions(-)cpus.c +2
-1@@ -1961,15 +1961,17 @@ static void qemu_tcg_init_vcpu(CPUState *cpu)snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/TCG" , cpu->cpu_index); +/* TODO: let the callers handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort); }else {
cpus.c static void qemu_tcg_init_vcpu(CPUState *cpu) · line 1977
Quoted 10 lines
cpus.c +2
-1/* share a single thread for all cpus with TCG */ snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"ALL CPUs/TCG" ); +/* TODO: let the callers handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_tcg_rr_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort); single_tcg_halt_cond = cpu->halt_cond; single_tcg_cpu_thread = cpu->thread;
You add this TODO comment to 24 out of 37 calls. Can you give your reasons for adding it to some calls, but not to others?
[...]
Quoted 16 lines
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);
[...]
Quoted 13 lines
util/qemu-thread-posix.c +1
-0@@ -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;
util/qemu-thread-posix.c static void *qemu_thread_start(void *args) · line 507
Quoted 10 lines
util/qemu-thread-posix.c +4
-3@@ -500,9 +501,13 @@ static void *qemu_thread_start(void *args)return r; } -void qemu_thread_create (QemuThread *thread,const char *name, -void *(*start_routine)(void *), -void *arg,int mode) +/* +* Return a boolean: true/false to indicate whether it succeeds. +* If fails, propagate the error to Error **errp and set the errno. +*/
Let's write something that can pass as a function contract:
/*
* Create a new thread with name @name
* The thread executes @start_routine() with argument @arg.
* The thread will be created in a detached state if @mode is
* QEMU_THREAD_DETACHED, and in a jounable state if it's
* QEMU_THREAD_JOINABLE.
* On success, return true.
* On failure, set @errno, store an error through @errp and return
* false.
*/
Personally, I'd return negative errno instead of false, and dispense with setting errno.
Quoted 84 lines
util/qemu-thread-posix.c +15
-4+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;@@ -511,7 +516,9 @@ void qemu_thread_create(QemuThread *thread, const char *name, err =pthread_attr_init (&attr);if (err) { -error_exit (err, __func__); + errno = err; +error_setg_errno (errp, errno,"pthread_attr_init failed" ); +return false; }if (mode ==QEMU_THREAD_DETACHED ) {@@ -529,13 +536,19 @@ void qemu_thread_create(QemuThread *thread, const char *name, err =pthread_create (&thread->thread, &attr, qemu_thread_start, qemu_thread_args); - -if (err) -error_exit (err, __func__); +if (err) { + errno = err; +error_setg_errno (errp, errno,"pthread_create failed" ); +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_errno (errp, errno, +"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)
[...]
Re: [Qemu-devel] [PATCH for-4.0 v9 06/16] qemu_thread: Make qemu_thread_create() handle errors properly
Quoted 14 lines · 在 2019年1月8日,01:18,Markus Armbruster <[email protected]> 写道:
Quoted 8 lines · Fei Li
qemu_thread_create()abort()s on error. Not nice. Give it a return value and an Error ** argument, so it can return success/failure.Considering
qemu_thread_create()is quite widely used in qemu, split this into two steps: this patch passes the&error_aborttoqemu_thread_create()everywhere, and the next 9 patches will improve on&error_abortfor callers who need.
Quoted 8 lines
Quoted 3 lines
Cc Markus Armbruster <[email protected]>Cc Paolo Bonzini <[email protected]>Signed-off-by Fei Li <[email protected]>The commit message's title promises more than the patch delivers. Suggest:
qemu_thread: Makeqemu_thread_create()take Error ** argument
Ok, thanks for the suggestion. :)
Quoted 54 lines
The rest of the commit message is fine.
Quoted 51 lines
---
cpus.c | 23 +++++++++++++++-------- dump.c | 3 ++- hw/misc/edu.c | 4 +++- hw/ppc/spapr_hcall.c | 4 +++- hw/rdma/rdma_backend.c | 3 ++- hw/usb/ccid-card-emulated.c | 5 +++-- include/qemu/thread.h | 4 ++-- io/task.c | 3 ++- iothread.c | 3 ++- migration/migration.c | 11 ++++++++--- migration/postcopy-ram.c | 4 +++- migration/ram.c | 12 ++++++++---- migration/savevm.c | 3 ++- 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 | 6 ++++-- util/compatfd.c | 6 ++++-- util/oslib-posix.c | 3 ++- util/qemu-thread-posix.c | 27 ++++++++++++++++++++------- util/qemu-thread-win32.c | 16 ++++++++++++---- util/rcu.c | 3 ++- util/thread-pool.c | 4 +++- 26 files changed, 112 insertions(+), 51 deletions(-)cpus.c +4
-2@@ -1961,15 +1961,17 @@ static void qemu_tcg_init_vcpu(CPUState *cpu)snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/TCG" , cpu->cpu_index); +/* TODO: let the callers handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort); }else {/* share a single thread for all cpus with TCG */ snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"ALL CPUs/TCG" ); +/* TODO: let the callers handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_tcg_rr_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort);
Quoted 5 lines
cpus.c static void qemu_tcg_init_vcpu(CPUState *cpu) · line 1977
Quoted 2 lines
cpus.c +0
-0single_tcg_halt_cond = cpu->halt_cond; single_tcg_cpu_thread = cpu->thread;You add this TODO comment to 24 out of 37 calls. Can you give your reasons for adding it to some calls, but not to others?
For those have TODO, I polish them in the next following patches, and for those do not have TODO I just let them use &error_abort.
Quoted 45 lines
[...]
Quoted 16 lines
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);[...]
Quoted 13 lines
util/qemu-thread-posix.c +1
-0@@ -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;util/qemu-thread-posix.c static void *qemu_thread_start(void *args) · line 507
Quoted 10 lines
util/qemu-thread-posix.c +4
-3@@ -500,9 +501,13 @@ static void *qemu_thread_start(void *args)return r; } -void qemu_thread_create (QemuThread *thread,const char *name, -void *(*start_routine)(void *), -void *arg,int mode) +/* +* Return a boolean: true/false to indicate whether it succeeds. +* If fails, propagate the error to Error **errp and set the errno. +*/ Let's write something that can pass as a function contract:
Quoted 10 lines
/*
* Create a new thread with name @name
* The thread executes @start_routine() with argument @arg.
* The thread will be created in a detached state if @mode is
*QEMU_THREAD_DETACHED, and in a jounable state if it's
*QEMU_THREAD_JOINABLE.
* On success, return true.
* On failure, set @errno, store an error through @errp and return
* false.
*/
Thanks so much for amending! :)
Quoted 2 lines
Personally, I'd return negative errno instead of false, and dispense with setting errno.
Emm, I think I have replied this in last version, but due to several reasons I did not wait for your feedback and sent the v9. Sorry for that.. And I like to paste my two considerations here:
“- Actually only one caller needs the errno, that is the above qemu_signalfd_compat().
- For the returning value, I remember there's once a email thread talking about it: returning a bool (and let the passed errp hold the error message) is to keep the consistency with glib.
”
So IMO I am wondering whether it is really needed to change the bool (true/false) to int (0/-errno), just for that sole function: qemu_signalfd_compat() which needs the errno. Besides if we return -errno, for each caller we need add a local variable like “ret= qemu_thread_create()” to store the -errno.
Have a nice day, thanks
Fei
Quoted 86 lines
Quoted 85 lines
util/qemu-thread-posix.c +15
-4+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;@@ -511,7 +516,9 @@ void qemu_thread_create(QemuThread *thread, const char *name, err =pthread_attr_init (&attr);if (err) { -error_exit (err, __func__); + errno = err; +error_setg_errno (errp, errno,"pthread_attr_init failed" ); +return false; }if (mode ==QEMU_THREAD_DETACHED ) {@@ -529,13 +536,19 @@ void qemu_thread_create(QemuThread *thread, const char *name, err =pthread_create (&thread->thread, &attr, qemu_thread_start, qemu_thread_args); - -if (err) -error_exit (err, __func__); +if (err) { + errno = err; +error_setg_errno (errp, errno,"pthread_create failed" ); +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_errno (errp, errno, +"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)[...]
Re: [Qemu-devel] [PATCH for-4.0 v9 06/16] qemu_thread: Make qemu_thread_create() handle errors properly
Quoted 75 lines · fei
Quoted 12 lines · 在 2019年1月8日,01:18,Markus Armbruster <[email protected]> 写道:
Quoted 8 lines · Fei Li
qemu_thread_create()abort()s on error. Not nice. Give it a return value and an Error ** argument, so it can return success/failure.Considering
qemu_thread_create()is quite widely used in qemu, split this into two steps: this patch passes the&error_aborttoqemu_thread_create()everywhere, and the next 9 patches will improve on&error_abortfor callers who need.Quoted 8 lines
Quoted 3 lines
Cc Markus Armbruster <[email protected]>Cc Paolo Bonzini <[email protected]>Signed-off-by Fei Li <[email protected]>The commit message's title promises more than the patch delivers. Suggest:
qemu_thread: Makeqemu_thread_create()take Error ** argumentOk, thanks for the suggestion. :)
Quoted 54 lines
The rest of the commit message is fine.
Quoted 51 lines
---
cpus.c | 23 +++++++++++++++-------- dump.c | 3 ++- hw/misc/edu.c | 4 +++- hw/ppc/spapr_hcall.c | 4 +++- hw/rdma/rdma_backend.c | 3 ++- hw/usb/ccid-card-emulated.c | 5 +++-- include/qemu/thread.h | 4 ++-- io/task.c | 3 ++- iothread.c | 3 ++- migration/migration.c | 11 ++++++++--- migration/postcopy-ram.c | 4 +++- migration/ram.c | 12 ++++++++---- migration/savevm.c | 3 ++- 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 | 6 ++++-- util/compatfd.c | 6 ++++-- util/oslib-posix.c | 3 ++- util/qemu-thread-posix.c | 27 ++++++++++++++++++++------- util/qemu-thread-win32.c | 16 ++++++++++++---- util/rcu.c | 3 ++- util/thread-pool.c | 4 +++- 26 files changed, 112 insertions(+), 51 deletions(-)cpus.c +4
-2@@ -1961,15 +1961,17 @@ static void qemu_tcg_init_vcpu(CPUState *cpu)snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/TCG" , cpu->cpu_index); +/* TODO: let the callers handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort); }else {/* share a single thread for all cpus with TCG */ snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"ALL CPUs/TCG" ); +/* TODO: let the callers handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_tcg_rr_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort);
Quoted 6 lines
Quoted 5 lines
cpus.c static void qemu_tcg_init_vcpu(CPUState *cpu) · line 1977
Quoted 2 lines
cpus.c +0
-0single_tcg_halt_cond = cpu->halt_cond; single_tcg_cpu_thread = cpu->thread;You add this TODO comment to 24 out of 37 calls. Can you give your reasons for adding it to some calls, but not to others?
For those have TODO, I polish them in the next following patches, and for those do not have TODO I just let them use
&error_abort.
Please mention that in the commit message.
Quoted 55 lines
Quoted 45 lines
[...]
Quoted 16 lines
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);[...]
Quoted 13 lines
util/qemu-thread-posix.c +1
-0@@ -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;util/qemu-thread-posix.c static void *qemu_thread_start(void *args) · line 507
Quoted 10 lines
util/qemu-thread-posix.c +4
-3@@ -500,9 +501,13 @@ static void *qemu_thread_start(void *args)return r; } -void qemu_thread_create (QemuThread *thread,const char *name, -void *(*start_routine)(void *), -void *arg,int mode) +/* +* Return a boolean: true/false to indicate whether it succeeds. +* If fails, propagate the error to Error **errp and set the errno. +*/ Let's write something that can pass as a function contract:
Quoted 10 lines
/*
* Create a new thread with name @name
* The thread executes @start_routine() with argument @arg.
* The thread will be created in a detached state if @mode is
*QEMU_THREAD_DETACHED, and in a jounable state if it's
*QEMU_THREAD_JOINABLE.
* On success, return true.
* On failure, set @errno, store an error through @errp and return
* false.
*/
Quoted 5 lines
Thanks so much for amending! :)
Quoted 2 lines
Personally, I'd return negative errno instead of false, and dispense with setting errno.
Emm, I think I have replied this in last version, but due to several reasons I did not wait for your feedback and sent the v9. Sorry for that.. And I like to paste my two considerations here:
“- Actually only one caller needs the errno, that is the aboveqemu_signalfd_compat().
Yes.
Quoted 1 line
- For the returning value, I remember there's once a email thread talking about it: returning a bool (and let the passed errp hold the error message) is to keep the consistency with glib.
GLib doesn't discourage return types other than boolean. It only asks that if you return boolean, then true should mean success and false should mean failure. See
https://developer.gnome.org/glib/stable/glib-Error-Reporting.html
under "Rules for use of GError", item "By convention, if you return a boolean value".
The discussion you remember was about a convention we used to enforce in QEMU, namely to avoid returning boolean success, and return void instead. That was basically a bad idea.
Quoted 1 line
So IMO I am wondering whether it is really needed to change the bool (true/false) to int (0/-errno), just for that sole function:
qemu_signalfd_compat()which needs the errno. Besides if we return -errno, for each caller we need add a local variable like “ret= qemu_thread_create()” to store the -errno.
Well, you either assign the error code to errno just for that caller, or you return the error code just for that caller. I'd do the latter because I consider it slightly simpler. Compare
* On success, return true.
* On failure, set @errno, store an error through @errp and return
* false.
to
* On success, return zero.
* On failure, store an error through @errp and return negative errno.
where the second sentence describes just two instead of three actions.
[...]
Re: [Qemu-devel] [PATCH for-4.0 v9 06/16] qemu_thread: Make qemu_thread_create() handle errors properly
Quoted 75 lines · Markus Armbruster
Quoted 73 lines · fei
Quoted 12 lines · 在 2019年1月8日,01:18,Markus Armbruster <[email protected]> 写道:
Quoted 8 lines · Fei Li
qemu_thread_create()abort()s on error. Not nice. Give it a return value and an Error ** argument, so it can return success/failure.Considering
qemu_thread_create()is quite widely used in qemu, split this into two steps: this patch passes the&error_aborttoqemu_thread_create()everywhere, and the next 9 patches will improve on&error_abortfor callers who need.Quoted 7 lines
Quoted 3 lines
Cc Markus Armbruster <[email protected]>Cc Paolo Bonzini <[email protected]>Signed-off-by Fei Li <[email protected]>The commit message's title promises more than the patch delivers. Suggest:
qemu_thread: Makeqemu_thread_create()take Error ** argumentOk, thanks for the suggestion. :)
Quoted 53 lines
The rest of the commit message is fine.
Quoted 51 lines
---
cpus.c | 23 +++++++++++++++-------- dump.c | 3 ++- hw/misc/edu.c | 4 +++- hw/ppc/spapr_hcall.c | 4 +++- hw/rdma/rdma_backend.c | 3 ++- hw/usb/ccid-card-emulated.c | 5 +++-- include/qemu/thread.h | 4 ++-- io/task.c | 3 ++- iothread.c | 3 ++- migration/migration.c | 11 ++++++++--- migration/postcopy-ram.c | 4 +++- migration/ram.c | 12 ++++++++---- migration/savevm.c | 3 ++- 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 | 6 ++++-- util/compatfd.c | 6 ++++-- util/oslib-posix.c | 3 ++- util/qemu-thread-posix.c | 27 ++++++++++++++++++++------- util/qemu-thread-win32.c | 16 ++++++++++++---- util/rcu.c | 3 ++- util/thread-pool.c | 4 +++- 26 files changed, 112 insertions(+), 51 deletions(-)cpus.c +4
-2@@ -1961,15 +1961,17 @@ static void qemu_tcg_init_vcpu(CPUState *cpu)snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"CPU %d/TCG" , cpu->cpu_index); +/* TODO: let the callers handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort); }else {/* share a single thread for all cpus with TCG */ snprintf (thread_name,VCPU_THREAD_NAME_SIZE ,"ALL CPUs/TCG" ); +/* TODO: let the callers handle the error instead of abort() here */ qemu_thread_create (cpu->thread, thread_name, qemu_tcg_rr_cpu_thread_fn, - cpu,QEMU_THREAD_JOINABLE ); + cpu,QEMU_THREAD_JOINABLE , &error_abort);
Quoted 6 lines
Quoted 5 lines
Quoted 4 lines
cpus.c static void qemu_tcg_init_vcpu(CPUState *cpu) · line 1977
Quoted 2 lines
cpus.c +0
-0single_tcg_halt_cond = cpu->halt_cond; single_tcg_cpu_thread = cpu->thread;You add this TODO comment to 24 out of 37 calls. Can you give your reasons for adding it to some calls, but not to others?
For those have TODO, I polish them in the next following patches, and for those do not have TODO I just let them use
&error_abort.Please mention that in the commit message.
ok.
Quoted 84 lines
Quoted 54 lines
Quoted 44 lines
[...]
Quoted 16 lines
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);[...]
Quoted 13 lines
util/qemu-thread-posix.c +1
-0@@ -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;util/qemu-thread-posix.c static void *qemu_thread_start(void *args) · line 507
Quoted 10 lines
util/qemu-thread-posix.c +4
-3@@ -500,9 +501,13 @@ static void *qemu_thread_start(void *args)return r; } -void qemu_thread_create (QemuThread *thread,const char *name, -void *(*start_routine)(void *), -void *arg,int mode) +/* +* Return a boolean: true/false to indicate whether it succeeds. +* If fails, propagate the error to Error **errp and set the errno. +*/ Let's write something that can pass as a function contract:
Quoted 10 lines
/*
* Create a new thread with name @name
* The thread executes @start_routine() with argument @arg.
* The thread will be created in a detached state if @mode is
*QEMU_THREAD_DETACHED, and in a jounable state if it's
*QEMU_THREAD_JOINABLE.
* On success, return true.
* On failure, set @errno, store an error through @errp and return
* false.
*/Quoted 5 lines
Thanks so much for amending! :)
Quoted 2 lines
Personally, I'd return negative errno instead of false, and dispense with setting errno.
Emm, I think I have replied this in last version, but due to several reasons I did not wait for your feedback and sent the v9. Sorry for that.. And I like to paste my two considerations here:
“- Actually only one caller needs the errno, that is the aboveqemu_signalfd_compat().Yes.
Quoted 1 line
- For the returning value, I remember there's once a email thread talking about it: returning a bool (and let the passed errp hold the error message) is to keep the consistency with glib.
GLib doesn't discourage return types other than boolean. It only asks that if you return boolean, then true should mean success and false should mean failure. See
https://developer.gnome.org/glib/stable/glib-Error-Reporting.html
under "Rules for use of GError", item "By convention, if you return a boolean value".
The discussion you remember was about a convention we used to enforce in QEMU, namely to avoid returning boolean success, and return void instead. That was basically a bad idea.
Quoted 1 line
So IMO I am wondering whether it is really needed to change the bool (true/false) to int (0/-errno), just for that sole function:
qemu_signalfd_compat()which needs the errno. Besides if we return -errno, for each caller we need add a local variable like “ret= qemu_thread_create()” to store the -errno.Well, you either assign the error code to errno just for that caller, or you return the error code just for that caller. I'd do the latter because I consider it slightly simpler. Compare
* On success, return true.
* On failure, set @errno, store an error through @errp and return
* false.
Quoted 8 lines
to
* On success, return zero.
* On failure, store an error through @errp and return negative errno.where the second sentence describes just two instead of three actions.
[...]
Ok, decribing two actions than three is indeed simpler. But I still have one uncertain:
for those callers do not need the errno value, could we just check the return value to see whether it is negative, but not cache the unused return value? I mean
In the caller:
{...
if (qemu_thread_create() < 0) {// do some cleanup} ...}
instead of
{ int ret;
...
ret = qemu_thread_create();
if (ret < 0) { //do some cleanup }
...}
As the first one can lessen quite a lot of codes. :)
Have a nice day, thanks
Fei
Re: [Qemu-devel] [PATCH for-4.0 v9 06/16] qemu_thread: Make qemu_thread_create() handle errors properly
Quoted 6 lines · Fei Li
Quoted 5 lines · Markus Armbruster
Quoted 3 lines · fei
Quoted 3 lines · 在 2019年1月8日,01:18,Markus Armbruster <[email protected]> 写道:
Fei Li <[email protected]> writes:
[...]
Quoted 79 lines
Quoted 65 lines
Quoted 35 lines
Quoted 25 lines
Quoted 13 lines
util/qemu-thread-posix.c +1
-0@@ -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;util/qemu-thread-posix.c static void *qemu_thread_start(void *args) · line 507
Quoted 10 lines
util/qemu-thread-posix.c +4
-3@@ -500,9 +501,13 @@ static void *qemu_thread_start(void *args)return r; } -void qemu_thread_create (QemuThread *thread,const char *name, -void *(*start_routine)(void *), -void *arg,int mode) +/* +* Return a boolean: true/false to indicate whether it succeeds. +* If fails, propagate the error to Error **errp and set the errno. +*/ Let's write something that can pass as a function contract:
Quoted 10 lines
/*
* Create a new thread with name @name
* The thread executes @start_routine() with argument @arg.
* The thread will be created in a detached state if @mode is
*QEMU_THREAD_DETACHED, and in a jounable state if it's
*QEMU_THREAD_JOINABLE.
* On success, return true.
* On failure, set @errno, store an error through @errp and return
* false.
*/Quoted 5 lines
Thanks so much for amending! :)
Quoted 2 lines
Personally, I'd return negative errno instead of false, and dispense with setting errno.
Emm, I think I have replied this in last version, but due to several reasons I did not wait for your feedback and sent the v9. Sorry for that.. And I like to paste my two considerations here:
“- Actually only one caller needs the errno, that is the aboveqemu_signalfd_compat().Yes.
Quoted 1 line
- For the returning value, I remember there's once a email thread talking about it: returning a bool (and let the passed errp hold the error message) is to keep the consistency with glib.
GLib doesn't discourage return types other than boolean. It only asks that if you return boolean, then true should mean success and false should mean failure. See
https://developer.gnome.org/glib/stable/glib-Error-Reporting.html
under "Rules for use of GError", item "By convention, if you return a boolean value".
The discussion you remember was about a convention we used to enforce in QEMU, namely to avoid returning boolean success, and return void instead. That was basically a bad idea.
Quoted 1 line
So IMO I am wondering whether it is really needed to change the bool (true/false) to int (0/-errno), just for that sole function:
qemu_signalfd_compat()which needs the errno. Besides if we return -errno, for each caller we need add a local variable like “ret= qemu_thread_create()” to store the -errno.Well, you either assign the error code to errno just for that caller, or you return the error code just for that caller. I'd do the latter because I consider it slightly simpler. Compare
* On success, return true.
* On failure, set @errno, store an error through @errp and return
* false.Quoted 8 lines
to
* On success, return zero.
* On failure, store an error through @errp and return negative errno.where the second sentence describes just two instead of three actions.
[...]
Ok, decribing two actions than three is indeed simpler. But I still have one uncertain:
for those callers do not need the errno value, could we just check the return value
to see whether it is negative, but not cache the unused return value? I mean
Quoted 5 lines
In the caller:
{...
if (qemu_thread_create()< 0) {// do some cleanup} ...}
This is just fine when you handle all errors the same.
Quoted 8 lines
instead of
{ int ret;
...
ret =qemu_thread_create();
if (ret < 0) { //do some cleanup }...}
I'd object to this one unless the value of @ret gets used elsewhere.
Quoted 5 lines
As the first one can lessen quite a lot of codes. :)
Have a nice day, thanks
Fei
Re: [Qemu-devel] [PATCH for-4.0 v9 06/16] qemu_thread: Make qemu_thread_create() handle errors properly
Quoted 102 lines · 在 2019年1月9日,22:36,Markus Armbruster <[email protected]> 写道:
Quoted 6 lines · Fei Li
Quoted 6 lines · Markus Armbruster
Quoted 3 lines · fei
Quoted 3 lines · 在 2019年1月8日,01:18,Markus Armbruster <[email protected]> 写道:
Fei Li <[email protected]> writes:
[...]
Quoted 79 lines
Quoted 65 lines
Quoted 35 lines
Quoted 25 lines
Quoted 13 lines
util/qemu-thread-posix.c +1
-0@@ -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;util/qemu-thread-posix.c static void *qemu_thread_start(void *args) · line 507
Quoted 10 lines
util/qemu-thread-posix.c +4
-3@@ -500,9 +501,13 @@ static void *qemu_thread_start(void *args)return r; } -void qemu_thread_create (QemuThread *thread,const char *name, -void *(*start_routine)(void *), -void *arg,int mode) +/* +* Return a boolean: true/false to indicate whether it succeeds. +* If fails, propagate the error to Error **errp and set the errno. +*/ Let's write something that can pass as a function contract:
Quoted 10 lines
/*
* Create a new thread with name @name
* The thread executes @start_routine() with argument @arg.
* The thread will be created in a detached state if @mode is
*QEMU_THREAD_DETACHED, and in a jounable state if it's
*QEMU_THREAD_JOINABLE.
* On success, return true.
* On failure, set @errno, store an error through @errp and return
* false.
*/Quoted 5 lines
Thanks so much for amending! :)
Quoted 2 lines
Personally, I'd return negative errno instead of false, and dispense with setting errno.
Emm, I think I have replied this in last version, but due to several reasons I did not wait for your feedback and sent the v9. Sorry for that.. And I like to paste my two considerations here:
“- Actually only one caller needs the errno, that is the aboveqemu_signalfd_compat().Yes.
Quoted 1 line
- For the returning value, I remember there's once a email thread talking about it: returning a bool (and let the passed errp hold the error message) is to keep the consistency with glib.
GLib doesn't discourage return types other than boolean. It only asks that if you return boolean, then true should mean success and false should mean failure. See
https://developer.gnome.org/glib/stable/glib-Error-Reporting.html
under "Rules for use of GError", item "By convention, if you return a boolean value".
The discussion you remember was about a convention we used to enforce in QEMU, namely to avoid returning boolean success, and return void instead. That was basically a bad idea.
Quoted 1 line
So IMO I am wondering whether it is really needed to change the bool (true/false) to int (0/-errno), just for that sole function:
qemu_signalfd_compat()which needs the errno. Besides if we return -errno, for each caller we need add a local variable like “ret= qemu_thread_create()” to store the -errno.Well, you either assign the error code to errno just for that caller, or you return the error code just for that caller. I'd do the latter because I consider it slightly simpler. Compare
* On success, return true.
* On failure, set @errno, store an error through @errp and return
* false.Quoted 8 lines
to
* On success, return zero.
* On failure, store an error through @errp and return negative errno.where the second sentence describes just two instead of three actions.
[...]
Ok, decribing two actions than three is indeed simpler. But I still have one uncertain:
for those callers do not need the errno value, could we just check the return value
to see whether it is negative, but not cache the unused return value? I meanQuoted 5 lines
In the caller:
{...
if (qemu_thread_create() < 0) {// do some cleanup}...}
This is just fine when you handle all errors the same.
Quoted 2 lines
instead of
Quoted 8 lines
Quoted 6 lines
{ int ret;
...ret = qemu_thread_create(); if (ret < 0) { //do some cleanup }...}
I'd object to this one unless the value of @ret gets used elsewhere.
Ok, thanks for the review :)
Have a nice day
Fei
Quoted 6 lines
Quoted 6 lines
As the first one can lessen quite a lot of codes. :)
Have a nice day, thanks
Fei
PATCH v9 7/16 qemu_thread: supplement error handling for qemu_X_start_vcpu
In reply to Fei LiThe callers of qemu_init_vcpu() already passed the **errp to handle errors. In view of this, add a new Error parameter to qemu_init_vcpu() and all qemu_X_start_vcpu() functions called by qemu_init_vcpu() to propagate the error and let the further callers 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 | 3 +- cpus.c | 86 ++++++++++++++++++++++++----------------- 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, 117 insertions(+), 58 deletions(-)
accel/tcg/user-exec-stub.c +2 -1
@@ -10,8 +10,9 @@ void cpu_resume(CPUState *cpu) { } -void qemu_init_vcpu (CPUState *cpu) +bool qemu_init_vcpu (CPUState *cpu,Error **errp) { +return true; }/* User mode emulation does not support record/replay yet. */
cpus.c +51 -35
174 lines not on this page · raw message
include/qom/cpu.h +1 -1
@@ -1006,7 +1006,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
@@ -1125,7 +1125,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
@@ -5279,7 +5279,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
@@ -145,7 +145,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
@@ -9711,7 +9711,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
@@ -305,7 +305,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
PATCH v9 8/16 qemu_thread: supplement error handling for qmp_dump_guest_memory
In reply to Fei LiUtilize the existed errp to propagate the error instead of the temporary &error_abort.
--- dump.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
dump.c +4 -3
@@ -2020,9 +2020,10 @@ void qmp_dump_guest_memory(bool paging, const char *file,if (detach_p) {/* detached dump */ s->detached = true; -/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (&s->dump_thread,"dump_thread" , dump_thread, - s,QEMU_THREAD_DETACHED , &error_abort); +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);
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH for-4.0 v9 08/16] qemu_thread: supplement error handling for qmp_dump_guest_memory
Quoted 15 lines · Fei Li
Utilize the existed errp to propagate the error instead of the temporary
&error_abort.Cc Markus Armbruster <[email protected]>Cc Marc-André Lureau <[email protected]>Signed-off-by Fei Li <[email protected]>--- dump.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)dump.c +0
-0
dump.c void qmp_dump_guest_memory(bool paging, const char *file, · line 2026
Quoted 10 lines
dump.c +4
-3@@ -2020,9 +2020,10 @@ void qmp_dump_guest_memory(bool paging, const char *file,if (detach_p) {/* detached dump */ s->detached = true; -/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (&s->dump_thread,"dump_thread" , dump_thread, - s,QEMU_THREAD_DETACHED , &error_abort); +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 */ + }
I don't think keeping the conditional "just in case" is worthwhile. Plain
qemu_thread_create(&s->dump_thread, "dump_thread", dump_thread,
s, QEMU_THREAD_DETACHED, errp);should do fine.
Quoted 3 lines
dump.c +0
-0}else {/* sync dump */ dump_process (s, errp);
Re: [Qemu-devel] [PATCH for-4.0 v9 08/16] qemu_thread: supplement error handling for qmp_dump_guest_memory
Quoted 35 lines · 在 2019年1月8日,01:21,Markus Armbruster <[email protected]> 写道:
Quoted 15 lines · Fei Li
Utilize the existed errp to propagate the error instead of the temporary
&error_abort.Cc Markus Armbruster <[email protected]>Cc Marc-André Lureau <[email protected]>Signed-off-by Fei Li <[email protected]>---
dump.c| 7 ++++---1 file changed, 4 insertions(+), 3 deletions(-)dump.c +0
-0dump.c void qmp_dump_guest_memory(bool paging, const char *file, · line 2026
Quoted 10 lines
dump.c +4
-3@@ -2020,9 +2020,10 @@ void qmp_dump_guest_memory(bool paging, const char *file,if (detach_p) {/* detached dump */ s->detached = true; -/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (&s->dump_thread,"dump_thread" , dump_thread, - s,QEMU_THREAD_DETACHED , &error_abort); +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 */ + }I don't think keeping the conditional "just in case" is worthwhile. Plain
Quoted 4 lines
qemu_thread_create(&s->dump_thread, "dump_thread", dump_thread, s, QEMU_THREAD_DETACHED, errp);should do fine.
Ok, will simplify this in next version.
Have a nice day, thanks
Fei
Quoted 4 lines
Quoted 4 lines
dump.c +0
-0}else {/* sync dump */ dump_process (s, errp);
PATCH v9 9/16 qemu_thread: supplement error handling for pci_edu_realize
In reply to Fei LiUtilize the existed errp to propagate the error instead of the temporary &error_abort.
--- hw/misc/edu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
hw/misc/edu.c +4 -3
@@ -356,9 +356,10 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp)qemu_mutex_init (&edu->thr_mutex);qemu_cond_init (&edu->thr_cond); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&edu->thread,"edu" , edu_fact_thread, - edu,QEMU_THREAD_JOINABLE , &error_abort); +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);
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
Quoted 15 lines · Fei Li
Utilize the existed errp to propagate the error instead of the temporary
&error_abort.Cc Markus Armbruster <[email protected]>Cc Jiri Slaby <[email protected]>Signed-off-by Fei Li <[email protected]>--- hw/misc/edu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)hw/misc/edu.c +0
-0
hw/misc/edu.c static void pci_edu_realize(PCIDevice *pdev, Error **errp) · line 361
Quoted 9 lines
hw/misc/edu.c +3
-3@@ -356,9 +356,10 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp)qemu_mutex_init (&edu->thr_mutex);qemu_cond_init (&edu->thr_cond); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&edu->thread,"edu" , edu_fact_thread, - edu,QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&edu->thread,"edu" , edu_fact_thread, + edu,QEMU_THREAD_JOINABLE , errp)) { +return ;
You need to clean up everything that got initialized so far. You might want to call qemu_thread_create() earlier so you have less to clean up.
hw/misc/edu.c static void pci_edu_realize(PCIDevice *pdev, Error **errp) · line 365
Quoted 4 lines
hw/misc/edu.c +1
-0+ }memory_region_init_io (&edu->mmio,OBJECT (edu), &edu_mmio_ops, edu,"edu-mmio" ,1 * MiB);
pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &edu->mmio);
}
static void pci_edu_uninit(PCIDevice *pdev)
{
EduState *edu = EDU(pdev); qemu_mutex_lock(&edu->thr_mutex);
edu->stopping = true;
qemu_mutex_unlock(&edu->thr_mutex);
qemu_cond_signal(&edu->thr_cond);
qemu_thread_join(&edu->thread);
qemu_cond_destroy(&edu->thr_cond);
qemu_mutex_destroy(&edu->thr_mutex);
timer_del(&edu->dma_timer);}
Preexisting: pci_edu_uninit() neglects to call msi_uninit(). Jiri?
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
Quoted 14 lines · Markus Armbruster
static void pci_edu_uninit(PCIDevice *pdev) { EduState *edu = EDU(pdev);qemu_mutex_lock(&edu->thr_mutex); edu->stopping = true; qemu_mutex_unlock(&edu->thr_mutex); qemu_cond_signal(&edu->thr_cond); qemu_thread_join(&edu->thread); qemu_cond_destroy(&edu->thr_cond); qemu_mutex_destroy(&edu->thr_mutex); timer_del(&edu->dma_timer);
Quoted 3 lines
}
Preexisting:
pci_edu_uninit()neglects to callmsi_uninit(). Jiri?\
I don't know, the MSI support was added in:
commit eabb5782f70b4a10975b24ccd7129929a05ac932
Author: Peter Xu <[email protected]> Date: Wed Sep 28 21:03:39 2016 +0800
hw/misc/edu: support MSI interrupt
Hence CCing Peter.
thanks,
Signature · 2 lines
js suse labs
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
Quoted 19 lines · Jiri Slaby
Quoted 14 lines · Markus Armbruster
static void pci_edu_uninit(PCIDevice *pdev) { EduState *edu = EDU(pdev);qemu_mutex_lock(&edu->thr_mutex); edu->stopping = true; qemu_mutex_unlock(&edu->thr_mutex); qemu_cond_signal(&edu->thr_cond); qemu_thread_join(&edu->thread); qemu_cond_destroy(&edu->thr_cond); qemu_mutex_destroy(&edu->thr_mutex); timer_del(&edu->dma_timer);Quoted 3 lines
}
Preexisting:
pci_edu_uninit()neglects to callmsi_uninit(). Jiri?\
Quoted 8 lines
I don't know, the MSI support was added in:
commiteabb5782f70b4a10975b24ccd7129929a05ac932Author: Peter Xu <[email protected]> Date: Wed Sep 28 21:03:39 2016 +0800hw/misc/edu: support MSI interrupt
Hence CCing Peter.
Hi, Jiri, Markus, Fei,
IMHO msi_uninit() is optional since it only operates on the config space of the device to remove the capability or fix up the flags without really doing any real destruction of objects so nothing will be leaked (unlike msix_uninit, which should be required). But I do agree that calling msi_uninit() could be even nicer here.
Anyone would like to post a patch? Or should I?
Thanks,
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
Quoted 27 lines · Peter Xu
Quoted 26 lines · Jiri Slaby
Quoted 14 lines · Markus Armbruster
static void pci_edu_uninit(PCIDevice *pdev) { EduState *edu = EDU(pdev);qemu_mutex_lock(&edu->thr_mutex); edu->stopping = true; qemu_mutex_unlock(&edu->thr_mutex); qemu_cond_signal(&edu->thr_cond); qemu_thread_join(&edu->thread); qemu_cond_destroy(&edu->thr_cond); qemu_mutex_destroy(&edu->thr_mutex); timer_del(&edu->dma_timer);Quoted 3 lines
}
Preexisting:
pci_edu_uninit()neglects to callmsi_uninit(). Jiri?\I don't know, the MSI support was added in:
commiteabb5782f70b4a10975b24ccd7129929a05ac932Author: Peter Xu <[email protected]> Date: Wed Sep 28 21:03:39 2016 +0800hw/misc/edu: support MSI interrupt
Quoted 8 lines
Quoted 1 line
Hence CCing Peter.
Hi, Jiri, Markus, Fei,
IMHO
msi_uninit()is optional since it only operates on the config space of the device to remove the capability or fix up the flags without really doing any real destruction of objects so nothing will be leaked (unlikemsix_uninit, which should be required).
Michael, Marcel, is neglecting to call msi_uninit() okay, a harmless bug, or a harmful bug?
Quoted 4 lines
But I do
agree that callingmsi_uninit()could be even nicer here.Anyone would like to post a patch? Or should I?
Please coordinate fixing this with Fei Li.
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
Quoted 29 lines · Markus Armbruster
Quoted 27 lines · Peter Xu
Quoted 26 lines · Jiri Slaby
Quoted 16 lines · Markus Armbruster
static void pci_edu_uninit(PCIDevice *pdev) { EduState *edu = EDU(pdev); qemu_mutex_lock(&edu->thr_mutex); edu->stopping = true; qemu_mutex_unlock(&edu->thr_mutex); qemu_cond_signal(&edu->thr_cond); qemu_thread_join(&edu->thread); qemu_cond_destroy(&edu->thr_cond); qemu_mutex_destroy(&edu->thr_mutex); timer_del(&edu->dma_timer); }Quoted 1 line
Preexisting:
pci_edu_uninit()neglects to callmsi_uninit(). Jiri?\I don't know, the MSI support was added in:
commiteabb5782f70b4a10975b24ccd7129929a05ac932Author: Peter Xu <[email protected]> Date: Wed Sep 28 21:03:39 2016 +0800hw/misc/edu: support MSI interrupt
Hence CCing Peter.
Quoted 8 lines
Quoted 6 lines
Hi, Jiri, Markus, Fei,
IMHO
msi_uninit()is optional since it only operates on the config space of the device to remove the capability or fix up the flags without really doing any real destruction of objects so nothing will be leaked (unlikemsix_uninit, which should be required).Michael, Marcel, is neglecting to call
msi_uninit()okay, a harmless bug, or a harmful bug?
Kindly ping. :)
If corresponding change is needed, I'd like to do the update in the next version.
Quoted 5 lines
Quoted 4 lines
But I do
agree that callingmsi_uninit()could be even nicer here.Anyone would like to post a patch? Or should I?
Please coordinate fixing this with Fei Li.
Have a nice day, thanks all
Fei
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
Quoted 37 lines · Fei Li
Quoted 35 lines · Markus Armbruster
Quoted 33 lines · Peter Xu
Quoted 18 lines · Jiri Slaby
Quoted 16 lines · Markus Armbruster
static void pci_edu_uninit(PCIDevice *pdev) { EduState *edu = EDU(pdev); qemu_mutex_lock(&edu->thr_mutex); edu->stopping = true; qemu_mutex_unlock(&edu->thr_mutex); qemu_cond_signal(&edu->thr_cond); qemu_thread_join(&edu->thread); qemu_cond_destroy(&edu->thr_cond); qemu_mutex_destroy(&edu->thr_mutex); timer_del(&edu->dma_timer); }Quoted 1 line
Preexisting:
pci_edu_uninit()neglects to callmsi_uninit(). Jiri?\Quoted 8 lines
I don't know, the MSI support was added in:
commiteabb5782f70b4a10975b24ccd7129929a05ac932Author: Peter Xu <[email protected]> Date: Wed Sep 28 21:03:39 2016 +0800hw/misc/edu: support MSI interrupt
Hence CCing Peter.
Hi, Jiri, Markus, Fei,
IMHO
msi_uninit()is optional since it only operates on the config space of the device to remove the capability or fix up the flags without really doing any real destruction of objects so nothing will be leaked (unlikemsix_uninit, which should be required).
Quoted 7 lines
Quoted 2 lines
Michael, Marcel, is neglecting to call
msi_uninit()okay, a harmless bug, or a harmful bug?Kindly ping. :)
If corresponding change is needed, I'd like to do the update in the next version.
Fei,
If you're going to post the edu patch, please post it as a standalone patch. More patches mean harder that the series could be accepted quickly. So it would be good to split patches sometimes especially if they are irrelevant.
Regards,
Signature · 1 line
Peter Xu
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
Quoted 43 lines · Peter Xu
Quoted 36 lines · Fei Li
Quoted 35 lines · Markus Armbruster
Quoted 33 lines · Peter Xu
Quoted 18 lines · Jiri Slaby
Quoted 16 lines · Markus Armbruster
static void pci_edu_uninit(PCIDevice *pdev) { EduState *edu = EDU(pdev); qemu_mutex_lock(&edu->thr_mutex); edu->stopping = true; qemu_mutex_unlock(&edu->thr_mutex); qemu_cond_signal(&edu->thr_cond); qemu_thread_join(&edu->thread); qemu_cond_destroy(&edu->thr_cond); qemu_mutex_destroy(&edu->thr_mutex); timer_del(&edu->dma_timer); }Quoted 1 line
Preexisting:
pci_edu_uninit()neglects to callmsi_uninit(). Jiri?\Quoted 8 lines
I don't know, the MSI support was added in:
commiteabb5782f70b4a10975b24ccd7129929a05ac932Author: Peter Xu <[email protected]> Date: Wed Sep 28 21:03:39 2016 +0800hw/misc/edu: support MSI interrupt
Hence CCing Peter.
Hi, Jiri, Markus, Fei,
IMHO
msi_uninit()is optional since it only operates on the config space of the device to remove the capability or fix up the flags without really doing any real destruction of objects so nothing will be leaked (unlikemsix_uninit, which should be required).Quoted 6 lines
Quoted 2 lines
Michael, Marcel, is neglecting to call
msi_uninit()okay, a harmless bug, or a harmful bug?Kindly ping. :)
If corresponding change is needed, I'd like to do the update in the next version.
Quoted 9 lines
Fei,
If you're going to post the edu patch, please post it as a standalone patch. More patches mean harder that the series could be accepted quickly. So it would be good to split patches sometimes especially if they are irrelevant.
Regards,
Ok, thanks for this helpful suggestion. Will send this patch alone in the next version. :)
Have a nice day
Fei
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
In reply to Markus ArmbrusterQuoted 18 lines · Markus Armbruster
Quoted 16 lines · Fei Li
Utilize the existed errp to propagate the error instead of the temporary
&error_abort.Cc Markus Armbruster <[email protected]>Cc Jiri Slaby <[email protected]>Signed-off-by Fei Li <[email protected]>--- hw/misc/edu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)hw/misc/edu.c +0
-0@@ -356,9 +356,10 @@ static void pci_edu_realize(PCIDevice *pdev, Error **errp)
Quoted 10 lines
hw/misc/edu.c static void pci_edu_realize(PCIDevice *pdev, Error **errp) · line 361
Quoted 8 lines
hw/misc/edu.c +3
-3qemu_mutex_init (&edu->thr_mutex);qemu_cond_init (&edu->thr_cond); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&edu->thread,"edu" , edu_fact_thread, - edu,QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&edu->thread,"edu" , edu_fact_thread, + edu,QEMU_THREAD_JOINABLE , errp)) { +return ;You need to clean up everything that got initialized so far. You might want to call
qemu_thread_create()earlier so you have less to clean up.
Just to make sure about how to do the cleanup. I notice that in device_set_realized(), the current code does not call "dc->unrealize(dev, NULL);" when dc->realize() fails.
if (dc->realize) {
dc->realize(dev, &local_err);
}
if (local_err != NULL) {
goto fail;
}
Is this on purpose? (Maybe due to some devices' realize() do their own cleanup
when fails? Sorry for the unsure, it is such a common function that I did not
check all. :( ) Or else, I prefer to do the cleanup in a unified manner, e.g. call "dc->unrealize(dev, NULL);" which is the pci_qdev_unrealize() for pci devices.
Have a nice day
Fei
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
Quoted 7 lines · Fei Li
Just to make sure about how to do the cleanup. I notice that in
device_set_realized(), the current code does not call "dc->unrealize(dev, NULL);" whendc->realize()fails.if (
dc->realize) {
dc->realize(dev, &local_err);
}
Quoted 7 lines
if (
local_err!= NULL) {
goto fail;
}Is this on purpose? (Maybe due to some devices'
realize()do their own cleanup
when fails? Sorry for the unsure, it is such a common function that I did not
check all. :( ) Or else, I prefer to do the cleanup in a unified manner, e.g. call "dc->unrealize(dev, NULL);" which is thepci_qdev_unrealize()for pci devices.
Yes, this is on purpose.
When a realize() method fails, it must revert everything it has done so far. Results in sane "either succeed completely, or fail and do nothing" semantics.
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
Quoted 4 lines · Markus Armbruster
Quoted 2 lines · Fei Li
Just to make sure about how to do the cleanup. I notice that in
device_set_realized(), the current code does not call "dc->unrealize(dev, NULL);" whendc->realize()fails.
Sorry that I am still uncertain.. I guess the code below I pasted was misleading, actually I want to stress the *dc->unrealize() is not called when dc->realize() fails* and the incomplete below "goto fail" does not include the dc->unrealize(),
but instead the dc->unrealize() is included in later child_realize_fail: & post_realize_fail:.
Emm, IMHO, I think when dc->realize() fails, the dc->unrealize() is either should be called in the common function: device_set_realized() in a unified way, that is
if (local_err != NULL) {
+ if (dc->unrealize) {
+ dc->unrealize(dev, local_err);
+ }
goto fail;
}
or do the unrealize() locally for each device earlier when dc->realize() fails. But I checked several dc->realize() function, they did not call unrealize() when fails. Besides, it may mean verbose code if unrealize() locally. Thus I think the above way is the right way to do the cleanup when realize() fails.
Quoted 9 lines
Quoted 9 lines
if (
dc->realize) {
dc->realize(dev, &local_err);
}if (
local_err!= NULL) {
goto fail;
}
Quoted 8 lines
Quoted 3 lines
Is this on purpose? (Maybe due to some devices'
realize()do their own cleanup
when fails? Sorry for the unsure, it is such a common function that I did not
check all. :( ) Or else, I prefer to do the cleanup in a unified manner, e.g. call "dc->unrealize(dev, NULL);" which is thepci_qdev_unrealize()for pci devices.Yes, this is on purpose.
When a
realize()method fails, it must revert everything it has done so far. Results in sane "either succeed completely, or fail and do nothing" semantics.
Have a nice day, thanks
Fei
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
Quoted 26 lines · Fei Li
Quoted 4 lines · Markus Armbruster
Quoted 2 lines · Fei Li
Just to make sure about how to do the cleanup. I notice that in
device_set_realized(), the current code does not call "dc->unrealize(dev, NULL);" whendc->realize()fails.Sorry that I am still uncertain.. I guess the code below I pasted was misleading,
actually I want to stress the*dc->unrealize()is not called whendc->realize()fails*
and the incomplete below "goto fail" does not include thedc->unrealize(), but instead thedc->unrealize()is included in laterchild_realize_fail: &post_realize_fail:.Emm, IMHO, I think when
dc->realize()fails, thedc->unrealize()is either should be
called in the common function:device_set_realized()in a unified way, that isif (
local_err!= NULL) {
+ if (dc->unrealize) {
+dc->unrealize(dev, local_err);
+ }
goto fail;
}
Quoted 7 lines
or do the
unrealize()locally for each device earlier whendc->realize()fails.But I checked several
dc->realize()function, they did not callunrealize()when fails. Besides, it may mean verbose code ifunrealize()locally. Thus I think the above way is the right way to do the cleanup whenrealize()fails.
The realize() method is specified to either succeed completely or fail completely, i.e. fail and do nothing. The "either succeed completely or fail completely" aspect of the specification is sane and perfectly ordinary.
How a concrete implementation accomplishes "fail completely" is up to the implementation.
An implementation may choose to structure its FOO_realize() and FOO_unrealize() in a way that lets FOO_realize() call FOO_unrealize() to clean up on failure.
An implementation may also choose to clean up differently.
This freedom of choice is by design.
Changing the specification now would involve auditing and updating all realize() and unrealize() methods. Not going to happen without an extremely compelling reason.
Quoted 21 lines
Quoted 9 lines
Quoted 9 lines
if (
dc->realize) {
dc->realize(dev, &local_err);
}if (
local_err!= NULL) {
goto fail;
}Quoted 8 lines
Quoted 3 lines
Is this on purpose? (Maybe due to some devices'
realize()do their own cleanup
when fails? Sorry for the unsure, it is such a common function that I did not
check all. :( ) Or else, I prefer to do the cleanup in a unified manner, e.g. call "dc->unrealize(dev, NULL);" which is thepci_qdev_unrealize()for pci devices.Yes, this is on purpose.
When a
realize()method fails, it must revert everything it has done so far. Results in sane "either succeed completely, or fail and do nothing" semantics.Have a nice day, thanks
Fei
Re: [Qemu-devel] [PATCH for-4.0 v9 09/16] qemu_thread: supplement error handling for pci_edu_realize
Quoted 47 lines · Markus Armbruster
Quoted 26 lines · Fei Li
Quoted 4 lines · Markus Armbruster
Quoted 2 lines · Fei Li
Just to make sure about how to do the cleanup. I notice that in
device_set_realized(), the current code does not call "dc->unrealize(dev, NULL);" whendc->realize()fails.Sorry that I am still uncertain.. I guess the code below I pasted was misleading,
actually I want to stress the*dc->unrealize()is not called whendc->realize()fails*
and the incomplete below "goto fail" does not include thedc->unrealize(), but instead thedc->unrealize()is included in laterchild_realize_fail: &post_realize_fail:.Emm, IMHO, I think when
dc->realize()fails, thedc->unrealize()is either should be
called in the common function:device_set_realized()in a unified way, that isif (
local_err!= NULL) {
+ if (dc->unrealize) {
+dc->unrealize(dev, local_err);
+ }
goto fail;
}Quoted 7 lines
or do the
unrealize()locally for each device earlier whendc->realize()fails.But I checked several
dc->realize()function, they did not callunrealize()when fails. Besides, it may mean verbose code ifunrealize()locally. Thus I think the above way is the right way to do the cleanup whenrealize()fails.The
realize()method is specified to either succeed completely or fail completely, i.e. fail and do nothing. The "either succeed completely or fail completely" aspect of the specification is sane and perfectly ordinary.How a concrete implementation accomplishes "fail completely" is up to the implementation.
An implementation may choose to structure its
FOO_realize()andFOO_unrealize()in a way that letsFOO_realize()callFOO_unrealize()to clean up on failure.
Quoted 7 lines
An implementation may also choose to clean up differently.
This freedom of choice is by design.
Changing the specification now would involve auditing and updating all
realize()andunrealize()methods. Not going to happen without an extremely compelling reason.
Ok, now I see. Thanks for the detail explanation. :)
Will add the cleanup in the next version.
Have a nice day
Fei
Quoted 19 lines
Quoted 19 lines
Quoted 8 lines
Quoted 8 lines
if (dc->realize) { dc->realize(dev, &local_err); } if (local_err != NULL) { goto fail; }Quoted 8 lines
Quoted 3 lines
Is this on purpose? (Maybe due to some devices'
realize()do their own cleanup
when fails? Sorry for the unsure, it is such a common function that I did not
check all. :( ) Or else, I prefer to do the cleanup in a unified manner, e.g. call "dc->unrealize(dev, NULL);" which is thepci_qdev_unrealize()for pci devices.Yes, this is on purpose.
When a
realize()method fails, it must revert everything it has done so far. Results in sane "either succeed completely, or fail and do nothing" semantics.Have a nice day, thanks
Fei
PATCH v9 10/16 qemu_thread: supplement error handling for h_resize_hpt_prepare
In reply to Fei LiAdd a local_err to hold the error, and return the corresponding error code to replace the temporary &error_abort.
--- hw/ppc/spapr_hcall.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
hw/ppc/spapr_hcall.c +8 -4
@@ -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,10 +539,13 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, pending->shift = shift; pending->ret =H_HARDWARE ; -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&pending->thread,"sPAPR HPT prepare" , - hpt_prepare_thread, pending, -QEMU_THREAD_DETACHED , &error_abort); +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;
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH for-4.0 v9 10/16] qemu_thread: supplement error handling for h_resize_hpt_prepare
Quoted 6 lines · Fei Li
Add a
local_errto hold the error, and return the corresponding error code to replace the temporary&error_abort.Cc Markus Armbruster <[email protected]>Cc David Gibson <[email protected]>Signed-off-by Fei Li <[email protected]>
This looks like a good change, but it no longer applies due to a change in the qemu_thread_create() signature.
Quoted 20 lines
--- hw/ppc/spapr_hcall.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)hw/ppc/spapr_hcall.c +1
-0@@ -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,10 +539,13 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, pending->shift = shift; pending->ret =H_HARDWARE ;
hw/ppc/spapr_hcall.c static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, · line 547
Quoted 10 lines
hw/ppc/spapr_hcall.c +6
-4-/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&pending->thread,"sPAPR HPT prepare" , - hpt_prepare_thread, pending, -QEMU_THREAD_DETACHED , &error_abort); +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 ;
I also think H_HARDWARE would be a better choice here. Although the failure is due to a resource constraint, it's not because the guest asked for too much, just because the host is in dire straits. From the guest's point of view it's basically a hardware failure.
Quoted 4 lines
hw/ppc/spapr_hcall.c +1
-0+ } spapr->pending_hpt = pending;
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH for-4.0 v9 10/16] qemu_thread: supplement error handling for h_resize_hpt_prepare
Quoted 9 lines · David Gibson
Quoted 6 lines · Fei Li
Add a
local_errto hold the error, and return the corresponding error code to replace the temporary&error_abort.Cc Markus Armbruster <[email protected]>Cc David Gibson <[email protected]>Signed-off-by Fei Li <[email protected]>This looks like a good change, but it no longer applies due to a change in the
qemu_thread_create()signature.
Sorry that I am not sure whether I understand. Do you mean using &error_abort is more suitable for this handling, rather than report the &local_err & return a failure reason?
Quoted 21 lines
Quoted 21 lines
--- hw/ppc/spapr_hcall.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)hw/ppc/spapr_hcall.c +1
-0@@ -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,10 +539,13 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, pending->shift = shift; pending->ret =H_HARDWARE ;
Quoted 14 lines
hw/ppc/spapr_hcall.c static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, · line 547
Quoted 10 lines
hw/ppc/spapr_hcall.c +6
-4-/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&pending->thread,"sPAPR HPT prepare" , - hpt_prepare_thread, pending, -QEMU_THREAD_DETACHED , &error_abort); +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 ;I also think
H_HARDWAREwould be a better choice here. Although the failure is due to a resource constraint, it's not because the guest asked for too much, just because the host is in dire straits. From the guest's point of view it's basically a hardware failure.
Ok, thanks. Will use H_HARDWARE instead.
Have a nice day, thanks for the review. :)
Fei
Quoted 5 lines
Quoted 5 lines
hw/ppc/spapr_hcall.c +1
-0+ } spapr->pending_hpt = pending;
Re: [Qemu-devel] [PATCH for-4.0 v9 10/16] qemu_thread: supplement error handling for h_resize_hpt_prepare
Quoted 6 lines · 李菲
Quoted 4 lines · David Gibson
Quoted 3 lines · Fei Li
Add a
local_errto hold the error, and return the corresponding error code to replace the temporary&error_abort.
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
Cc Markus Armbruster <[email protected]>Cc David Gibson <[email protected]>Signed-off-by Fei Li <[email protected]>This looks like a good change, but it no longer applies due to a change in the
qemu_thread_create()signature.Sorry that I am not sure whether I understand. Do you mean using
&error_abortis more suitable for this handling, rather than report the&local_err& return a failure reason?
No, I just mean that context has been altered by a global change and the patch will need to be fixed up to cope with that.
Quoted 42 lines
Quoted 25 lines
Quoted 25 lines
--- hw/ppc/spapr_hcall.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)hw/ppc/spapr_hcall.c +3
-4@@ -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,10 +539,13 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, pending->shift = shift; pending->ret =H_HARDWARE ; -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&pending->thread,"sPAPR HPT prepare" , - hpt_prepare_thread, pending, -QEMU_THREAD_DETACHED , &error_abort); + if (!qemu_thread_create(&pending->thread, "sPAPR HPT prepare", + hpt_prepare_thread, pending,Quoted 8 lines
hw/ppc/spapr_hcall.c static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, · line 547
Quoted 4 lines
hw/ppc/spapr_hcall.c +4
-0+ QEMU_THREAD_DETACHED, &local_err)) { +error_reportf_err (local_err,"failed to create hpt_prepare_thread: " ); +g_free (pending); +return H_RESOURCE ;I also think
H_HARDWAREwould be a better choice here. Although the failure is due to a resource constraint, it's not because the guest asked for too much, just because the host is in dire straits. From the guest's point of view it's basically a hardware failure.Ok, thanks. Will use
H_HARDWAREinstead.Have a nice day, thanks for the review. :)
FeiQuoted 3 lines
Quoted 3 lines
hw/ppc/spapr_hcall.c +1
-0+ } spapr->pending_hpt = pending;
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH for-4.0 v9 10/16] qemu_thread: supplement error handling for h_resize_hpt_prepare
Quoted 9 lines · David Gibson
Quoted 8 lines · 李菲
Quoted 7 lines · David Gibson
Quoted 6 lines · Fei Li
Add a
local_errto hold the error, and return the corresponding error code to replace the temporary&error_abort.Cc Markus Armbruster <[email protected]>Cc David Gibson <[email protected]>Signed-off-by Fei Li <[email protected]>
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
This looks like a good change, but it no longer applies due to a change in the
qemu_thread_create()signature.Sorry that I am not sure whether I understand. Do you mean using
&error_abortis more suitable for this handling, rather than report the&local_err& return a failure reason?No, I just mean that context has been altered by a global change and the patch will need to be fixed up to cope with that.
Just to be clearer: does the "global change" mean the "[patch 06/16] qemu_thread: Make qemu_thread_create() handle errors properly", or another patch not in this patch series?
If it means the [patch 06/16], I want to explain more: the 06/16 handles all qemu_thread_create() by passing &error_abort as the parameter, and the following patches are to improve on the &error_abort for callers who can handle more properly. E.g. if qemu_thread_create() fails in h_resize_hpt_prepare(), I think reporting the &local_err & returning the failure reason is more proper than just abort() inside qemu_thread_create() when calls error_setg_errno().
In other words, this patch is actually written to apply to patch 06. And I have no clue where it needs to be fixed up. Please correct me if I understand wrong.
Have a nice day, thanks :)
Fei
Quoted 39 lines
Quoted 39 lines
Quoted 25 lines
Quoted 25 lines
--- hw/ppc/spapr_hcall.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)hw/ppc/spapr_hcall.c +3
-4@@ -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,10 +539,13 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, pending->shift = shift; pending->ret =H_HARDWARE ; -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&pending->thread,"sPAPR HPT prepare" , - hpt_prepare_thread, pending, -QEMU_THREAD_DETACHED , &error_abort); + if (!qemu_thread_create(&pending->thread, "sPAPR HPT prepare", + hpt_prepare_thread, pending,Quoted 8 lines
hw/ppc/spapr_hcall.c static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, · line 547
Quoted 4 lines
hw/ppc/spapr_hcall.c +4
-0+ QEMU_THREAD_DETACHED, &local_err)) { +error_reportf_err (local_err,"failed to create hpt_prepare_thread: " ); +g_free (pending); +return H_RESOURCE ;I also think
H_HARDWAREwould be a better choice here. Although the failure is due to a resource constraint, it's not because the guest asked for too much, just because the host is in dire straits. From the guest's point of view it's basically a hardware failure.Ok, thanks. Will use
H_HARDWAREinstead.Have a nice day, thanks for the review. :)
FeiQuoted 2 lines
Quoted 2 lines
hw/ppc/spapr_hcall.c +1
-0+ } spapr->pending_hpt = pending;
David Gibson
Acked-byRe: [Qemu-devel] [PATCH for-4.0 v9 10/16] qemu_thread: supplement error handling for h_resize_hpt_prepare
Quoted 32 lines · Fei Li
Quoted 9 lines · David Gibson
Quoted 8 lines · 李菲
Quoted 7 lines · David Gibson
Quoted 6 lines · Fei Li
Add a
local_errto hold the error, and return the corresponding error code to replace the temporary&error_abort.Cc Markus Armbruster <[email protected]>Cc David Gibson <[email protected]>Signed-off-by Fei Li <[email protected]>Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
This looks like a good change, but it no longer applies due to a change in the
qemu_thread_create()signature.Sorry that I am not sure whether I understand. Do you mean using
&error_abortis more suitable for this handling, rather than report the&local_err& return a failure reason?No, I just mean that context has been altered by a global change and the patch will need to be fixed up to cope with that.
Just to be clearer: does the "global change" mean the "[patch 06/16]
qemu_thread: Makeqemu_thread_create()handle errors properly", or another patch not in this patch series?If it means the [patch 06/16], I want to explain more: the 06/16 handles all
qemu_thread_create()by passing&error_abortas the parameter, and the following patches are to improve on the&error_abortfor callers who can handle more properly. E.g. ifqemu_thread_create()fails inh_resize_hpt_prepare(),
I think reporting the&local_err& returning the failure reason is more proper
than justabort()insideqemu_thread_create()when callserror_setg_errno().
Quoted 7 lines
In other words, this patch is actually written to apply to patch 06. And I have
no clue where it needs to be fixed up. Please correct me if I understand wrong.Have a nice day, thanks :)
Ah, sorry. Since I was only CCed on this patch, not the rest of the series, I assumed it was independent and didn't think to check the earlier patches of the series.
So, yes, I think the global change I'm referring to is 6/16, which I didn't have, so that explains the problem.
In that case it's probably best if this goes in via the same tree the rest of the series is going to. So, with the H_HARDWARE change made:
Quoted 43 lines
Fei
Quoted 39 lines
Quoted 39 lines
Quoted 25 lines
Quoted 25 lines
--- hw/ppc/spapr_hcall.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)hw/ppc/spapr_hcall.c +3
-4@@ -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,10 +539,13 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, pending->shift = shift; pending->ret =H_HARDWARE ; -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&pending->thread,"sPAPR HPT prepare" , - hpt_prepare_thread, pending, -QEMU_THREAD_DETACHED , &error_abort); + if (!qemu_thread_create(&pending->thread, "sPAPR HPT prepare", + hpt_prepare_thread, pending,Quoted 8 lines
hw/ppc/spapr_hcall.c static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, · line 547
Quoted 4 lines
hw/ppc/spapr_hcall.c +4
-0+ QEMU_THREAD_DETACHED, &local_err)) { +error_reportf_err (local_err,"failed to create hpt_prepare_thread: " ); +g_free (pending); +return H_RESOURCE ;I also think
H_HARDWAREwould be a better choice here. Although the failure is due to a resource constraint, it's not because the guest asked for too much, just because the host is in dire straits. From the guest's point of view it's basically a hardware failure.Ok, thanks. Will use
H_HARDWAREinstead.Have a nice day, thanks for the review. :)
FeiQuoted 2 lines
Quoted 2 lines
hw/ppc/spapr_hcall.c +1
-0+ } spapr->pending_hpt = pending;
Signature · 4 lines
David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
Re: [Qemu-devel] [PATCH for-4.0 v9 10/16] qemu_thread: supplement error handling for h_resize_hpt_prepare
Quoted 37 lines · David Gibson
Quoted 36 lines · Fei Li
Quoted 9 lines · David Gibson
Quoted 8 lines · 李菲
Quoted 7 lines · David Gibson
Quoted 6 lines · Fei Li
Add a
local_errto hold the error, and return the corresponding error code to replace the temporary&error_abort.Cc Markus Armbruster <[email protected]>Cc David Gibson <[email protected]>Signed-off-by Fei Li <[email protected]>Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
This looks like a good change, but it no longer applies due to a change in the
qemu_thread_create()signature.Sorry that I am not sure whether I understand. Do you mean using
&error_abortis more suitable for this handling, rather than report the&local_err& return a failure reason?No, I just mean that context has been altered by a global change and the patch will need to be fixed up to cope with that.
Just to be clearer: does the "global change" mean the "[patch 06/16]
qemu_thread: Makeqemu_thread_create()handle errors properly", or another patch not in this patch series?If it means the [patch 06/16], I want to explain more: the 06/16 handles all
qemu_thread_create()by passing&error_abortas the parameter, and the following patches are to improve on the&error_abortfor callers who can handle more properly. E.g. ifqemu_thread_create()fails inh_resize_hpt_prepare(),
I think reporting the&local_err& returning the failure reason is more proper
than justabort()insideqemu_thread_create()when callserror_setg_errno().In other words, this patch is actually written to apply to patch 06. And I have
no clue where it needs to be fixed up. Please correct me if I understand wrong.
Quoted 4 lines
Quoted 1 line
Have a nice day, thanks :)
Ah, sorry. Since I was only CCed on this patch, not the rest of the series, I assumed it was independent and didn't think to check the earlier patches of the series.
A good reminder, CCing all during the review stage seems more reasonable. :)
Quoted 8 lines
So, yes, I think the global change I'm referring to is 6/16, which I didn't have, so that explains the problem.
In that case it's probably best if this goes in via the same tree the rest of the series is going to. So, with the
H_HARDWAREchange made:Acked-by David Gibson <[email protected]>
Thanks for the review!
Have a nice day ;)
Fei
Quoted 43 lines
Quoted 43 lines
Fei
Quoted 38 lines
Quoted 38 lines
Quoted 24 lines
Quoted 24 lines
--- hw/ppc/spapr_hcall.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)hw/ppc/spapr_hcall.c +3
-4@@ -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,10 +539,13 @@ static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, pending->shift = shift; pending->ret =H_HARDWARE ; -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&pending->thread,"sPAPR HPT prepare" , - hpt_prepare_thread, pending, -QEMU_THREAD_DETACHED , &error_abort); + if (!qemu_thread_create(&pending->thread, "sPAPR HPT prepare", + hpt_prepare_thread, pending,Quoted 8 lines
hw/ppc/spapr_hcall.c static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, · line 547
Quoted 4 lines
hw/ppc/spapr_hcall.c +4
-0+ QEMU_THREAD_DETACHED, &local_err)) { +error_reportf_err (local_err,"failed to create hpt_prepare_thread: " ); +g_free (pending); +return H_RESOURCE ;I also think
H_HARDWAREwould be a better choice here. Although the failure is due to a resource constraint, it's not because the guest asked for too much, just because the host is in dire straits. From the guest's point of view it's basically a hardware failure.Ok, thanks. Will use
H_HARDWAREinstead.Have a nice day, thanks for the review. :)
FeiQuoted 2 lines
Quoted 2 lines
hw/ppc/spapr_hcall.c +1
-0+ } spapr->pending_hpt = pending;
PATCH v9 11/16 qemu_thread: supplement error handling for emulated_realize
In reply to Fei LiUtilize the existed errp to propagate the error and do the corresponding cleanup to replace the temporary &error_abort.
--- hw/usb/ccid-card-emulated.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
hw/usb/ccid-card-emulated.c +9 -6
@@ -32,7 +32,6 @@#include "qemu/thread.h" #include "qemu/main-loop.h" #include "ccid.h" -#include "qapi/error.h" #define DPRINTF (card, lvl, fmt, ...) \ do {\
@@ -544,11 +543,15 @@ static void emulated_realize(CCIDCardState *base, Error **errp)error_setg (errp,"%s: failed to initialize vcard" ,TYPE_EMULATED_CCID ); goto out2; } -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&card->event_thread_id,"ccid/event" , event_thread, - card,QEMU_THREAD_JOINABLE , &error_abort); -qemu_thread_create (&card->apdu_thread_id,"ccid/apdu" , handle_apdu_thread, - card,QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&card->event_thread_id,"ccid/event" , event_thread, + card,QEMU_THREAD_JOINABLE , errp)) { + goto out2; + } +if (!qemu_thread_create (&card->apdu_thread_id,"ccid/apdu" , + handle_apdu_thread, card, +QEMU_THREAD_JOINABLE , errp)) { + goto out2; + } out2:clean_event_notifier (card);
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH for-4.0 v9 11/16] qemu_thread: supplement error handling for emulated_realize
Quoted 29 lines · Fei Li
Utilize the existed errp to propagate the error and do the corresponding cleanup to replace the temporary
&error_abort.Cc Cc: Markus Armbruster <[email protected]>Cc Gerd Hoffmann <[email protected]>Signed-off-by Fei Li <[email protected]>--- hw/usb/ccid-card-emulated.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)hw/usb/ccid-card-emulated.c +0
-4@@ -32,7 +32,6 @@#include "qemu/thread.h" #include "qemu/main-loop.h" #include "ccid.h" -#include "qapi/error.h" #define DPRINTF (card, lvl, fmt, ...) \ do {\@@ -544,11 +543,15 @@ static void emulated_realize(CCIDCardState *base, Error **errp)error_setg (errp,"%s: failed to initialize vcard" ,TYPE_EMULATED_CCID ); goto out2; } -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&card->event_thread_id,"ccid/event" , event_thread, - card,QEMU_THREAD_JOINABLE , &error_abort);
hw/usb/ccid-card-emulated.c static void emulated_realize(CCIDCardState *base, Error **errp) · line 553
Quoted 10 lines
hw/usb/ccid-card-emulated.c +8
-2-qemu_thread_create (&card->apdu_thread_id,"ccid/apdu" , handle_apdu_thread, - card,QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&card->event_thread_id,"ccid/event" , event_thread, + card,QEMU_THREAD_JOINABLE , errp)) { + goto out2; + } +if (!qemu_thread_create (&card->apdu_thread_id,"ccid/apdu" , + handle_apdu_thread, card, +QEMU_THREAD_JOINABLE , errp)) { + goto out2;
You need to stop and join the first thread.
Quoted 4 lines
hw/usb/ccid-card-emulated.c +1
-0+ } out2:clean_event_notifier (card);
Re: [Qemu-devel] [PATCH for-4.0 v9 11/16] qemu_thread: supplement error handling for emulated_realize
Quoted 34 lines · Markus Armbruster
Quoted 32 lines · Fei Li
Utilize the existed errp to propagate the error and do the corresponding cleanup to replace the temporary
&error_abort.Cc Cc: Markus Armbruster <[email protected]>Cc Gerd Hoffmann <[email protected]>Signed-off-by Fei Li <[email protected]>--- hw/usb/ccid-card-emulated.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)hw/usb/ccid-card-emulated.c +1
-6@@ -32,7 +32,6 @@#include "qemu/thread.h" #include "qemu/main-loop.h" #include "ccid.h" -#include "qapi/error.h" #define DPRINTF (card, lvl, fmt, ...) \ do {\@@ -544,11 +543,15 @@ static void emulated_realize(CCIDCardState *base, Error **errp)error_setg (errp,"%s: failed to initialize vcard" ,TYPE_EMULATED_CCID ); goto out2; } -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&card->event_thread_id,"ccid/event" , event_thread, - card,QEMU_THREAD_JOINABLE , &error_abort); -qemu_thread_create (&card->apdu_thread_id,"ccid/apdu" , handle_apdu_thread, - card,QEMU_THREAD_JOINABLE , &error_abort); + if (!qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread,
Quoted 8 lines
hw/usb/ccid-card-emulated.c static void emulated_realize(CCIDCardState *base, Error **errp) · line 553
Quoted 7 lines
hw/usb/ccid-card-emulated.c +7
-0+ card, QEMU_THREAD_JOINABLE, errp)) { + goto out2; + } +if (!qemu_thread_create (&card->apdu_thread_id,"ccid/apdu" , + handle_apdu_thread, card, +QEMU_THREAD_JOINABLE , errp)) { + goto out2;You need to stop and join the first thread.
Thanks for pointing this out!
Have a nice day
Fei
Quoted 5 lines
Quoted 5 lines
hw/usb/ccid-card-emulated.c +1
-0+ } out2:clean_event_notifier (card);
PATCH v9 12/16 qemu_thread: supplement error handling for iothread_complete/qemu_signalfd_compat
In reply to Fei LiFor iothread_complete: utilize the existed errp to propagate the error and do the corresponding cleanup to replace the temporary &error_abort.
For qemu_signalfd_compat: add a local_err to hold the error, and return the corresponding error code to replace the temporary &error_abort.
--- iothread.c | 17 +++++++++++------ util/compatfd.c | 11 ++++++++--- 2 files changed, 19 insertions(+), 9 deletions(-)
iothread.c +11 -6
@@ -164,9 +164,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);
@@ -178,9 +176,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); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&iothread->thread, thread_name, iothread_run, - iothread,QEMU_THREAD_JOINABLE , &error_abort); +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);
@@ -191,6 +192,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 {
util/compatfd.c +8 -3
@@ -71,6 +71,7 @@ static int qemu_signalfd_compat(const sigset_t *mask)struct sigfd_compat_info *info;QemuThread thread;int fds[2 ]; +Error *local_err =NULL ; info =malloc (sizeof (*info));if (info ==NULL ) {
@@ -89,9 +90,13 @@ static int qemu_signalfd_compat(const sigset_t *mask)memcpy (&info->mask, mask,sizeof (*mask)); info->fd = fds[1 ]; -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&thread,"signalfd_compat" , sigwait_compat, - info,QEMU_THREAD_DETACHED , &error_abort); +if (!qemu_thread_create (&thread,"signalfd_compat" , sigwait_compat, + info,QEMU_THREAD_DETACHED , &local_err)) { +close (fds[0 ]); +close (fds[1 ]); +free (info); +return -1 ; + }return fds[0 ]; }
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH for-4.0 v9 12/16] qemu_thread: supplement error handling for iothread_complete/qemu_signalfd_compat
Quoted 7 lines · Fei Li
For
iothread_complete: utilize the existed errp to propagate the error and do the corresponding cleanup to replace the temporary&error_abort.For
qemu_signalfd_compat: add alocal_errto hold the error, and return the corresponding error code to replace the temporary&error_abort.
I'd split the patch.
Quoted 25 lines
Cc Markus Armbruster <[email protected]>Cc Eric Blake <[email protected]>Signed-off-by Fei Li <[email protected]>--- iothread.c | 17 +++++++++++------ util/compatfd.c | 11 ++++++++--- 2 files changed, 19 insertions(+), 9 deletions(-)iothread.c +1
-3@@ -164,9 +164,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);
iothread.c static void iothread_complete(UserCreatable *obj, Error **errp) · line 182
Quoted 10 lines
iothread.c +4
-3@@ -178,9 +176,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); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&iothread->thread, thread_name, iothread_run, - iothread,QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&iothread->thread, thread_name, iothread_run, + iothread,QEMU_THREAD_JOINABLE , errp)) { +g_free (thread_name); +g_free (name);
I suspect you're missing cleanup here:
qemu_cond_destroy(&iothread->init_done_cond);
qemu_mutex_destroy(&iothread->init_done_lock);But I'm not 100% sure, to be honest. Stefan, can you help?
iothread.c static void iothread_complete(UserCreatable *obj, Error **errp) · line 187
Quoted 5 lines
iothread.c +2
-0+ goto fail; + }g_free (thread_name);g_free (name);
I'd avoid the code duplication like this:
thread_ok = qemu_thread_create(&iothread->thread, thread_name,
iothread_run, iothread,
QEMU_THREAD_JOINABLE, errp);
g_free(thread_name);
g_free(name);
if (!thread_ok) {
qemu_cond_destroy(&iothread->init_done_cond);
qemu_mutex_destroy(&iothread->init_done_lock);
goto fail;
}Matter of taste.
Hmm, iothread.c has no maintainer. Stefan, you created it, would you be willing to serve as maintainer?
Quoted 26 lines
iothread.c +4
-0@@ -191,6 +192,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 {util/compatfd.c +1
-0@@ -71,6 +71,7 @@ static int qemu_signalfd_compat(const sigset_t *mask)struct sigfd_compat_info *info;QemuThread thread;int fds[2 ]; +Error *local_err =NULL ; info =malloc (sizeof (*info));if (info ==NULL ) {@@ -89,9 +90,13 @@ static int qemu_signalfd_compat(const sigset_t *mask)memcpy (&info->mask, mask,sizeof (*mask)); info->fd = fds[1 ];
util/compatfd.c static int qemu_signalfd_compat(const sigset_t *mask) · line 98
Quoted 10 lines
util/compatfd.c +6
-3-/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&thread,"signalfd_compat" , sigwait_compat, - info,QEMU_THREAD_DETACHED , &error_abort); +if (!qemu_thread_create (&thread,"signalfd_compat" , sigwait_compat, + info,QEMU_THREAD_DETACHED , &local_err)) { +close (fds[0 ]); +close (fds[1 ]); +free (info); +return -1 ;
Leaks @local_err. Pass NULL instead.
Quoted 4 lines
util/compatfd.c +1
-0+ }return fds[0 ]; }
Re: [Qemu-devel] [PATCH for-4.0 v9 12/16] qemu_thread: supplement error handling for iothread_complete/qemu_signalfd_compat
Quoted 10 lines · 在 2019年1月8日,01:50,Markus Armbruster <[email protected]> 写道:
Quoted 4 lines · Fei Li
For
iothread_complete: utilize the existed errp to propagate the error and do the corresponding cleanup to replace the temporary&error_abort.
Quoted 5 lines
Quoted 3 lines
For
qemu_signalfd_compat: add alocal_errto hold the error, and return the corresponding error code to replace the temporary&error_abort.I'd split the patch.
Ok.
Quoted 39 lines
Quoted 26 lines
Cc Markus Armbruster <[email protected]>Cc Eric Blake <[email protected]>Signed-off-by Fei Li <[email protected]>---
iothread.c| 17 +++++++++++------util/compatfd.c| 11 ++++++++---2 files changed, 19 insertions(+), 9 deletions(-)iothread.c +1
-3@@ -164,9 +164,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);iothread.c static void iothread_complete(UserCreatable *obj, Error **errp) · line 182
Quoted 10 lines
iothread.c +4
-3@@ -178,9 +176,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); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&iothread->thread, thread_name, iothread_run, - iothread,QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&iothread->thread, thread_name, iothread_run, + iothread,QEMU_THREAD_JOINABLE , errp)) { +g_free (thread_name); +g_free (name);I suspect you're missing cleanup here:
Quoted 2 lines
qemu_cond_destroy(&iothread->init_done_cond);
qemu_mutex_destroy(&iothread->init_done_lock);I remember I checked the code, when ucc->complete() fails, there’s a finalize() function to do the destroy. But did not test all the callers, so let’s wait for Stefan’s feedback. :)
Quoted 55 lines
But I'm not 100% sure, to be honest. Stefan, can you help?
iothread.c static void iothread_complete(UserCreatable *obj, Error **errp) · line 187
Quoted 5 lines
iothread.c +2
-0+ goto fail; + }g_free (thread_name);g_free (name);I'd avoid the code duplication like this:
thread_ok = qemu_thread_create(&iothread->thread, thread_name, iothread_run, iothread, QEMU_THREAD_JOINABLE, errp); g_free(thread_name); g_free(name); if (!thread_ok) { qemu_cond_destroy(&iothread->init_done_cond); qemu_mutex_destroy(&iothread->init_done_lock); goto fail; }Matter of taste.
Hmm,
iothread.chas no maintainer. Stefan, you created it, would you be willing to serve as maintainer?Quoted 27 lines
iothread.c +4
-0@@ -191,6 +192,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 {util/compatfd.c +1
-0@@ -71,6 +71,7 @@ static int qemu_signalfd_compat(const sigset_t *mask)struct sigfd_compat_info *info;QemuThread thread;int fds[2 ]; +Error *local_err =NULL ; info =malloc (sizeof (*info));if (info ==NULL ) {@@ -89,9 +90,13 @@ static int qemu_signalfd_compat(const sigset_t *mask)memcpy (&info->mask, mask,sizeof (*mask)); info->fd = fds[1 ];
Quoted 11 lines
util/compatfd.c static int qemu_signalfd_compat(const sigset_t *mask) · line 98
Quoted 9 lines
util/compatfd.c +6
-3-/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&thread,"signalfd_compat" , sigwait_compat, - info,QEMU_THREAD_DETACHED , &error_abort); +if (!qemu_thread_create (&thread,"signalfd_compat" , sigwait_compat, + info,QEMU_THREAD_DETACHED , &local_err)) { +close (fds[0 ]); +close (fds[1 ]); +free (info); +return -1 ;Leaks @local_err. Pass NULL instead.
Ok, thanks!
Have a nice day
Fei
Quoted 5 lines
Quoted 5 lines
util/compatfd.c +1
-0+ }return fds[0 ]; }
Re: [Qemu-devel] [PATCH for-4.0 v9 12/16] qemu_thread: supplement error handling for iothread_complete/qemu_signalfd_compat
Quoted 50 lines · fei
Quoted 13 lines · 在 2019年1月8日,01:50,Markus Armbruster <[email protected]> 写道:
Quoted 7 lines · Fei Li
For
iothread_complete: utilize the existed errp to propagate the error and do the corresponding cleanup to replace the temporary&error_abort.For
qemu_signalfd_compat: add alocal_errto hold the error, and return the corresponding error code to replace the temporary&error_abort.I'd split the patch.
Ok.
Quoted 36 lines
Quoted 24 lines
Cc Markus Armbruster <[email protected]>Cc Eric Blake <[email protected]>Signed-off-by Fei Li <[email protected]>---
iothread.c| 17 +++++++++++------util/compatfd.c| 11 ++++++++---2 files changed, 19 insertions(+), 9 deletions(-)iothread.c +1
-3@@ -164,9 +164,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);iothread.c static void iothread_complete(UserCreatable *obj, Error **errp) · line 182
Quoted 10 lines
iothread.c +4
-3@@ -178,9 +176,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); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&iothread->thread, thread_name, iothread_run, - iothread,QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&iothread->thread, thread_name, iothread_run, + iothread,QEMU_THREAD_JOINABLE , errp)) { +g_free (thread_name); +g_free (name);I suspect you're missing cleanup here:
Quoted 3 lines
Quoted 2 lines
qemu_cond_destroy(&iothread->init_done_cond); qemu_mutex_destroy(&iothread->init_done_lock);I remember I checked the code, when
ucc->complete()fails, there’s afinalize()function to do the destroy.
To be specific, the qemu_xxx_destroy() is called by
object_unref() => object_finalize() => object_deinit() => type->instance_finalize(obj); (that is, iothread_instance_finalize).
For the iothread_complete(), it is only called in user_creatable_complete() as ucc->complete(). I checked the code, when callers of user_creatable_complete() fails, all of them will call object_unref() to call the qemu_xxx_destroy(), except one &error_abort case (e.i. desugar_shm()).
Quoted 1 line
But did not test all the callers, so let’s wait for Stefan’s feedback. :)
But again, I did not do all the test. Correct me if I am wrong. :)
Quoted 10 lines
Quoted 10 lines
But I'm not 100% sure, to be honest. Stefan, can you help?
iothread.c static void iothread_complete(UserCreatable *obj, Error **errp) · line 187
Quoted 5 lines
iothread.c +2
-0+ goto fail; + }g_free (thread_name);g_free (name);I'd avoid the code duplication like this:
Quoted 10 lines
Quoted 10 lines
thread_ok = qemu_thread_create(&iothread->thread, thread_name, iothread_run, iothread, QEMU_THREAD_JOINABLE, errp); g_free(thread_name); g_free(name); if (!thread_ok) { qemu_cond_destroy(&iothread->init_done_cond); qemu_mutex_destroy(&iothread->init_done_lock); goto fail; }
Ok, thanks.
Have a nice day
Fei
Quoted 5 lines
Quoted 5 lines
Matter of taste.
Hmm,
iothread.chas no maintainer. Stefan, you created it, would you be willing to serve as maintainer?
Re: [Qemu-devel] [PATCH for-4.0 v9 12/16] qemu_thread: supplement error handling for iothread_complete/qemu_signalfd_compat
Quoted 60 lines · Fei Li
Quoted 50 lines · fei
Quoted 13 lines · 在 2019年1月8日,01:50,Markus Armbruster <[email protected]> 写道:
Quoted 7 lines · Fei Li
For
iothread_complete: utilize the existed errp to propagate the error and do the corresponding cleanup to replace the temporary&error_abort.For
qemu_signalfd_compat: add alocal_errto hold the error, and return the corresponding error code to replace the temporary&error_abort.I'd split the patch.
Ok.
Quoted 36 lines
Quoted 24 lines
Cc Markus Armbruster <[email protected]>Cc Eric Blake <[email protected]>Signed-off-by Fei Li <[email protected]>---
iothread.c| 17 +++++++++++------util/compatfd.c| 11 ++++++++---2 files changed, 19 insertions(+), 9 deletions(-)iothread.c +1
-3@@ -164,9 +164,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);iothread.c static void iothread_complete(UserCreatable *obj, Error **errp) · line 182
Quoted 10 lines
iothread.c +4
-3@@ -178,9 +176,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); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&iothread->thread, thread_name, iothread_run, - iothread,QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&iothread->thread, thread_name, iothread_run, + iothread,QEMU_THREAD_JOINABLE , errp)) { +g_free (thread_name); +g_free (name);I suspect you're missing cleanup here:
Quoted 3 lines
Quoted 2 lines
qemu_cond_destroy(&iothread->init_done_cond); qemu_mutex_destroy(&iothread->init_done_lock);I remember I checked the code, when
ucc->complete()fails, there’s afinalize()function to do the destroy.To be specific, the
qemu_xxx_destroy()is called by
object_unref()=>object_finalize()=>object_deinit()=>type->instance_finalize(obj); (that is,iothread_instance_finalize).
Quoted 6 lines
For the
iothread_complete(), it is only called inuser_creatable_complete()asucc->complete().
I checked the code, when callers ofuser_creatable_complete()fails, all of them will callobject_unref()to call theqemu_xxx_destroy(), except one&error_abortcase (e.i.desugar_shm()).
I'm not familiar with iothread.c. But like anyone capable of reading C, I can find out stuff.
iothread_instance_finalize() guards its cleanups. In particular, it cleans up ->init_done_cond and init_done_lock only when ->thread_id != -1.
iothread_instance_init() initializes ->thread_id = -1.
iothread_run() sets it to the actual thread ID.
When iothread_instance_complete() succeeds, it has waited for ->thread_id to become != -1, in the /* Wait for initialization to complete */ loop.
When it fails, ->thread_id is still -1.
Therefore, you cannot rely on iothread_instance_finalize() for cleaning up ->init_done_lock and ->init_done_cond on iothread_instance_complete() failure.
I'm pretty sure you could've figured this out yourself instead of relying on me.
[...]
Re: [Qemu-devel] [PATCH for-4.0 v9 12/16] qemu_thread: supplement error handling for iothread_complete/qemu_signalfd_compat
Quoted 66 lines · Markus Armbruster
Quoted 58 lines · Fei Li
Quoted 49 lines · fei
Quoted 12 lines · 在 2019年1月8日,01:50,Markus Armbruster <[email protected]> 写道:
Quoted 7 lines · Fei Li
For
iothread_complete: utilize the existed errp to propagate the error and do the corresponding cleanup to replace the temporary&error_abort.For
qemu_signalfd_compat: add alocal_errto hold the error, and return the corresponding error code to replace the temporary&error_abort.I'd split the patch.
Ok.
Quoted 36 lines
Quoted 24 lines
Cc Markus Armbruster <[email protected]>Cc Eric Blake <[email protected]>Signed-off-by Fei Li <[email protected]>---
iothread.c| 17 +++++++++++------util/compatfd.c| 11 ++++++++---2 files changed, 19 insertions(+), 9 deletions(-)iothread.c +1
-3@@ -164,9 +164,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);iothread.c static void iothread_complete(UserCreatable *obj, Error **errp) · line 182
Quoted 10 lines
iothread.c +4
-3@@ -178,9 +176,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); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&iothread->thread, thread_name, iothread_run, - iothread,QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&iothread->thread, thread_name, iothread_run, + iothread,QEMU_THREAD_JOINABLE , errp)) { +g_free (thread_name); +g_free (name);I suspect you're missing cleanup here:
Quoted 3 lines
Quoted 2 lines
qemu_cond_destroy(&iothread->init_done_cond); qemu_mutex_destroy(&iothread->init_done_lock);I remember I checked the code, when
ucc->complete()fails, there’s afinalize()function to do the destroy.To be specific, the
qemu_xxx_destroy()is called by
object_unref()=>object_finalize()=>object_deinit()=>type->instance_finalize(obj); (that is,iothread_instance_finalize).Quoted 6 lines
For the
iothread_complete(), it is only called inuser_creatable_complete()asucc->complete().
I checked the code, when callers ofuser_creatable_complete()fails, all of them will callobject_unref()to call theqemu_xxx_destroy(), except one&error_abortcase (e.i.desugar_shm()).
Quoted 6 lines
I'm not familiar with
iothread.c. But like anyone capable of reading C, I can find out stuff.
iothread_instance_finalize()guards its cleanups. In particular, it cleans up ->init_done_cond andinit_done_lockonly when ->thread_id != -1.
Ah, sorry that I overlooked the "if (iothread->thread_id != -1)". So embarrassed, and sorry for the trouble.. You are right, and I will add the qemu_xxx_destroy() in the next version. ;)
Have a nice day, thanks so much!
Fei
Quoted 19 lines
iothread_instance_init()initializes ->thread_id = -1.
iothread_run()sets it to the actual thread ID.When
iothread_instance_complete()succeeds, it has waited for ->thread_id to become != -1, in the /* Wait for initialization to complete */ loop.When it fails, ->thread_id is still -1.
Therefore, you cannot rely on
iothread_instance_finalize()for cleaning up ->init_done_lock and ->init_done_cond oniothread_instance_complete()failure.I'm pretty sure you could've figured this out yourself instead of relying on me.
[...]
PATCH v9 13/16 qemu_thread: supplement error handling for migration
In reply to Fei LiUpdate qemu_thread_create()'s callers by
- setting an error on qemu_thread_create() failure for callers that set an error on failure;
- reporting the error and returning failure for callers that return an error code on failure;
- reporting the error and setting some state for callers that just report errors and choose not to continue on.
--- migration/migration.c | 33 ++++++++++++++++++++++----------- migration/postcopy-ram.c | 16 ++++++++++++---- migration/ram.c | 44 ++++++++++++++++++++++++++++++-------------- migration/savevm.c | 12 ++++++++---- 4 files changed, 72 insertions(+), 33 deletions(-)
migration/migration.c +22 -11
@@ -447,10 +447,13 @@ static void process_incoming_migration_co(void *opaque) goto fail; } -/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (&mis->colo_incoming_thread,"COLO incoming" , - colo_process_incoming_thread, mis, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&mis->colo_incoming_thread,"COLO incoming" , + colo_process_incoming_thread, mis, +QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err,"failed to create " +"colo_process_incoming_thread: " ); + goto fail; + } mis->have_colo_incoming_thread = true;qemu_coroutine_yield ();
@@ -2347,6 +2350,7 @@ out:static int open_return_path_on_source (MigrationState *ms,bool create_thread) { +Error *local_err =NULL ; ms->rp_state.from_dst_file =qemu_file_get_return_path (ms->to_dst_file);if (!ms->rp_state.from_dst_file) {
@@ -2360,10 +2364,13 @@ static int open_return_path_on_source(MigrationState *ms,return 0 ; } -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&ms->rp_state.rp_thread,"return path" , - source_return_path_thread, ms, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&ms->rp_state.rp_thread,"return path" , + source_return_path_thread, ms, +QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err, +"failed to create source_return_path_thread: " ); +return -1 ; + }trace_open_return_path_on_source_continue ();
@@ -3193,9 +3200,13 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)migrate_fd_cleanup (s);return ; } -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&s->thread,"live_migration" , migration_thread, s, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&s->thread,"live_migration" , migration_thread, s, +QEMU_THREAD_JOINABLE , &error_in)) { +error_reportf_err (error_in,"failed to create migration_thread: " ); +migrate_set_state (&s->state, s->state,MIGRATION_STATUS_FAILED ); +migrate_fd_cleanup (s); +return ; + } s->migration_thread_running = true; }
migration/postcopy-ram.c +12 -4
@@ -1083,6 +1083,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 ) {
@@ -1109,10 +1111,16 @@ int postcopy_ram_enable_notify(MigrationIncomingState *mis) }qemu_sem_init (&mis->fault_thread_sem,0 ); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&mis->fault_thread,"postcopy/fault" , - postcopy_ram_fault_thread, mis, -QEMU_THREAD_JOINABLE , &error_abort); +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 +30 -14
80 lines not on this page · raw message
migration/savevm.c +8 -4
@@ -1747,10 +1747,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 ); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&mis->listen_thread,"postcopy/listen" , - postcopy_ram_listen_thread,NULL , -QEMU_THREAD_DETACHED , &error_abort); +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);
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH for-4.0 v9 13/16] qemu_thread: supplement error handling for migration
Quoted 30 lines · * Fei Li ([email protected]) wrote:
Update qemu_thread_create()'s callers by
- setting an error onqemu_thread_create()failure for callers that set an error on failure;
- reporting the error and returning failure for callers that return an error code on failure;
- reporting the error and setting some state for callers that just report errors and choose not to continue on.Cc Markus Armbruster <[email protected]>Cc Dr. David Alan Gilbert <[email protected]>Cc Peter Xu <[email protected]>Signed-off-by Fei Li <[email protected]>--- migration/migration.c | 33 ++++++++++++++++++++++----------- migration/postcopy-ram.c | 16 ++++++++++++---- migration/ram.c | 44 ++++++++++++++++++++++++++++++-------------- migration/savevm.c | 12 ++++++++---- 4 files changed, 72 insertions(+), 33 deletions(-)migration/migration.c +0
-3@@ -447,10 +447,13 @@ static void process_incoming_migration_co(void *opaque) goto fail; } -/* TODO: let the further caller handle the error instead of abort() */ - qemu_thread_create(&mis->colo_incoming_thread, "COLO incoming", - colo_process_incoming_thread, mis,
migration/migration.c static void process_incoming_migration_co(void *opaque) · line 458
Quoted 10 lines
migration/migration.c +7
-1- QEMU_THREAD_JOINABLE, &error_abort); +if (!qemu_thread_create (&mis->colo_incoming_thread,"COLO incoming" , + colo_process_incoming_thread, mis, +QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err,"failed to create " +"colo_process_incoming_thread: " ); + goto fail; + } mis->have_colo_incoming_thread = true;qemu_coroutine_yield ();
OK
Quoted 13 lines
migration/migration.c +1
-1@@ -2347,6 +2350,7 @@ out:static int open_return_path_on_source (MigrationState *ms,bool create_thread) { +Error *local_err =NULL ; ms->rp_state.from_dst_file =qemu_file_get_return_path (ms->to_dst_file);if (!ms->rp_state.from_dst_file) {@@ -2360,10 +2364,13 @@ static int open_return_path_on_source(MigrationState *ms,return 0 ; } -/* TODO: let the further caller handle the error instead of abort() here */
migration/migration.c static int open_return_path_on_source(MigrationState *ms, · line 2373
Quoted 10 lines
migration/migration.c +7
-3-qemu_thread_create (&ms->rp_state.rp_thread,"return path" , - source_return_path_thread, ms, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&ms->rp_state.rp_thread,"return path" , + source_return_path_thread, ms, +QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err, +"failed to create source_return_path_thread: " ); +return -1 ; + }
I think that has to close the from_dst_file and set the from_dst_file=NULL. That file is owned by the thread, and it's normally the thread that cleans it up.
I think other than that missing close it's fine; and we can do that as a fix later, so:
Quoted 7 lines
migration/migration.c +0
-0trace_open_return_path_on_source_continue ();@@ -3193,9 +3200,13 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)migrate_fd_cleanup (s);return ; }
migration/migration.c void migrate_fd_connect(MigrationState *s, Error *error_in) · line 3209
Quoted 10 lines
migration/migration.c +7
-3-/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&s->thread,"live_migration" , migration_thread, s, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&s->thread,"live_migration" , migration_thread, s, +QEMU_THREAD_JOINABLE , &error_in)) { +error_reportf_err (error_in,"failed to create migration_thread: " ); +migrate_set_state (&s->state, s->state,MIGRATION_STATUS_FAILED ); +migrate_fd_cleanup (s); +return ; + }
OK
Quoted 27 lines
migration/migration.c +0
-0s->migration_thread_running = true; }migration/postcopy-ram.c +5
-4@@ -1083,6 +1083,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 ) {@@ -1109,10 +1111,16 @@ int postcopy_ram_enable_notify(MigrationIncomingState *mis) }qemu_sem_init (&mis->fault_thread_sem,0 ); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&mis->fault_thread,"postcopy/fault" , - postcopy_ram_fault_thread, mis, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&mis->fault_thread,"postcopy/fault" , + postcopy_ram_fault_thread, mis, +QEMU_THREAD_JOINABLE , &local_err)) {
migration/postcopy-ram.c int postcopy_ram_enable_notify(MigrationIncomingState *mis) · line 1126
Quoted 10 lines
migration/postcopy-ram.c +7
-0+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;
OK
Quoted 16 lines
migration/ram.c +1
-0@@ -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,10 +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);
migration/ram.c static int compress_threads_save_setup(void) · line 511
Quoted 10 lines
migration/ram.c +6
-4-/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (compress_threads + i,"compress" , - do_data_compress, comp_param + i, -QEMU_THREAD_JOINABLE , &error_abort); +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; + }
OK
Quoted 90 lines
migration/ram.c +23
-10}return 0 ;@@ -1076,9 +1079,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; -/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (&p->thread, p->name, multifd_send_thread, p, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&p->thread, p->name, multifd_send_thread, p, +QEMU_THREAD_JOINABLE , &local_err)) { +migrate_set_error (migrate_get_current (), local_err); +error_reportf_err (local_err, +"failed to create multifd_send_thread: " ); +multifd_save_cleanup (); +return ; + }atomic_inc (&multifd_send_state->count); }@@ -1357,9 +1365,13 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) p->num_packets =1 ; p->running = true; -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&p->thread, p->name, multifd_recv_thread, p, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&p->thread, p->name, multifd_recv_thread, p, +QEMU_THREAD_JOINABLE , &local_err)) { +error_propagate_prepend (errp, local_err, +"failed to create multifd_recv_thread: " ); +multifd_recv_terminate_threads (local_err); +return false; + }atomic_inc (&multifd_recv_state->count);return atomic_read (&multifd_recv_state->count) ==migrate_multifd_channels ();@@ -3625,6 +3637,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 ;@@ -3646,10 +3659,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; -/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (decompress_threads + i,"decompress" , - do_data_decompress, decomp_param + i, -QEMU_THREAD_JOINABLE , &error_abort); +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
-4@@ -1747,10 +1747,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 ); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&mis->listen_thread,"postcopy/listen" , - postcopy_ram_listen_thread,NULL , -QEMU_THREAD_DETACHED , &error_abort); +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);Signature · 1 line
2.13.7
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [PATCH for-4.0 v9 13/16] qemu_thread: supplement error handling for migration
Quoted 70 lines · Dr. David Alan Gilbert
Quoted 30 lines · * Fei Li ([email protected]) wrote:
Update qemu_thread_create()'s callers by
- setting an error onqemu_thread_create()failure for callers that set an error on failure;
- reporting the error and returning failure for callers that return an error code on failure;
- reporting the error and setting some state for callers that just report errors and choose not to continue on.Cc Markus Armbruster <[email protected]>Cc Dr. David Alan Gilbert <[email protected]>Cc Peter Xu <[email protected]>Signed-off-by Fei Li <[email protected]>--- migration/migration.c | 33 ++++++++++++++++++++++----------- migration/postcopy-ram.c | 16 ++++++++++++---- migration/ram.c | 44 ++++++++++++++++++++++++++++++-------------- migration/savevm.c | 12 ++++++++---- 4 files changed, 72 insertions(+), 33 deletions(-)migration/migration.c +0
-3@@ -447,10 +447,13 @@ static void process_incoming_migration_co(void *opaque) goto fail; } -/* TODO: let the further caller handle the error instead of abort() */ - qemu_thread_create(&mis->colo_incoming_thread, "COLO incoming", - colo_process_incoming_thread, mis,migration/migration.c static void process_incoming_migration_co(void *opaque) · line 458
Quoted 10 lines
migration/migration.c +7
-1- QEMU_THREAD_JOINABLE, &error_abort); +if (!qemu_thread_create (&mis->colo_incoming_thread,"COLO incoming" , + colo_process_incoming_thread, mis, +QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err,"failed to create " +"colo_process_incoming_thread: " ); + goto fail; + } mis->have_colo_incoming_thread = true;qemu_coroutine_yield ();OK
Quoted 13 lines
migration/migration.c +1
-1@@ -2347,6 +2350,7 @@ out:static int open_return_path_on_source (MigrationState *ms,bool create_thread) { +Error *local_err =NULL ; ms->rp_state.from_dst_file =qemu_file_get_return_path (ms->to_dst_file);if (!ms->rp_state.from_dst_file) {@@ -2360,10 +2364,13 @@ static int open_return_path_on_source(MigrationState *ms,return 0 ; } -/* TODO: let the further caller handle the error instead of abort() here */ migration/migration.c static int open_return_path_on_source(MigrationState *ms, · line 2373
Quoted 10 lines
migration/migration.c +7
-3-qemu_thread_create (&ms->rp_state.rp_thread,"return path" , - source_return_path_thread, ms, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&ms->rp_state.rp_thread,"return path" , + source_return_path_thread, ms, +QEMU_THREAD_JOINABLE , &local_err)) { +error_reportf_err (local_err, +"failed to create source_return_path_thread: " ); +return -1 ; + }I think that has to close the
from_dst_fileand set the from_dst_file=NULL. That file is owned by the thread, and it's normally the thread that cleans it up.
Quoted 5 lines
I think other than that missing close it's fine; and we can do that as a fix later, so:
Reviewed-by Dr. David Alan Gilbert <[email protected]>
Ok, I will add the cleanup for the from_dst_file in the next version.
Thanks for the review! Have a nice day :)
Fei
Quoted 179 lines
Quoted 8 lines
migration/migration.c +0
-0trace_open_return_path_on_source_continue ();@@ -3193,9 +3200,13 @@ void migrate_fd_connect(MigrationState *s, Error *error_in)migrate_fd_cleanup (s);return ; }migration/migration.c void migrate_fd_connect(MigrationState *s, Error *error_in) · line 3209
Quoted 10 lines
migration/migration.c +7
-3-/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&s->thread,"live_migration" , migration_thread, s, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&s->thread,"live_migration" , migration_thread, s, +QEMU_THREAD_JOINABLE , &error_in)) { +error_reportf_err (error_in,"failed to create migration_thread: " ); +migrate_set_state (&s->state, s->state,MIGRATION_STATUS_FAILED ); +migrate_fd_cleanup (s); +return ; + }OK
Quoted 27 lines
migration/migration.c +0
-0s->migration_thread_running = true; }migration/postcopy-ram.c +5
-4@@ -1083,6 +1083,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 ) {@@ -1109,10 +1111,16 @@ int postcopy_ram_enable_notify(MigrationIncomingState *mis) }qemu_sem_init (&mis->fault_thread_sem,0 ); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&mis->fault_thread,"postcopy/fault" , - postcopy_ram_fault_thread, mis, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&mis->fault_thread,"postcopy/fault" , + postcopy_ram_fault_thread, mis, +QEMU_THREAD_JOINABLE , &local_err)) {migration/postcopy-ram.c int postcopy_ram_enable_notify(MigrationIncomingState *mis) · line 1126
Quoted 10 lines
migration/postcopy-ram.c +7
-0+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;OK
Quoted 16 lines
migration/ram.c +1
-0@@ -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,10 +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);migration/ram.c static int compress_threads_save_setup(void) · line 511
Quoted 10 lines
migration/ram.c +6
-4-/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (compress_threads + i,"compress" , - do_data_compress, comp_param + i, -QEMU_THREAD_JOINABLE , &error_abort); +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; + }OK
Quoted 90 lines
migration/ram.c +23
-10}return 0 ;@@ -1076,9 +1079,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; -/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (&p->thread, p->name, multifd_send_thread, p, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&p->thread, p->name, multifd_send_thread, p, +QEMU_THREAD_JOINABLE , &local_err)) { +migrate_set_error (migrate_get_current (), local_err); +error_reportf_err (local_err, +"failed to create multifd_send_thread: " ); +multifd_save_cleanup (); +return ; + }atomic_inc (&multifd_send_state->count); }@@ -1357,9 +1365,13 @@ bool multifd_recv_new_channel(QIOChannel *ioc, Error **errp) p->num_packets =1 ; p->running = true; -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&p->thread, p->name, multifd_recv_thread, p, -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&p->thread, p->name, multifd_recv_thread, p, +QEMU_THREAD_JOINABLE , &local_err)) { +error_propagate_prepend (errp, local_err, +"failed to create multifd_recv_thread: " ); +multifd_recv_terminate_threads (local_err); +return false; + }atomic_inc (&multifd_recv_state->count);return atomic_read (&multifd_recv_state->count) ==migrate_multifd_channels ();@@ -3625,6 +3637,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 ;@@ -3646,10 +3659,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; -/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (decompress_threads + i,"decompress" , - do_data_decompress, decomp_param + i, -QEMU_THREAD_JOINABLE , &error_abort); +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
-4@@ -1747,10 +1747,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 ); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&mis->listen_thread,"postcopy/listen" , - postcopy_ram_listen_thread,NULL , -QEMU_THREAD_DETACHED , &error_abort); +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);Signature · 1 line
2.13.7--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Re: [Qemu-devel] [PATCH for-4.0 v9 13/16] qemu_thread: supplement error handling for migration
In reply to Fei LiQuoted 12 lines · Fei Li
Update qemu_thread_create()'s callers by
- setting an error onqemu_thread_create()failure for callers that set an error on failure;
- reporting the error and returning failure for callers that return an error code on failure;
- reporting the error and setting some state for callers that just report errors and choose not to continue on.Cc Markus Armbruster <[email protected]>Cc Dr. David Alan Gilbert <[email protected]>Cc Peter Xu <[email protected]>Signed-off-by Fei Li <[email protected]>
[...]
Quoted 4 lines
migration/ram.c +0
-0
[...]
Quoted 12 lines
migration/ram.c +1
-0@@ -3625,6 +3637,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 ;@@ -3646,10 +3659,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;
migration/ram.c static int compress_threads_load_setup(QEMUFile *f) · line 3667
Quoted 10 lines
migration/ram.c +6
-4-/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (decompress_threads + i,"decompress" , - do_data_decompress, decomp_param + i, -QEMU_THREAD_JOINABLE , &error_abort); +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;
Broken error handling, see my review of PATCH 16.
Quoted 4 lines
migration/ram.c +1
-0+ } }return 0 ; exit:
[...]
Re: [Qemu-devel] [PATCH for-4.0 v9 13/16] qemu_thread: supplement error handling for migration
Quoted 40 lines · 在 2019年1月9日,23:26,Markus Armbruster <[email protected]> 写道:
Quoted 12 lines · Fei Li
Update qemu_thread_create()'s callers by
- setting an error onqemu_thread_create()failure for callers that set an error on failure;
- reporting the error and returning failure for callers that return an error code on failure;
- reporting the error and setting some state for callers that just report errors and choose not to continue on.Cc Markus Armbruster <[email protected]>Cc Dr. David Alan Gilbert <[email protected]>Cc Peter Xu <[email protected]>Signed-off-by Fei Li <[email protected]>[...]
Quoted 4 lines
migration/ram.c +0
-0[...]
Quoted 16 lines
migration/ram.c +1
-4@@ -3625,6 +3637,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 ;@@ -3646,10 +3659,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; -/* TODO: let the further caller handle the error instead of abort() */ -qemu_thread_create (decompress_threads + i,"decompress" , - do_data_decompress, decomp_param + i, -QEMU_THREAD_JOINABLE , &error_abort);
Quoted 8 lines
migration/ram.c static int compress_threads_load_setup(QEMUFile *f) · line 3667
Quoted 6 lines
migration/ram.c +6
-0+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;Broken error handling, see my review of PATCH 16.
Yep, seems both the compress_threads_save_setup() and compress_threads_load_setup() have such problem.
Quoted 6 lines
Quoted 5 lines
migration/ram.c +1
-0+ } }return 0 ;exit:
[...]
PATCH v9 14/16 qemu_thread: supplement error handling for vnc_start_worker_thread
In reply to Fei LiSupplement the error handling for vnc_thread_worker_thread: add an Error parameter for it to propagate the error to its caller to handle in case it fails, and make it return a Boolean to indicate whether it succeeds.
--- ui/vnc-jobs.c | 17 +++++++++++------ ui/vnc-jobs.h | 2 +- ui/vnc.c | 4 +++- 3 files changed, 15 insertions(+), 8 deletions(-)
ui/vnc-jobs.c +11 -6
@@ -332,16 +332,21 @@ 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 (); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, - q,QEMU_THREAD_DETACHED , &error_abort); +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; }
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 +3 -1
@@ -3236,7 +3236,9 @@ void vnc_display_init(const char *id, Error **errp) 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);
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH for-4.0 v9 14/16] qemu_thread: supplement error handling for vnc_start_worker_thread
Quoted 21 lines · Fei Li
Supplement the error handling for
vnc_thread_worker_thread: add an Error parameter for it to propagate the error to its caller to handle in case it fails, and make it return a Boolean to indicate whether it succeeds.Cc Markus Armbruster <[email protected]>Cc Gerd Hoffmann <[email protected]>Signed-off-by Fei Li <[email protected]>--- ui/vnc-jobs.c | 17 +++++++++++------ ui/vnc-jobs.h | 2 +- ui/vnc.c | 4 +++- 3 files changed, 15 insertions(+), 8 deletions(-)ui/vnc-jobs.c +0
-0@@ -332,16 +332,21 @@ static bool vnc_worker_thread_running(void)return queue;/* Check global queue */ }
ui/vnc-jobs.c static bool vnc_worker_thread_running(void) · line 340
Quoted 10 lines
ui/vnc-jobs.c +3
-3-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;
Why not simply return true?
Quoted 43 lines
ui/vnc-jobs.c +8
-3+ } q =vnc_queue_init (); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, - q,QEMU_THREAD_DETACHED , &error_abort); +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; }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 +3
-1@@ -3236,7 +3236,9 @@ void vnc_display_init(const char *id, Error **errp) 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);
Re: [Qemu-devel] [PATCH for-4.0 v9 14/16] qemu_thread: supplement error handling for vnc_start_worker_thread
Quoted 33 lines · 在 2019年1月8日,01:54,Markus Armbruster <[email protected]> 写道:
Quoted 27 lines · Fei Li
Supplement the error handling for
vnc_thread_worker_thread: add an Error parameter for it to propagate the error to its caller to handle in case it fails, and make it return a Boolean to indicate whether it succeeds.Cc Markus Armbruster <[email protected]>Cc Gerd Hoffmann <[email protected]>Signed-off-by Fei Li <[email protected]>---
ui/vnc-jobs.c | 17 +++++++++++------ ui/vnc-jobs.h | 2 +- ui/vnc.c | 4 +++- 3 files changed, 15 insertions(+), 8 deletions(-)ui/vnc-jobs.c +1
-1@@ -332,16 +332,21 @@ 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;
Quoted 6 lines
ui/vnc-jobs.c static bool vnc_worker_thread_running(void) · line 340
Quoted 4 lines
ui/vnc-jobs.c +2
-2-if (vnc_worker_thread_running ()) -return ; +if (vnc_worker_thread_running ()) { + goto out;Why not simply return true?
Sounds right.. Will remove the below “out:” too.
Have a nice day, thanks
Fei
Quoted 44 lines
Quoted 44 lines
ui/vnc-jobs.c +8
-3+ } q =vnc_queue_init (); -/* TODO: let the further caller handle the error instead of abort() here */ -qemu_thread_create (&q->thread,"vnc_worker" , vnc_worker_thread, - q,QEMU_THREAD_DETACHED , &error_abort); +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; }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 +3
-1@@ -3236,7 +3236,9 @@ void vnc_display_init(const char *id, Error **errp) 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);
PATCH v9 15/16 qemu_thread: supplement error handling for touch_all_pages
In reply to Fei LiSupplement the error handling for touch_all_pages: add an Error parameter for it to propagate the error to its caller to do the handling in case it fails.
--- util/oslib-posix.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)
util/oslib-posix.c +16 -9
@@ -431,15 +431,17 @@ static inline int get_memset_num_threads(int smp_cpus) }static bool touch_all_pages (char *area,size_t hpagesize,size_t numpages, -int smp_cpus) +int smp_cpus,Error **errp) {size_t numpages_per_thread;size_t size_per_thread;char *addr = area;int i =0 ; +int started_thread =0 ; 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,14 +450,18 @@ 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; -/* TODO: let the callers handle the error instead of abort() here */ -qemu_thread_create (&memset_thread[i].pgthread,"touch_pages" , - do_touch_pages, &memset_thread[i], -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&memset_thread[i].pgthread,"touch_pages" , + do_touch_pages, &memset_thread[i], +QEMU_THREAD_JOINABLE , errp)) { + 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);
@@ -471,6 +477,7 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,struct sigaction act, oldact;size_t hpagesize =qemu_fd_getpagesize (fd);size_t numpages =DIV_ROUND_UP (memory, hpagesize); +Error *local_err =NULL ;memset (&act,0 ,sizeof (act)); act.sa_handler = &sigbus_handler;
@@ -484,9 +491,9 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, }/* touch pages simultaneously */ -if (touch_all_pages (area, hpagesize, numpages, smp_cpus)) { -error_setg (errp,"os_mem_prealloc: Insufficient free host memory " -"pages available to allocate guest RAM" ); +if (touch_all_pages (area, hpagesize, numpages, smp_cpus, &local_err)) { +error_propagate_prepend (errp, local_err,"os_mem_prealloc: Insufficient" +" free host memory pages available to allocate guest RAM: " ); } ret =sigaction (SIGBUS , &oldact,NULL );
Signature · 1 line
2.13.7
Re: [Qemu-devel] [PATCH for-4.0 v9 15/16] qemu_thread: supplement error handling for touch_all_pages
Quoted 37 lines · Fei Li
Supplement the error handling for
touch_all_pages: add an Error parameter for it to propagate the error to its caller to do the handling in case it fails.Cc Markus Armbruster <[email protected]>Signed-off-by Fei Li <[email protected]>--- util/oslib-posix.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-)util/oslib-posix.c +3
-1@@ -431,15 +431,17 @@ static inline int get_memset_num_threads(int smp_cpus) }static bool touch_all_pages (char *area,size_t hpagesize,size_t numpages, -int smp_cpus) +int smp_cpus,Error **errp) {size_t numpages_per_thread;size_t size_per_thread;char *addr = area;int i =0 ; +int started_thread =0 ; 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,14 +450,18 @@ 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;
util/oslib-posix.c static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, · line 458
Quoted 10 lines
util/oslib-posix.c +6
-4-/* TODO: let the callers handle the error instead of abort() here */ -qemu_thread_create (&memset_thread[i].pgthread,"touch_pages" , - do_touch_pages, &memset_thread[i], -QEMU_THREAD_JOINABLE , &error_abort); +if (!qemu_thread_create (&memset_thread[i].pgthread,"touch_pages" , + do_touch_pages, &memset_thread[i], +QEMU_THREAD_JOINABLE , errp)) { + memset_thread_failed = true; + started_thread = i; + goto out;
break rather than goto, please.
util/oslib-posix.c static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, · line 466
Quoted 9 lines
util/oslib-posix.c +3
-1+ } 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); }
I don't like how @started_thread is computed. The name suggests it's the number of threads started so far. That's the case when you initialize it to zero. But then you immediately set it to memset_thread(). It again becomes the case only when you break the loop on error, or when you complete it successfully.
There's no need for @started_thread, since the number of threads created is readily available as @i:
memset_num_threads = i;
for (i = 0; i < memset_num_threads; i++) {
qemu_thread_join(&memset_thread[i].pgthread);
}Rest of the function:
util/oslib-posix.c static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, · line 467
Quoted 1 line
util/oslib-posix.c +0
-0g_free (memset_thread);
memset_thread = NULL;
return memset_thread_failed;}
If do_touch_pages() set memset_thread_failed(), we return false without setting an error. I believe you should
if (memset_thread_failed) {
error_setg(errp, "os_mem_prealloc: Insufficient free host memory "
"pages available to allocate guest RAM");
return false;
}
return true;here, and ...
Quoted 9 lines
util/oslib-posix.c +1
-0@@ -471,6 +477,7 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,struct sigaction act, oldact;size_t hpagesize =qemu_fd_getpagesize (fd);size_t numpages =DIV_ROUND_UP (memory, hpagesize); +Error *local_err =NULL ;memset (&act,0 ,sizeof (act)); act.sa_handler = &sigbus_handler;
util/oslib-posix.c void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, · line 497
Quoted 10 lines
util/oslib-posix.c +3
-3@@ -484,9 +491,9 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, }/* touch pages simultaneously */ -if (touch_all_pages (area, hpagesize, numpages, smp_cpus)) { -error_setg (errp,"os_mem_prealloc: Insufficient free host memory " -"pages available to allocate guest RAM" ); +if (touch_all_pages (area, hpagesize, numpages, smp_cpus, &local_err)) { +error_propagate_prepend (errp, local_err,"os_mem_prealloc: Insufficient" +" free host memory pages available to allocate guest RAM: " ); }
... not mess with the error message here, i.e.
touch_all_pages(area, hpagesize, numpages, smp_cpus), errp);
Quoted 2 lines
util/oslib-posix.c +0
-0ret =sigaction (SIGBUS , &oldact,NULL );
Re: [Qemu-devel] [PATCH for-4.0 v9 15/16] qemu_thread: supplement error handling for touch_all_pages
Quoted 47 lines · 在 2019年1月8日,02:13,Markus Armbruster <[email protected]> 写道:
Quoted 41 lines · Fei Li
Supplement the error handling for
touch_all_pages: add an Error parameter for it to propagate the error to its caller to do the handling in case it fails.Cc Markus Armbruster <[email protected]>Signed-off-by Fei Li <[email protected]>---
util/oslib-posix.c| 25 ++++++++++++++++---------1 file changed, 16 insertions(+), 9 deletions(-)util/oslib-posix.c +3
-5@@ -431,15 +431,17 @@ static inline int get_memset_num_threads(int smp_cpus) }static bool touch_all_pages (char *area,size_t hpagesize,size_t numpages, -int smp_cpus) +int smp_cpus,Error **errp) {size_t numpages_per_thread;size_t size_per_thread;char *addr = area;int i =0 ; +int started_thread =0 ; 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,14 +450,18 @@ 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; -/* TODO: let the callers handle the error instead of abort() here */ -qemu_thread_create (&memset_thread[i].pgthread,"touch_pages" , - do_touch_pages, &memset_thread[i], -QEMU_THREAD_JOINABLE , &error_abort);
Quoted 8 lines
util/oslib-posix.c static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, · line 458
Quoted 6 lines
util/oslib-posix.c +6
-0+if (!qemu_thread_create (&memset_thread[i].pgthread,"touch_pages" , + do_touch_pages, &memset_thread[i], +QEMU_THREAD_JOINABLE , errp)) { + memset_thread_failed = true; + started_thread = i; + goto out;break rather than goto, please.
Ok
Quoted 17 lines
util/oslib-posix.c static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, · line 466
Quoted 10 lines
util/oslib-posix.c +3
-1+ } 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); }I don't like how @started_thread is computed. The name suggests it's the number of threads started so far. That's the case when you initialize it to zero. But then you immediately set it to
memset_thread(). It again becomes the case only when you break the loop on error, or when you complete it successfully.
Quoted 4 lines
There's no need for @started_thread, since the number of threads created is readily available as @i:
memset_num_threads = i;
Thanks for this wonderful suggestion! This helps a lot! ;)
Quoted 15 lines
for (i = 0; i < memset_num_threads; i++) { qemu_thread_join(&memset_thread[i].pgthread); }Rest of the function:
util/oslib-posix.c static bool touch_all_pages(char *area, size_t hpagesize, size_t numpages, · line 467
Quoted 1 line
util/oslib-posix.c +0
-0g_free (memset_thread);memset_thread = NULL; return memset_thread_failed;}
If
do_touch_pages()setmemset_thread_failed(), we return false without setting an error. I believe you should
Quoted 7 lines
if (memset_thread_failed) {
error_setg(errp, "os_mem_prealloc: Insufficient free host memory "
"pages available to allocate guest RAM");
return false;
}
return true;Ok
Quoted 24 lines
here, and ...
Quoted 9 lines
util/oslib-posix.c +1
-0@@ -471,6 +477,7 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus,struct sigaction act, oldact;size_t hpagesize =qemu_fd_getpagesize (fd);size_t numpages =DIV_ROUND_UP (memory, hpagesize); +Error *local_err =NULL ;memset (&act,0 ,sizeof (act)); act.sa_handler = &sigbus_handler;util/oslib-posix.c void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, · line 497
Quoted 10 lines
util/oslib-posix.c +3
-3@@ -484,9 +491,9 @@ void os_mem_prealloc(int fd, char *area, size_t memory, int smp_cpus, }/* touch pages simultaneously */ -if (touch_all_pages (area, hpagesize, numpages, smp_cpus)) { -error_setg (errp,"os_mem_prealloc: Insufficient free host memory " -"pages available to allocate guest RAM" ); +if (touch_all_pages (area, hpagesize, numpages, smp_cpus, &local_err)) { +error_propagate_prepend (errp, local_err,"os_mem_prealloc: Insufficient" +" free host memory pages available to allocate guest RAM: " ); }... not mess with the error message here, i.e.
Quoted 1 line
touch_all_pages(area, hpagesize, numpages, smp_cpus), errp);
Ok, will amend this in the next version.
Have a nice day, thanks again
Fei
Quoted 3 lines
Quoted 3 lines
util/oslib-posix.c +0
-0ret =sigaction (SIGBUS , &oldact,NULL );
PATCH v9 16/16 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
@@ -571,6 +571,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
@@ -367,7 +367,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
Re: [Qemu-devel] [PATCH for-4.0 v9 16/16] qemu_thread_join: fix segmentation fault
Quoted 17 lines · Fei Li
To avoid the segmentation fault in
qemu_thread_join(), just directly return when the QemuThread *thread failed to be created in eitherqemu-thread-posix.corqemu-thread-win32.c.Cc Stefan Weil <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>--- util/qemu-thread-posix.c | 3 +++ util/qemu-thread-win32.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-)util/qemu-thread-posix.c +0
-0
util/qemu-thread-posix.c void *qemu_thread_join(QemuThread *thread) · line 576
Quoted 6 lines
util/qemu-thread-posix.c +3
-0@@ -571,6 +571,9 @@ void *qemu_thread_join(QemuThread *thread)int err;void *ret; +if (!thread->thread) { +return NULL ; + }
How can this happen?
Quoted 15 lines
util/qemu-thread-posix.c +0
-0err =pthread_join (thread->thread, &ret);if (err) {error_exit (err, __func__);util/qemu-thread-win32.c +1
-1@@ -367,7 +367,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 ; }
Re: [Qemu-devel] [PATCH for-4.0 v9 16/16] qemu_thread_join: fix segmentation fault
Quoted 26 lines · 在 2019年1月8日,01:55,Markus Armbruster <[email protected]> 写道:
Quoted 20 lines · Fei Li
To avoid the segmentation fault in
qemu_thread_join(), just directly return when the QemuThread *thread failed to be created in eitherqemu-thread-posix.corqemu-thread-win32.c.Cc Stefan Weil <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>---
util/qemu-thread-posix.c| 3 +++util/qemu-thread-win32.c| 2 +-2 files changed, 4 insertions(+), 1 deletion(-)util/qemu-thread-posix.c +0
-0@@ -571,6 +571,9 @@ void *qemu_thread_join(QemuThread *thread)int err;void *ret;
Quoted 5 lines
util/qemu-thread-posix.c void *qemu_thread_join(QemuThread *thread) · line 576
Quoted 3 lines
util/qemu-thread-posix.c +3
-0+if (!thread->thread) { +return NULL ; + }How can this happen?
I think I have answered this earlier, please check the following link to see whether it helps:
http://lists.nongnu.org/archive/html/qemu-devel/2018-11/msg06554.html
Have a nice day, thanks
Fei
Quoted 16 lines
Quoted 16 lines
util/qemu-thread-posix.c +0
-0err =pthread_join (thread->thread, &ret);if (err) {error_exit (err, __func__);util/qemu-thread-win32.c +1
-1@@ -367,7 +367,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 ; }
Re: [Qemu-devel] [PATCH for-4.0 v9 16/16] qemu_thread_join: fix segmentation fault
Quoted 24 lines · fei
Quoted 24 lines · 在 2019年1月8日,01:55,Markus Armbruster <[email protected]> 写道:
Quoted 20 lines · Fei Li
To avoid the segmentation fault in
qemu_thread_join(), just directly return when the QemuThread *thread failed to be created in eitherqemu-thread-posix.corqemu-thread-win32.c.Cc Stefan Weil <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>---
util/qemu-thread-posix.c| 3 +++util/qemu-thread-win32.c| 2 +-2 files changed, 4 insertions(+), 1 deletion(-)util/qemu-thread-posix.c +0
-0@@ -571,6 +571,9 @@ void *qemu_thread_join(QemuThread *thread)int err;void *ret;
Quoted 7 lines
Quoted 5 lines
util/qemu-thread-posix.c void *qemu_thread_join(QemuThread *thread) · line 576
Quoted 3 lines
util/qemu-thread-posix.c +3
-0+if (!thread->thread) { +return NULL ; + }How can this happen?
I think I have answered this earlier, please check the following link to see whether it helps:
http://lists.nongnu.org/archive/html/qemu-devel/2018-11/msg06554.html
Thanks for the pointer. Unfortunately, I don't understand your explanation. You also wrote there "I will remove this patch in next version"; looks like you've since changed your mind.
What exactly breaks if we omit this patch? Assuming something does
break: imagine we did omit this patch, then forgot we ever saw it, and now you've discovered the breakage. Write us the bug report, complete with reproducer.
[...]
Re: [Qemu-devel] [PATCH for-4.0 v9 16/16] qemu_thread_join: fix segmentation fault
Quoted 30 lines · Markus Armbruster
Quoted 28 lines · fei
Quoted 28 lines · 在 2019年1月8日,01:55,Markus Armbruster <[email protected]> 写道:
Quoted 17 lines · Fei Li
To avoid the segmentation fault in
qemu_thread_join(), just directly return when the QemuThread *thread failed to be created in eitherqemu-thread-posix.corqemu-thread-win32.c.Cc Stefan Weil <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>---
util/qemu-thread-posix.c| 3 +++util/qemu-thread-win32.c| 2 +-2 files changed, 4 insertions(+), 1 deletion(-)util/qemu-thread-posix.c +0
-0util/qemu-thread-posix.c void *qemu_thread_join(QemuThread *thread) · line 576
Quoted 6 lines
util/qemu-thread-posix.c +3
-0@@ -571,6 +571,9 @@ void *qemu_thread_join(QemuThread *thread)int err;void *ret; +if (!thread->thread) { +return NULL ; + }How can this happen?
Quoted 5 lines
Quoted 2 lines
I think I have answered this earlier, please check the following link to see whether it helps:
http://lists.nongnu.org/archive/html/qemu-devel/2018-11/msg06554.htmlThanks for the pointer. Unfortunately, I don't understand your explanation. You also wrote there "I will remove this patch in next version"; looks like you've since changed your mind.
Emm, issues left over from history.. The background is I was hurry to make those five Reviewed-by patches be merged, including this v9 16/16 patch but not the real qemu_thread_create() modification. But actually this patch is to fix the segmentation fault after we modified qemu_thread_create() related functions although it has got a Reviewed-by earlier. :) Thus to not make troube, I wrote the "remove..." sentence to separate it from those 5 Reviewed-by patches, and were plan to send only four patches. But later I got a message that these five patches are not that urgent to catch qemu v3.1, thus I joined the earlier 5 R-b patches into the later v8 & v9 to have a better review.
Sorry for the trouble, I need to explain it without involving too much background..
Back at the farm: in our current qemu code, some cleanups use a loop to join() the total number of threads if caller fails. This is not a problem until applying the qemu_thread_create() modification. E.g. when compress_threads_save_setup() fails while trying to create the last do_data_compress thread, segmentation fault will occur when join() is called (sadly there's not enough condition to filter this unsuccessful created thread) as this thread is actually not be created.
Hope the above makes it clear. :)
Have a nice day
Fei
Quoted 7 lines
What exactly breaks if we omit this patch? Assuming something does
break: imagine we did omit this patch, then forgot we ever saw it, and now you've discovered the breakage. Write us the bug report, complete with reproducer.[...]
Re: [Qemu-devel] [PATCH for-4.0 v9 16/16] qemu_thread_join: fix segmentation fault
Quoted 67 lines · Fei Li
Quoted 30 lines · Markus Armbruster
Quoted 28 lines · fei
Quoted 28 lines · 在 2019年1月8日,01:55,Markus Armbruster <[email protected]> 写道:
Quoted 17 lines · Fei Li
To avoid the segmentation fault in
qemu_thread_join(), just directly return when the QemuThread *thread failed to be created in eitherqemu-thread-posix.corqemu-thread-win32.c.Cc Stefan Weil <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>---
util/qemu-thread-posix.c| 3 +++util/qemu-thread-win32.c| 2 +-2 files changed, 4 insertions(+), 1 deletion(-)util/qemu-thread-posix.c +0
-0util/qemu-thread-posix.c void *qemu_thread_join(QemuThread *thread) · line 576
Quoted 6 lines
util/qemu-thread-posix.c +3
-0@@ -571,6 +571,9 @@ void *qemu_thread_join(QemuThread *thread)int err;void *ret; +if (!thread->thread) { +return NULL ; + }How can this happen?
Quoted 5 lines
Quoted 2 lines
I think I have answered this earlier, please check the following link to see whether it helps:
http://lists.nongnu.org/archive/html/qemu-devel/2018-11/msg06554.htmlThanks for the pointer. Unfortunately, I don't understand your explanation. You also wrote there "I will remove this patch in next version"; looks like you've since changed your mind.
Emm, issues left over from history.. The background is I was hurry to make those five
Reviewed-by patches be merged, including this v9 16/16 patch but not the realqemu_thread_create()modification. But actually this patch is to fix the segmentation
fault after we modifiedqemu_thread_create()related functions although it has got a
Reviewed-by earlier. :) Thus to not make troube, I wrote the "remove..." sentence
to separate it from those 5 Reviewed-by patches, and were plan to send only four patches.
But later I got a message that these five patches are not that urgent to catch qemu v3.1,
thus I joined the earlier 5 R-b patches into the later v8 & v9 to have a better review.Sorry for the trouble, I need to explain it without involving too much background..
Back at the farm: in our current qemu code, some cleanups use a loop to
join()
the total number of threads if caller fails. This is not a problem until applying theqemu_thread_create()modification. E.g. whencompress_threads_save_setup()fails while trying to create the lastdo_data_compressthread, segmentation fault
will occur whenjoin()is called (sadly there's not enough condition to filter this
unsuccessful created thread) as this thread is actually not be created.
Quoted 1 line
Hope the above makes it clear. :)
Alright, let's have a look at compress_threads_save_setup():
static int compress_threads_save_setup(void)
{
int i, thread_count;
if (!migrate_use_compression()) {
return 0;
}
thread_count = migrate_compress_threads();
compress_threads = g_new0(QemuThread, thread_count);
comp_param = g_new0(CompressParam, thread_count);
qemu_cond_init(&comp_done_cond);
qemu_mutex_init(&comp_done_lock);
for (i = 0; i < thread_count; i++) {
comp_param[i].originbuf = g_try_malloc(TARGET_PAGE_SIZE);
if (!comp_param[i].originbuf) {
goto exit;
}
if (deflateInit(&comp_param[i].stream,
migrate_compress_level()) != Z_OK) {
g_free(comp_param[i].originbuf);
goto exit;
}
/* comp_param[i].file is just used as a dummy buffer to save data,
* set its ops to empty.
*/
comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops);
comp_param[i].done = true;
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);
}
return 0;
exit:
compress_threads_save_cleanup();
return -1;
}At label exit, we have @i threads, all fully initialized. That's an invariant.
compress_threads_save_cleanup() finds the threads to clean up by checking comp_param[i].file:
static void compress_threads_save_cleanup(void)
{
int i, thread_count;
if (!migrate_use_compression() || !comp_param) {
return;
}
thread_count = migrate_compress_threads();
for (i = 0; i < thread_count; i++) {
/*
* we use it as a indicator which shows if the thread is
* properly init'd or not
*/---> if (!comp_param[i].file) {
---> break;
---> }
qemu_mutex_lock(&comp_param[i].mutex);
comp_param[i].quit = true;
qemu_cond_signal(&comp_param[i].cond);
qemu_mutex_unlock(&comp_param[i].mutex);
qemu_thread_join(compress_threads + i);
qemu_mutex_destroy(&comp_param[i].mutex);
qemu_cond_destroy(&comp_param[i].cond);
deflateEnd(&comp_param[i].stream);
g_free(comp_param[i].originbuf);
qemu_fclose(comp_param[i].file);
comp_param[i].file = NULL;
}
qemu_mutex_destroy(&comp_done_lock);
qemu_cond_destroy(&comp_done_cond);
g_free(compress_threads);
g_free(comp_param);
compress_threads = NULL;
comp_param = NULL;
}Due to the invariant, a comp_param[i] with a null .file doesn't need *any* cleanup.
To maintain the invariant, compress_threads_save_setup() carefully cleans up any partial initializations itself before a goto exit. Since the code is arranged smartly, the only such cleanup is the g_free(comp_param[i].originbuf) before the second goto exit.
Your PATCH 13 adds a third goto exit, but neglects to clean up partial initializations. Breaks the invariant.
I see two sane solutions:
1. compress_threads_save_setup() carefully cleans up partial initializations itself. compress_threads_save_cleanup() copes only with fully initialized comp_param[i]. This is how things work before your series.
2. compress_threads_save_cleanup() copes with partially initialized comp_param[i], i.e. does the right thing for each goto exit in compress_threads_save_setup(). compress_threads_save_setup() doesn't clean up partial initializations.
Your PATCH 13 together with the fixup PATCH 16 does
3. A confusing mix of the two.
Don't.
Quoted 9 lines
Have a nice day
FeiQuoted 7 lines
What exactly breaks if we omit this patch? Assuming something does
break: imagine we did omit this patch, then forgot we ever saw it, and now you've discovered the breakage. Write us the bug report, complete with reproducer.[...]
Re: [Qemu-devel] [PATCH for-4.0 v9 16/16] qemu_thread_join: fix segmentation fault
Quoted 188 lines · 在 2019年1月9日,23:24,Markus Armbruster <[email protected]> 写道:
Quoted 67 lines · Fei Li
Quoted 31 lines · Markus Armbruster
Quoted 28 lines · fei
Quoted 28 lines · 在 2019年1月8日,01:55,Markus Armbruster <[email protected]> 写道:
Quoted 17 lines · Fei Li
To avoid the segmentation fault in
qemu_thread_join(), just directly return when the QemuThread *thread failed to be created in eitherqemu-thread-posix.corqemu-thread-win32.c.Cc Stefan Weil <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>---
util/qemu-thread-posix.c| 3 +++util/qemu-thread-win32.c| 2 +-2 files changed, 4 insertions(+), 1 deletion(-)util/qemu-thread-posix.c +0
-0util/qemu-thread-posix.c void *qemu_thread_join(QemuThread *thread) · line 576
Quoted 6 lines
util/qemu-thread-posix.c +3
-0@@ -571,6 +571,9 @@ void *qemu_thread_join(QemuThread *thread)int err;void *ret; +if (!thread->thread) { +return NULL ; + }How can this happen?
Quoted 5 lines
Quoted 2 lines
I think I have answered this earlier, please check the following link to see whether it helps:
http://lists.nongnu.org/archive/html/qemu-devel/2018-11/msg06554.htmlThanks for the pointer. Unfortunately, I don't understand your explanation. You also wrote there "I will remove this patch in next version"; looks like you've since changed your mind.
Emm, issues left over from history.. The background is I was hurry to make those five
Reviewed-by patches be merged, including this v9 16/16 patch but not the realqemu_thread_create()modification. But actually this patch is to fix the segmentation
fault after we modifiedqemu_thread_create()related functions although it has got a
Reviewed-by earlier. :) Thus to not make troube, I wrote the "remove..." sentence
to separate it from those 5 Reviewed-by patches, and were plan to send only four patches.
But later I got a message that these five patches are not that urgent to catch qemu v3.1,
thus I joined the earlier 5 R-b patches into the later v8 & v9 to have a better review.Sorry for the trouble, I need to explain it without involving too much background..
Back at the farm: in our current qemu code, some cleanups use a loop to
join()
the total number of threads if caller fails. This is not a problem until applying theqemu_thread_create()modification. E.g. whencompress_threads_save_setup()fails while trying to create the lastdo_data_compressthread, segmentation fault
will occur whenjoin()is called (sadly there's not enough condition to filter this
unsuccessful created thread) as this thread is actually not be created.Quoted 1 line
Hope the above makes it clear. :)
Alright, let's have a look at
compress_threads_save_setup():static int compress_threads_save_setup(void) { int i, thread_count;if (!migrate_use_compression()) { return 0; } thread_count = migrate_compress_threads(); compress_threads = g_new0(QemuThread, thread_count); comp_param = g_new0(CompressParam, thread_count); qemu_cond_init(&comp_done_cond); qemu_mutex_init(&comp_done_lock); for (i = 0; i < thread_count; i++) { comp_param[i].originbuf = g_try_malloc(TARGET_PAGE_SIZE); if (!comp_param[i].originbuf) { goto exit; } if (deflateInit(&comp_param[i].stream, migrate_compress_level()) != Z_OK) { g_free(comp_param[i].originbuf); goto exit; } /* comp_param[i].file is just used as a dummy buffer to save data, * set its ops to empty. */ comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops); comp_param[i].done = true; 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); } return 0;exit: compress_threads_save_cleanup(); return -1; }At label exit, we have @i threads, all fully initialized. That's an invariant.
compress_threads_save_cleanup()finds the threads to clean up by checking comp_param[i].file:static void compress_threads_save_cleanup(void) { int i, thread_count;if (!migrate_use_compression() || !comp_param) { return; } thread_count = migrate_compress_threads(); for (i = 0; i < thread_count; i++) { /* * we use it as a indicator which shows if the thread is * properly init'd or not */---> if (!comp_param[i].file) {
---> break;
---> }qemu_mutex_lock(&comp_param[i].mutex); comp_param[i].quit = true; qemu_cond_signal(&comp_param[i].cond); qemu_mutex_unlock(&comp_param[i].mutex); qemu_thread_join(compress_threads + i); qemu_mutex_destroy(&comp_param[i].mutex); qemu_cond_destroy(&comp_param[i].cond); deflateEnd(&comp_param[i].stream); g_free(comp_param[i].originbuf); qemu_fclose(comp_param[i].file); comp_param[i].file = NULL; } qemu_mutex_destroy(&comp_done_lock); qemu_cond_destroy(&comp_done_cond); g_free(compress_threads); g_free(comp_param); compress_threads = NULL; comp_param = NULL;}
Due to the invariant, a comp_param[i] with a null .file doesn't need *any* cleanup.
To maintain the invariant,
compress_threads_save_setup()carefully cleans up any partial initializations itself before a goto exit. Since the code is arranged smartly, the only such cleanup is theg_free(comp_param[i].originbuf)before the second goto exit.Your PATCH 13 adds a third goto exit, but neglects to clean up partial initializations. Breaks the invariant.
I see two sane solutions:
1.
compress_threads_save_setup()carefully cleans up partial initializations itself.compress_threads_save_cleanup()copes only with fully initialized comp_param[i]. This is how things work before your series.2.
compress_threads_save_cleanup()copes with partially initialized comp_param[i], i.e. does the right thing for each goto exit incompress_threads_save_setup().compress_threads_save_setup()doesn't clean up partial initializations.
Quoted 5 lines
Your PATCH 13 together with the fixup PATCH 16 does
3. A confusing mix of the two.
Don't.
Thanks for the detail analysis! :)
Emm.. Actually I have thought to do the cleanup in the setup() function for the third ‘goto exit’ [1], which is a partial initialization.
But due to the below [1] is too long and seems not neat (I notice that most cleanups for each thread are in the xxx_cleanup() function), I turned to modify the join() function.. Is the long [1] acceptable when the third ‘goto exit’ is called, or is there any other better way to do the cleanup?
[1]
qemu_mutex_lock(&comp_param[i].mutex);
comp_param[i].quit = true;
qemu_cond_signal(&comp_param[i].cond);
qemu_mutex_unlock(&comp_param[i].mutex);qemu_mutex_destroy(&comp_param[i].mutex);
qemu_cond_destroy(&comp_param[i].cond);
deflateEnd(&comp_param[i].stream);
g_free(comp_param[i].originbuf);
qemu_fclose(comp_param[i].file);
comp_param[i].file = NULL;Have a nice day, thanks
Fei
Quoted 10 lines
Quoted 10 lines
Have a nice day
FeiQuoted 7 lines
What exactly breaks if we omit this patch? Assuming something does
break: imagine we did omit this patch, then forgot we ever saw it, and now you've discovered the breakage. Write us the bug report, complete with reproducer.[...]
Re: [Qemu-devel] [PATCH for-4.0 v9 16/16] qemu_thread_join: fix segmentation fault
Quoted 202 lines · fei
Quoted 186 lines · 在 2019年1月9日,23:24,Markus Armbruster <[email protected]> 写道:
Quoted 67 lines · Fei Li
Quoted 31 lines · Markus Armbruster
Quoted 28 lines · fei
Quoted 28 lines · 在 2019年1月8日,01:55,Markus Armbruster <[email protected]> 写道:
Quoted 17 lines · Fei Li
To avoid the segmentation fault in
qemu_thread_join(), just directly return when the QemuThread *thread failed to be created in eitherqemu-thread-posix.corqemu-thread-win32.c.Cc Stefan Weil <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>---
util/qemu-thread-posix.c| 3 +++util/qemu-thread-win32.c| 2 +-2 files changed, 4 insertions(+), 1 deletion(-)util/qemu-thread-posix.c +0
-0util/qemu-thread-posix.c void *qemu_thread_join(QemuThread *thread) · line 576
Quoted 6 lines
util/qemu-thread-posix.c +3
-0@@ -571,6 +571,9 @@ void *qemu_thread_join(QemuThread *thread)int err;void *ret; +if (!thread->thread) { +return NULL ; + }How can this happen?
Quoted 5 lines
Quoted 2 lines
I think I have answered this earlier, please check the following link to see whether it helps:
http://lists.nongnu.org/archive/html/qemu-devel/2018-11/msg06554.htmlThanks for the pointer. Unfortunately, I don't understand your explanation. You also wrote there "I will remove this patch in next version"; looks like you've since changed your mind.
Emm, issues left over from history.. The background is I was hurry to make those five
Reviewed-by patches be merged, including this v9 16/16 patch but not the realqemu_thread_create()modification. But actually this patch is to fix the segmentation
fault after we modifiedqemu_thread_create()related functions although it has got a
Reviewed-by earlier. :) Thus to not make troube, I wrote the "remove..." sentence
to separate it from those 5 Reviewed-by patches, and were plan to send only four patches.
But later I got a message that these five patches are not that urgent to catch qemu v3.1,
thus I joined the earlier 5 R-b patches into the later v8 & v9 to have a better review.Sorry for the trouble, I need to explain it without involving too much background..
Back at the farm: in our current qemu code, some cleanups use a loop to
join()
the total number of threads if caller fails. This is not a problem until applying theqemu_thread_create()modification. E.g. whencompress_threads_save_setup()fails while trying to create the lastdo_data_compressthread, segmentation fault
will occur whenjoin()is called (sadly there's not enough condition to filter this
unsuccessful created thread) as this thread is actually not be created.Quoted 1 line
Hope the above makes it clear. :)
Alright, let's have a look at
compress_threads_save_setup():static int compress_threads_save_setup(void) { int i, thread_count;if (!migrate_use_compression()) { return 0; } thread_count = migrate_compress_threads(); compress_threads = g_new0(QemuThread, thread_count); comp_param = g_new0(CompressParam, thread_count); qemu_cond_init(&comp_done_cond); qemu_mutex_init(&comp_done_lock); for (i = 0; i < thread_count; i++) { comp_param[i].originbuf = g_try_malloc(TARGET_PAGE_SIZE); if (!comp_param[i].originbuf) { goto exit; } if (deflateInit(&comp_param[i].stream, migrate_compress_level()) != Z_OK) { g_free(comp_param[i].originbuf); goto exit; } /* comp_param[i].file is just used as a dummy buffer to save data, * set its ops to empty. */ comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops); comp_param[i].done = true; 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); } return 0;exit: compress_threads_save_cleanup(); return -1; }At label exit, we have @i threads, all fully initialized. That's an invariant.
compress_threads_save_cleanup()finds the threads to clean up by checking comp_param[i].file:static void compress_threads_save_cleanup(void) { int i, thread_count;if (!migrate_use_compression() || !comp_param) { return; } thread_count = migrate_compress_threads(); for (i = 0; i < thread_count; i++) { /* * we use it as a indicator which shows if the thread is * properly init'd or not */---> if (!comp_param[i].file) {
---> break;
---> }qemu_mutex_lock(&comp_param[i].mutex); comp_param[i].quit = true; qemu_cond_signal(&comp_param[i].cond); qemu_mutex_unlock(&comp_param[i].mutex); qemu_thread_join(compress_threads + i); qemu_mutex_destroy(&comp_param[i].mutex); qemu_cond_destroy(&comp_param[i].cond); deflateEnd(&comp_param[i].stream); g_free(comp_param[i].originbuf); qemu_fclose(comp_param[i].file); comp_param[i].file = NULL; } qemu_mutex_destroy(&comp_done_lock); qemu_cond_destroy(&comp_done_cond); g_free(compress_threads); g_free(comp_param); compress_threads = NULL; comp_param = NULL;}
Due to the invariant, a comp_param[i] with a null .file doesn't need *any* cleanup.
To maintain the invariant,
compress_threads_save_setup()carefully cleans up any partial initializations itself before a goto exit. Since the code is arranged smartly, the only such cleanup is theg_free(comp_param[i].originbuf)before the second goto exit.Your PATCH 13 adds a third goto exit, but neglects to clean up partial initializations. Breaks the invariant.
I see two sane solutions:
1.
compress_threads_save_setup()carefully cleans up partial initializations itself.compress_threads_save_cleanup()copes only with fully initialized comp_param[i]. This is how things work before your series.2.
compress_threads_save_cleanup()copes with partially initialized comp_param[i], i.e. does the right thing for each goto exit incompress_threads_save_setup().compress_threads_save_setup()doesn't clean up partial initializations.Quoted 5 lines
Your PATCH 13 together with the fixup PATCH 16 does
3. A confusing mix of the two.
Don't.
Thanks for the detail analysis! :)
Emm.. Actually I have thought to do the cleanup in thesetup()function for the third ‘goto exit’ [1], which is a partial initialization.
But due to the below [1] is too long and seems not neat (I notice that most cleanups for each thread are in thexxx_cleanup()function), I turned to modify thejoin()function.. Is the long [1] acceptable when the third ‘goto exit’ is called, or is there any other better way to do the cleanup?[1]
qemu_mutex_lock(&comp_param[i].mutex); comp_param[i].quit = true; qemu_cond_signal(&comp_param[i].cond); qemu_mutex_unlock(&comp_param[i].mutex);
Quoted 6 lines
qemu_mutex_destroy(&comp_param[i].mutex);
qemu_cond_destroy(&comp_param[i].cond);
deflateEnd(&comp_param[i].stream);
g_free(comp_param[i].originbuf);
qemu_fclose(comp_param[i].file);
comp_param[i].file = NULL;Have you considered creating the thread earlier, e.g. right after initializing compression with deflateInit()?
Re: [Qemu-devel] [PATCH for-4.0 v9 16/16] qemu_thread_join: fix segmentation fault
Quoted 203 lines · Markus Armbruster
Quoted 201 lines · fei
Quoted 185 lines · 在 2019年1月9日,23:24,Markus Armbruster <[email protected]> 写道:
Quoted 67 lines · Fei Li
Quoted 31 lines · Markus Armbruster
Quoted 28 lines · fei
Quoted 28 lines · 在 2019年1月8日,01:55,Markus Armbruster <[email protected]> 写道:
Quoted 17 lines · Fei Li
To avoid the segmentation fault in
qemu_thread_join(), just directly return when the QemuThread *thread failed to be created in eitherqemu-thread-posix.corqemu-thread-win32.c.Cc Stefan Weil <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>---
util/qemu-thread-posix.c| 3 +++util/qemu-thread-win32.c| 2 +-2 files changed, 4 insertions(+), 1 deletion(-)util/qemu-thread-posix.c +0
-0util/qemu-thread-posix.c void *qemu_thread_join(QemuThread *thread) · line 576
Quoted 6 lines
util/qemu-thread-posix.c +3
-0@@ -571,6 +571,9 @@ void *qemu_thread_join(QemuThread *thread)int err;void *ret; +if (!thread->thread) { +return NULL ; + }How can this happen?
Quoted 5 lines
Quoted 2 lines
I think I have answered this earlier, please check the following link to see whether it helps:
http://lists.nongnu.org/archive/html/qemu-devel/2018-11/msg06554.htmlThanks for the pointer. Unfortunately, I don't understand your explanation. You also wrote there "I will remove this patch in next version"; looks like you've since changed your mind.
Emm, issues left over from history.. The background is I was hurry to make those five
Reviewed-by patches be merged, including this v9 16/16 patch but not the realqemu_thread_create()modification. But actually this patch is to fix the segmentation
fault after we modifiedqemu_thread_create()related functions although it has got a
Reviewed-by earlier. :) Thus to not make troube, I wrote the "remove..." sentence
to separate it from those 5 Reviewed-by patches, and were plan to send only four patches.
But later I got a message that these five patches are not that urgent to catch qemu v3.1,
thus I joined the earlier 5 R-b patches into the later v8 & v9 to have a better review.Sorry for the trouble, I need to explain it without involving too much background..
Back at the farm: in our current qemu code, some cleanups use a loop to
join()
the total number of threads if caller fails. This is not a problem until applying theqemu_thread_create()modification. E.g. whencompress_threads_save_setup()fails while trying to create the lastdo_data_compressthread, segmentation fault
will occur whenjoin()is called (sadly there's not enough condition to filter this
unsuccessful created thread) as this thread is actually not be created.Quoted 1 line
Hope the above makes it clear. :)
Alright, let's have a look at
compress_threads_save_setup():static int compress_threads_save_setup(void) { int i, thread_count; if (!migrate_use_compression()) { return 0; } thread_count = migrate_compress_threads(); compress_threads = g_new0(QemuThread, thread_count); comp_param = g_new0(CompressParam, thread_count); qemu_cond_init(&comp_done_cond); qemu_mutex_init(&comp_done_lock); for (i = 0; i < thread_count; i++) { comp_param[i].originbuf = g_try_malloc(TARGET_PAGE_SIZE); if (!comp_param[i].originbuf) { goto exit; } if (deflateInit(&comp_param[i].stream, migrate_compress_level()) != Z_OK) { g_free(comp_param[i].originbuf); goto exit; } /* comp_param[i].file is just used as a dummy buffer to save data, * set its ops to empty. */ comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops); comp_param[i].done = true; 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); } return 0; exit: compress_threads_save_cleanup(); return -1; }At label exit, we have @i threads, all fully initialized. That's an invariant.
compress_threads_save_cleanup()finds the threads to clean up by checking comp_param[i].file:static void compress_threads_save_cleanup(void) { int i, thread_count; if (!migrate_use_compression() || !comp_param) { return; } thread_count = migrate_compress_threads(); for (i = 0; i < thread_count; i++) { /* * we use it as a indicator which shows if the thread is * properly init'd or not */---> if (!comp_param[i].file) {
---> break;
---> }qemu_mutex_lock(&comp_param[i].mutex); comp_param[i].quit = true; qemu_cond_signal(&comp_param[i].cond); qemu_mutex_unlock(&comp_param[i].mutex); qemu_thread_join(compress_threads + i); qemu_mutex_destroy(&comp_param[i].mutex); qemu_cond_destroy(&comp_param[i].cond); deflateEnd(&comp_param[i].stream); g_free(comp_param[i].originbuf); qemu_fclose(comp_param[i].file); comp_param[i].file = NULL; } qemu_mutex_destroy(&comp_done_lock); qemu_cond_destroy(&comp_done_cond); g_free(compress_threads); g_free(comp_param); compress_threads = NULL; comp_param = NULL; }Due to the invariant, a comp_param[i] with a null .file doesn't need *any* cleanup.
To maintain the invariant,
compress_threads_save_setup()carefully cleans up any partial initializations itself before a goto exit. Since the code is arranged smartly, the only such cleanup is theg_free(comp_param[i].originbuf)before the second goto exit.Your PATCH 13 adds a third goto exit, but neglects to clean up partial initializations. Breaks the invariant.
I see two sane solutions:
1.
compress_threads_save_setup()carefully cleans up partial initializations itself.compress_threads_save_cleanup()copes only with fully initialized comp_param[i]. This is how things work before your series.2.
compress_threads_save_cleanup()copes with partially initialized comp_param[i], i.e. does the right thing for each goto exit incompress_threads_save_setup().compress_threads_save_setup()doesn't clean up partial initializations.Quoted 5 lines
Your PATCH 13 together with the fixup PATCH 16 does
3. A confusing mix of the two.
Don't.
Thanks for the detail analysis! :)
Emm.. Actually I have thought to do the cleanup in thesetup()function for the third ‘goto exit’ [1], which is a partial initialization.
But due to the below [1] is too long and seems not neat (I notice that most cleanups for each thread are in thexxx_cleanup()function), I turned to modify thejoin()function.. Is the long [1] acceptable when the third ‘goto exit’ is called, or is there any other better way to do the cleanup?[1]
qemu_mutex_lock(&comp_param[i].mutex); comp_param[i].quit = true; qemu_cond_signal(&comp_param[i].cond); qemu_mutex_unlock(&comp_param[i].mutex);
Quoted 8 lines
Quoted 6 lines
qemu_mutex_destroy(&comp_param[i].mutex); qemu_cond_destroy(&comp_param[i].cond); deflateEnd(&comp_param[i].stream); g_free(comp_param[i].originbuf); qemu_fclose(comp_param[i].file); comp_param[i].file = NULL;Have you considered creating the thread earlier, e.g. right after initializing compression with
deflateInit()?
I am afraid we can not do this, as the members of comp_param[i], like file/done/quit/mutex/cond will be used later in the new created thread: do_data_[de]compress via qemu_thread_create().
Thus it seems we have to accept the above long [1] if we do want to clean up partial initialization in xxx_setup(). :(
BTW, there is no other argument can be used except the "(compress_threads+i)->thread" to differentiate whether should we join() the thread, just in case we want to change the xxx_cleanup() function.
*
*
Have a nice day, thanks
Fei
Re: [Qemu-devel] [PATCH for-4.0 v9 16/16] qemu_thread_join: fix segmentation fault
Quoted 210 lines · Fei Li
Quoted 209 lines · Markus Armbruster
Quoted 207 lines · fei
Quoted 185 lines · 在 2019年1月9日,23:24,Markus Armbruster <[email protected]> 写道:
Quoted 67 lines · Fei Li
Quoted 31 lines · Markus Armbruster
Quoted 28 lines · fei
Quoted 28 lines · 在 2019年1月8日,01:55,Markus Armbruster <[email protected]> 写道:
Quoted 17 lines · Fei Li
To avoid the segmentation fault in
qemu_thread_join(), just directly return when the QemuThread *thread failed to be created in eitherqemu-thread-posix.corqemu-thread-win32.c.Cc Stefan Weil <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>---
util/qemu-thread-posix.c| 3 +++util/qemu-thread-win32.c| 2 +-2 files changed, 4 insertions(+), 1 deletion(-)util/qemu-thread-posix.c +0
-0util/qemu-thread-posix.c void *qemu_thread_join(QemuThread *thread) · line 576
Quoted 6 lines
util/qemu-thread-posix.c +3
-0@@ -571,6 +571,9 @@ void *qemu_thread_join(QemuThread *thread)int err;void *ret; +if (!thread->thread) { +return NULL ; + }How can this happen?
Quoted 5 lines
Quoted 2 lines
I think I have answered this earlier, please check the following link to see whether it helps:
http://lists.nongnu.org/archive/html/qemu-devel/2018-11/msg06554.htmlThanks for the pointer. Unfortunately, I don't understand your explanation. You also wrote there "I will remove this patch in next version"; looks like you've since changed your mind.
Emm, issues left over from history.. The background is I was hurry to make those five
Reviewed-by patches be merged, including this v9 16/16 patch but not the realqemu_thread_create()modification. But actually this patch is to fix the segmentation
fault after we modifiedqemu_thread_create()related functions although it has got a
Reviewed-by earlier. :) Thus to not make troube, I wrote the "remove..." sentence
to separate it from those 5 Reviewed-by patches, and were plan to send only four patches.
But later I got a message that these five patches are not that urgent to catch qemu v3.1,
thus I joined the earlier 5 R-b patches into the later v8 & v9 to have a better review.Sorry for the trouble, I need to explain it without involving too much background..
Back at the farm: in our current qemu code, some cleanups use a loop to
join()
the total number of threads if caller fails. This is not a problem until applying theqemu_thread_create()modification. E.g. whencompress_threads_save_setup()fails while trying to create the lastdo_data_compressthread, segmentation fault
will occur whenjoin()is called (sadly there's not enough condition to filter this
unsuccessful created thread) as this thread is actually not be created.Quoted 1 line
Hope the above makes it clear. :)
Alright, let's have a look at
compress_threads_save_setup():static int compress_threads_save_setup(void) { int i, thread_count; if (!migrate_use_compression()) { return 0; } thread_count = migrate_compress_threads(); compress_threads = g_new0(QemuThread, thread_count); comp_param = g_new0(CompressParam, thread_count); qemu_cond_init(&comp_done_cond); qemu_mutex_init(&comp_done_lock); for (i = 0; i < thread_count; i++) { comp_param[i].originbuf = g_try_malloc(TARGET_PAGE_SIZE); if (!comp_param[i].originbuf) { goto exit; } if (deflateInit(&comp_param[i].stream, migrate_compress_level()) != Z_OK) { g_free(comp_param[i].originbuf); goto exit; } /* comp_param[i].file is just used as a dummy buffer to save data, * set its ops to empty. */ comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops); comp_param[i].done = true; 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); } return 0; exit: compress_threads_save_cleanup(); return -1; }At label exit, we have @i threads, all fully initialized. That's an invariant.
compress_threads_save_cleanup()finds the threads to clean up by checking comp_param[i].file:static void compress_threads_save_cleanup(void) { int i, thread_count; if (!migrate_use_compression() || !comp_param) { return; } thread_count = migrate_compress_threads(); for (i = 0; i < thread_count; i++) { /* * we use it as a indicator which shows if the thread is * properly init'd or not */---> if (!comp_param[i].file) {
---> break;
---> }qemu_mutex_lock(&comp_param[i].mutex); comp_param[i].quit = true; qemu_cond_signal(&comp_param[i].cond); qemu_mutex_unlock(&comp_param[i].mutex); qemu_thread_join(compress_threads + i); qemu_mutex_destroy(&comp_param[i].mutex); qemu_cond_destroy(&comp_param[i].cond); deflateEnd(&comp_param[i].stream); g_free(comp_param[i].originbuf); qemu_fclose(comp_param[i].file); comp_param[i].file = NULL; } qemu_mutex_destroy(&comp_done_lock); qemu_cond_destroy(&comp_done_cond); g_free(compress_threads); g_free(comp_param); compress_threads = NULL; comp_param = NULL; }Due to the invariant, a comp_param[i] with a null .file doesn't need *any* cleanup.
To maintain the invariant,
compress_threads_save_setup()carefully cleans up any partial initializations itself before a goto exit. Since the code is arranged smartly, the only such cleanup is theg_free(comp_param[i].originbuf)before the second goto exit.Your PATCH 13 adds a third goto exit, but neglects to clean up partial initializations. Breaks the invariant.
I see two sane solutions:
1.
compress_threads_save_setup()carefully cleans up partial initializations itself.compress_threads_save_cleanup()copes only with fully initialized comp_param[i]. This is how things work before your series.2.
compress_threads_save_cleanup()copes with partially initialized comp_param[i], i.e. does the right thing for each goto exit incompress_threads_save_setup().compress_threads_save_setup()doesn't clean up partial initializations.Quoted 5 lines
Your PATCH 13 together with the fixup PATCH 16 does
3. A confusing mix of the two.
Don't.
Thanks for the detail analysis! :)
Emm.. Actually I have thought to do the cleanup in thesetup()function for the third ‘goto exit’ [1], which is a partial initialization.
But due to the below [1] is too long and seems not neat (I notice that most cleanups for each thread are in thexxx_cleanup()function), I turned to modify thejoin()function.. Is the long [1] acceptable when the third ‘goto exit’ is called, or is there any other better way to do the cleanup?[1]
qemu_mutex_lock(&comp_param[i].mutex); comp_param[i].quit = true; qemu_cond_signal(&comp_param[i].cond); qemu_mutex_unlock(&comp_param[i].mutex);qemu_mutex_destroy(&comp_param[i].mutex); qemu_cond_destroy(&comp_param[i].cond); deflateEnd(&comp_param[i].stream); g_free(comp_param[i].originbuf); qemu_fclose(comp_param[i].file); comp_param[i].file = NULL;
Quoted 6 lines
Quoted 2 lines
Have you considered creating the thread earlier, e.g. right after initializing compression with
deflateInit()?I am afraid we can not do this, as the members of comp_param[i], like file/done/quit/mutex/cond
will be used later in the new created thread: do_data_[de]compress viaqemu_thread_create().
You're right.
Quoted 9 lines
Thus it seems we have to accept the above long [1] if we do want to clean up partial initialization
inxxx_setup(). :(BTW, there is no other argument can be used except the "(compress_threads+i)->thread" to
differentiate whether should wejoin()the thread, just in case we want to change thexxx_cleanup()function.
We can try to make compress_threads_save_cleanup() cope with partially initialized comp_param[i]. Let's have a look at its members:
bool done; // no cleanup
bool quit; // see [2]
bool zero_page; // no cleanup
QEMUFile *file; // qemu_fclose() if non-null
QemuMutex mutex; // see [1]
QemuCond cond; // see [1]
RAMBlock *block; // no cleanup (must be null)
ram_addr_t offset; // no cleanup /* internally used fields */
z_stream stream; // see [3]
uint8_t *originbuf; // unconditional g_free()
[1]: we could do something like
if (comp_param[i].mutex.initialized) {
qemu_mutex_destroy(&comp_param[i].mutex);
}
if (comp_param[i].cond.initialized) {
qemu_cond_destroy(&comp_param[i].cond);
}but that would be unclean. Instead, I'd initialize these guys first, so we can clean them up unconditionally.
[2] This is used to make the thread terminate. Must be done before we call qemu_thread_join(). I think it can safely be done always, as long as long as .mutex and .cond are initialized. Trivial if we initialize them first.
[3]: I can't see a squeaky clean way to detect whether .stream has been initialized with deflateInit(). Here's a slightly unclean way:deflateInit() sets .stream.msg to null on success, and to non-null on failure. We can make it non-null until we're ready to call deflateInit(), then have compress_threads_save_cleanup() clean up .stream when it's null. If that's too unclean for your or your reviewers' taste, add a boolean @stream_initialized flag.
Re: [Qemu-devel] [PATCH for-4.0 v9 16/16] qemu_thread_join: fix segmentation fault
Quoted 254 lines · Markus Armbruster
Quoted 210 lines · Fei Li
Quoted 209 lines · Markus Armbruster
Quoted 207 lines · fei
Quoted 185 lines · 在 2019年1月9日,23:24,Markus Armbruster <[email protected]> 写道:
Quoted 67 lines · Fei Li
Quoted 31 lines · Markus Armbruster
Quoted 28 lines · fei
Quoted 28 lines · 在 2019年1月8日,01:55,Markus Armbruster <[email protected]> 写道:
Quoted 17 lines · Fei Li
To avoid the segmentation fault in
qemu_thread_join(), just directly return when the QemuThread *thread failed to be created in eitherqemu-thread-posix.corqemu-thread-win32.c.Cc Stefan Weil <[email protected]>Signed-off-by Fei Li <[email protected]>Reviewed-by Fam Zheng <[email protected]>---
util/qemu-thread-posix.c| 3 +++util/qemu-thread-win32.c| 2 +-2 files changed, 4 insertions(+), 1 deletion(-)util/qemu-thread-posix.c +0
-0util/qemu-thread-posix.c void *qemu_thread_join(QemuThread *thread) · line 576
Quoted 6 lines
util/qemu-thread-posix.c +3
-0@@ -571,6 +571,9 @@ void *qemu_thread_join(QemuThread *thread)int err;void *ret; +if (!thread->thread) { +return NULL ; + }How can this happen?
Quoted 5 lines
Quoted 2 lines
I think I have answered this earlier, please check the following link to see whether it helps:
http://lists.nongnu.org/archive/html/qemu-devel/2018-11/msg06554.htmlThanks for the pointer. Unfortunately, I don't understand your explanation. You also wrote there "I will remove this patch in next version"; looks like you've since changed your mind.
Emm, issues left over from history.. The background is I was hurry to make those five
Reviewed-by patches be merged, including this v9 16/16 patch but not the realqemu_thread_create()modification. But actually this patch is to fix the segmentation
fault after we modifiedqemu_thread_create()related functions although it has got a
Reviewed-by earlier. :) Thus to not make troube, I wrote the "remove..." sentence
to separate it from those 5 Reviewed-by patches, and were plan to send only four patches.
But later I got a message that these five patches are not that urgent to catch qemu v3.1,
thus I joined the earlier 5 R-b patches into the later v8 & v9 to have a better review.Sorry for the trouble, I need to explain it without involving too much background..
Back at the farm: in our current qemu code, some cleanups use a loop to
join()
the total number of threads if caller fails. This is not a problem until applying theqemu_thread_create()modification. E.g. whencompress_threads_save_setup()fails while trying to create the lastdo_data_compressthread, segmentation fault
will occur whenjoin()is called (sadly there's not enough condition to filter this
unsuccessful created thread) as this thread is actually not be created.Quoted 1 line
Hope the above makes it clear. :)
Alright, let's have a look at
compress_threads_save_setup():static int compress_threads_save_setup(void) { int i, thread_count; if (!migrate_use_compression()) { return 0; } thread_count = migrate_compress_threads(); compress_threads = g_new0(QemuThread, thread_count); comp_param = g_new0(CompressParam, thread_count); qemu_cond_init(&comp_done_cond); qemu_mutex_init(&comp_done_lock); for (i = 0; i < thread_count; i++) { comp_param[i].originbuf = g_try_malloc(TARGET_PAGE_SIZE); if (!comp_param[i].originbuf) { goto exit; } if (deflateInit(&comp_param[i].stream, migrate_compress_level()) != Z_OK) { g_free(comp_param[i].originbuf); goto exit; } /* comp_param[i].file is just used as a dummy buffer to save data, * set its ops to empty. */ comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops); comp_param[i].done = true; 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); } return 0; exit: compress_threads_save_cleanup(); return -1; }At label exit, we have @i threads, all fully initialized. That's an invariant.
compress_threads_save_cleanup()finds the threads to clean up by checking comp_param[i].file:static void compress_threads_save_cleanup(void) { int i, thread_count; if (!migrate_use_compression() || !comp_param) { return; } thread_count = migrate_compress_threads(); for (i = 0; i < thread_count; i++) { /* * we use it as a indicator which shows if the thread is * properly init'd or not */---> if (!comp_param[i].file) {
---> break;
---> }qemu_mutex_lock(&comp_param[i].mutex); comp_param[i].quit = true; qemu_cond_signal(&comp_param[i].cond); qemu_mutex_unlock(&comp_param[i].mutex); qemu_thread_join(compress_threads + i); qemu_mutex_destroy(&comp_param[i].mutex); qemu_cond_destroy(&comp_param[i].cond); deflateEnd(&comp_param[i].stream); g_free(comp_param[i].originbuf); qemu_fclose(comp_param[i].file); comp_param[i].file = NULL; } qemu_mutex_destroy(&comp_done_lock); qemu_cond_destroy(&comp_done_cond); g_free(compress_threads); g_free(comp_param); compress_threads = NULL; comp_param = NULL; }Due to the invariant, a comp_param[i] with a null .file doesn't need *any* cleanup.
To maintain the invariant,
compress_threads_save_setup()carefully cleans up any partial initializations itself before a goto exit. Since the code is arranged smartly, the only such cleanup is theg_free(comp_param[i].originbuf)before the second goto exit.Your PATCH 13 adds a third goto exit, but neglects to clean up partial initializations. Breaks the invariant.
I see two sane solutions:
1.
compress_threads_save_setup()carefully cleans up partial initializations itself.compress_threads_save_cleanup()copes only with fully initialized comp_param[i]. This is how things work before your series.2.
compress_threads_save_cleanup()copes with partially initialized comp_param[i], i.e. does the right thing for each goto exit incompress_threads_save_setup().compress_threads_save_setup()doesn't clean up partial initializations.Quoted 5 lines
Your PATCH 13 together with the fixup PATCH 16 does
3. A confusing mix of the two.
Don't.
Thanks for the detail analysis! :)
Emm.. Actually I have thought to do the cleanup in thesetup()function for the third ‘goto exit’ [1], which is a partial initialization.
But due to the below [1] is too long and seems not neat (I notice that most cleanups for each thread are in thexxx_cleanup()function), I turned to modify thejoin()function.. Is the long [1] acceptable when the third ‘goto exit’ is called, or is there any other better way to do the cleanup?[1]
qemu_mutex_lock(&comp_param[i].mutex); comp_param[i].quit = true; qemu_cond_signal(&comp_param[i].cond); qemu_mutex_unlock(&comp_param[i].mutex);qemu_mutex_destroy(&comp_param[i].mutex); qemu_cond_destroy(&comp_param[i].cond); deflateEnd(&comp_param[i].stream); g_free(comp_param[i].originbuf); qemu_fclose(comp_param[i].file); comp_param[i].file = NULL;Quoted 6 lines
Quoted 2 lines
Have you considered creating the thread earlier, e.g. right after initializing compression with
deflateInit()?I am afraid we can not do this, as the members of comp_param[i], like file/done/quit/mutex/cond
will be used later in the new created thread: do_data_[de]compress viaqemu_thread_create().You're right.
Quoted 9 lines
Thus it seems we have to accept the above long [1] if we do want to clean up partial initialization
inxxx_setup(). :(BTW, there is no other argument can be used except the "(compress_threads+i)->thread" to
differentiate whether should wejoin()the thread, just in case we want to change thexxx_cleanup()function.We can try to make
compress_threads_save_cleanup()cope with partially initialized comp_param[i]. Let's have a look at its members:bool done; // no cleanup bool quit; // see [2] bool zero_page; // no cleanup QEMUFile *file; // qemu_fclose() if non-null QemuMutex mutex; // see [1] QemuCond cond; // see [1] RAMBlock *block; // no cleanup (must be null) ram_addr_t offset; // no cleanup/* internally used fields */
z_streamstream; // see [3]
uint8_t*originbuf; // unconditionalg_free()[1]: we could do something like
if (comp_param[i].mutex.initialized) { qemu_mutex_destroy(&comp_param[i].mutex); } if (comp_param[i].cond.initialized) { qemu_cond_destroy(&comp_param[i].cond); }
Quoted 7 lines
but that would be unclean. Instead, I'd initialize these guys first, so we can clean them up unconditionally.
[2] This is used to make the thread terminate. Must be done before we call
qemu_thread_join(). I think it can safely be done always, as long as long as .mutex and .cond are initialized. Trivial if we initialize them first.
Thanks for the detail analysis, it helps a lot! I translate the above [1] & [2] to "move the below three '+' ahead of the initialization of comp_param[i].file" for xxx_setup():
+ qemu_mutex_init(&comp_param[i].mutex);
+ qemu_cond_init(&comp_param[i].cond);
+ comp_param[i].quit = false;
/* comp_param[i].file is just used as a dummy buffer to save data,
* set its ops to empty.
*/
comp_param[i].file = qemu_fopen_ops(NULL, &empty_ops); comp_param[i].done = true;
if (!qemu_thread_create(compress_threads + i, "compress",
...
And accordingly, do the corresponding change for the xxx_cleanup().
Quoted 7 lines
[3]: I can't see a squeaky clean way to detect whether .stream has been initialized with
deflateInit(). Here's a slightly unclean way:deflateInit()sets .stream.msg to null on success, and to non-null on failure. We can make it non-null until we're ready to calldeflateInit(), then havecompress_threads_save_cleanup()clean up .stream when it's null. If that's too unclean for your or your reviewers' taste, add a boolean @stream_initialized flag.
Emm, I am not sure either. Let's cc the migration maintainers to have their opinions.
Have a nice day, thanks for the review. :)
Fei
Patchew URL: https://patchew.org/QEMU/[email protected]/
Patchew URL: https://patchew.org/QEMU/[email protected]/
Hi,
This series failed the docker-quick@centos7 build test. Please find the testing commands and their output below. If you have Docker installed, you can probably reproduce it locally.
=== TEST SCRIPT BEGIN ===
#!/bin/bash
time make docker-test-quick@centos7 SHOW_ENV=1 J=8 === TEST SCRIPT END ===
libpmem support no
libudev no
WARNING: Use of SDL 1.2 is deprecated and will be removed in
WARNING: future releases. Please switch to using SDL 2.0
NOTE: cross-compilers enabled: 'cc'
GEN x86_64-softmmu/config-devices.mak.tmp
---
CC hw/usb/host-stub.o
CC hw/virtio/virtio-bus.o/tmp/qemu-test/src/hw/usb/ccid-card-emulated.c: In function 'init_event_notifier':/tmp/qemu-test/src/hw/usb/ccid-card-emulated.c:404:9: error: implicit declaration of function 'error_setg' [-Werror=implicit-function-declaration]
error_setg(errp, "ccid-card-emul: event notifier creation failed");
^
/tmp/qemu-test/src/hw/usb/ccid-card-emulated.c:404:9: error: nested extern declaration of 'error_setg' [-Werror=nested-externs]
/tmp/qemu-test/src/hw/usb/ccid-card-emulated.c: In function 'emulated_realize':
/tmp/qemu-test/src/hw/usb/ccid-card-emulated.c:513:13: error: implicit declaration of function 'error_append_hint' [-Werror=implicit-function-declaration]
error_append_hint(errp, "%s\n", ptable->name);
^/tmp/qemu-test/src/hw/usb/ccid-card-emulated.c:513:13: error: nested extern declaration of 'error_append_hint' [-Werror=nested-externs] /tmp/qemu-test/src/hw/usb/ccid-card-emulated.c: At top level:
cc1: error: unrecognized command line option "-Wno-format-truncation" [-Werror]
cc1: all warnings being treated as errors
make: *** [hw/usb/ccid-card-emulated.o] Error 1
make: *** Waiting for unfinished jobs....
The full log is available at
http://patchew.org/logs/[email protected]/testing.docker-quick@centos7/?type=message.
---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to [email protected]
Hi all,
Sorry for the mistakenly deleted " include "qapi/error.h" " for
[PATCH for-4.0 v9 11/16] qemu_thread: supplement error handling for emulated_realize, will add this #include back in next version.
Have a nice day, and again sorry for the trouble.
Fei
Quoted 48 lines · 在 2019/1/2 下午9:46, [email protected] 写道:
Patchew URL: https://patchew.org/QEMU/[email protected]/
Hi,
This series failed the docker-quick@centos7 build test. Please find the testing commands and their output below. If you have Docker installed, you can probably reproduce it locally.
=== TEST SCRIPT BEGIN ===
#!/bin/bash
time make docker-test-quick@centos7 SHOW_ENV=1 J=8 === TEST SCRIPT END ===libpmem support no
libudev noWARNING: Use of SDL 1.2 is deprecated and will be removed in
WARNING: future releases. Please switch to using SDL 2.0NOTE: cross-compilers enabled: 'cc'
GEN x86_64-softmmu/config-devices.mak.tmp
---
CChw/usb/host-stub.o
CChw/virtio/virtio-bus.o/tmp/qemu-test/src/hw/usb/ccid-card-emulated.c: In function 'init_event_notifier':/tmp/qemu-test/src/hw/usb/ccid-card-emulated.c:404:9: error: implicit declaration of function 'error_setg' [-Werror=implicit-function-declaration]error_setg(errp, "ccid-card-emul: event notifier creation failed"); ^ /tmp/qemu-test/src/hw/usb/ccid-card-emulated.c:404:9: error: nested extern declaration of 'error_setg' [-Werror=nested-externs] /tmp/qemu-test/src/hw/usb/ccid-card-emulated.c: In function 'emulated_realize': /tmp/qemu-test/src/hw/usb/ccid-card-emulated.c:513:13: error: implicit declaration of function 'error_append_hint' [-Werror=implicit-function-declaration] error_append_hint(errp, "%s\n", ptable->name); ^
/tmp/qemu-test/src/hw/usb/ccid-card-emulated.c:513:13: error: nested extern declaration of 'error_append_hint' [-Werror=nested-externs]/tmp/qemu-test/src/hw/usb/ccid-card-emulated.c: At top level:
cc1: error: unrecognized command line option "-Wno-format-truncation" [-Werror]
cc1: all warnings being treated as errors
make: *** [hw/usb/ccid-card-emulated.o] Error 1
make: *** Waiting for unfinished jobs....The full log is available at
http://patchew.org/logs/[email protected]/testing.docker-quick@centos7/?type=message.
---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to [email protected]