From f6bca156ca1aa9e405908a8eff251b692b32b045 Mon Sep 17 00:00:00 2001 From: Dodji Seketeli Date: Fri, 24 Feb 2017 14:16:35 +0100 Subject: [PATCH] Make abipkgdiff.cc use the abigail::workers interface With this patch, the code of abipkgdiff.cc doesn't use the pthreads API directly anymore. Rather, it uses the higher level "Workers Queue" API provided by the abigail::workers namespace. The main benefits are: - better code readability and maintainability. The code base doesn't have any global variable anymore. This is going to be helpful when adding new features to the abipkgdiff.cc code base. - faster code. The tests/runtestdiffpkg test program executes on ~ 17s without the patch, and on ~ 11s with the patch on my old X220 laptop. * tools/abipkgdiff.cc: Remove ftw.h, pthread.h, unistd.h, add fts.h and abg-workers.h. (verbose, elf_file_paths_tls_key, reports_map, env_map, map_lock) (arg_lock, prog_options): Remove all these global variables. (struct package_descriptor): Remove this type. (pthread_routine_extract_package) (first_package_tree_walker_callback_fn) (second_package_tree_walker_callback_fn, pthread_routine_compare) (pthread_join, pthread_routine_extract_pkg_and_map_its_content): Remove these functions. (options::{num_workers, verbose}): Define new data members. (options::options): Initialize the new verbose and num_workers data members. (package::erase_extraction_directory) (erase_created_temporary_directories_parent): Take the program options in parameter. Don't use the global verbose variable anymore. (package::erase_extraction_directories) (erase_created_temporary_directories, extract_package): Take the program options in parameter. (extract_rpm, extract_deb, extract_tar): Likewise. And don't use the global verbose variable anymore. (compare): Don't use the global verbose variable anymore. Use the new compare_task type along with the abigail::workers::queue type. (pkg_extraction_task, pkg_prepare_task, compare_task) (comparison_done_notify): Define new classes. (maybe_update_vector_of_package_content): Define new static function. (create_maps_of_package_content): Don't take the ftw_cp_type anymore. Don't use the global verbose variable anymore. Use the fts_{open,read,close} functions, rather than the ftw one. (extract_package_and_map_its_content): Don't use pthreads anymore. Use the new pkg_extraction_task type created along with the abigail::workers::queue type. (prepare_packages): Don't use pthreads anymore. Use the new pkg_prepare_task type along with the abigail::workers::queue type. (elf_size_is_greater): Adjust to use abigail::workers::queue::tasks, rather than the previous compaer_args_sptr type. (parse_command_line): Adjust to stop using the global verbose variable. (main): Remove use of global variables prog_options and also the packages variable. * tests/data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64--dbus-glib-0.104-3.fc23.armv7hl-report-0.txt: Adjust. * tests/data/test-diff-pkg/dirpkg-0-report-0.txt: Likewise. * tests/data/test-diff-pkg/test-dbus-glib-0.80-3.fc12.x86_64-report-0.txt: Likewise. * tests/data/test-diff-pkg/test-rpm-report-0.txt: Likewise. * tests/data/test-diff-pkg/test-rpm-report-1.txt: Likewise. * tests/data/test-diff-pkg/test-rpm-report-2.txt: Likewise. * tests/data/test-diff-pkg/test-rpm-report-3.txt: Likewise. * tests/data/test-fedabipkgdiff/test0-from-fc20-to-fc23-dbus-glib-report-0.txt: Likewise. * tests/data/test-fedabipkgdiff/test1-from-fc20-to-dbus-glib-0.106-1.fc23.x86_64-report-0.txt: Likewise. * tests/data/test-fedabipkgdiff/test2-dbus-glib-0.100.2-2.fc20--dbus-glib-0.106-1.fc23-report-0.txt: Likewise. * tests/data/test-fedabipkgdiff/test3-dbus-glib-0.100.2-2.fc20.i686--dbus-glib-0.106-1.fc23.i686-report-0.txt: Likewise. * tests/data/test-fedabipkgdiff/test4-glib-0.100.2-2.fc20.x86_64.rpm-glib-0.106-1.fc23.x86_64.rpm-report-0.txt: Likewise. Signed-off-by: Dodji Seketeli --- ...bus-glib-0.104-3.fc23.armv7hl-report-0.txt | 18 +- .../data/test-diff-pkg/dirpkg-0-report-0.txt | 16 - ...-dbus-glib-0.80-3.fc12.x86_64-report-0.txt | 8 - .../data/test-diff-pkg/test-rpm-report-0.txt | 36 +- .../data/test-diff-pkg/test-rpm-report-1.txt | 34 +- .../data/test-diff-pkg/test-rpm-report-2.txt | 34 +- .../data/test-diff-pkg/test-rpm-report-3.txt | 34 +- ...0-from-fc20-to-fc23-dbus-glib-report-0.txt | 28 +- ...dbus-glib-0.106-1.fc23.x86_64-report-0.txt | 22 +- ....fc20--dbus-glib-0.106-1.fc23-report-0.txt | 28 +- ...--dbus-glib-0.106-1.fc23.i686-report-0.txt | 22 +- ...-glib-0.106-1.fc23.x86_64.rpm-report-0.txt | 22 +- ...dbus-glib-0.106-1.fc23.x86_64-report-0.txt | 24 +- ...-vte291-0.39.90-1.fc22.x86_64-report-0.txt | 24 +- tools/abipkgdiff.cc | 1053 ++++++++--------- 15 files changed, 663 insertions(+), 740 deletions(-) diff --git a/tests/data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64--dbus-glib-0.104-3.fc23.armv7hl-report-0.txt b/tests/data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64--dbus-glib-0.104-3.fc23.armv7hl-report-0.txt index f56aa02b..14bf41a3 100644 --- a/tests/data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64--dbus-glib-0.104-3.fc23.armv7hl-report-0.txt +++ b/tests/data/test-diff-pkg/dbus-glib-0.104-3.fc23.x86_64--dbus-glib-0.104-3.fc23.armv7hl-report-0.txt @@ -1,3 +1,12 @@ +================ changes of 'libdbus-glib-1.so.2.3.2'=============== + ELF architecture changed + Functions changes summary: 0 Removed, 0 Changed, 0 Added function + Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + + architecture changed from 'elf-amd-x86_64' to 'elf-arm' + +================ end of changes of 'libdbus-glib-1.so.2.3.2'=============== + ================ changes of 'dbus-binding-tool'=============== ELF architecture changed Functions changes summary: 0 Removed, 0 Changed, 0 Added function @@ -22,12 +31,3 @@ ================ end of changes of 'dbus-binding-tool'=============== -================ changes of 'libdbus-glib-1.so.2.3.2'=============== - ELF architecture changed - Functions changes summary: 0 Removed, 0 Changed, 0 Added function - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - - architecture changed from 'elf-amd-x86_64' to 'elf-arm' - -================ end of changes of 'libdbus-glib-1.so.2.3.2'=============== - diff --git a/tests/data/test-diff-pkg/dirpkg-0-report-0.txt b/tests/data/test-diff-pkg/dirpkg-0-report-0.txt index c7c92265..e69de29b 100644 --- a/tests/data/test-diff-pkg/dirpkg-0-report-0.txt +++ b/tests/data/test-diff-pkg/dirpkg-0-report-0.txt @@ -1,16 +0,0 @@ -================ changes of 'libobj-v0.so'=============== - Functions changes summary: 0 Removed, 1 Changed, 0 Added function - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - - 1 function with some indirect sub-type change: - - [C]'function void bar(S&)' has some indirect sub-type changes: - parameter 1 of type 'S&' has sub-type changes: - in referenced type 'struct S': - type size changed from 32 to 64 bits - 1 data member insertion: - 'char S::mem1', at offset 32 (in bits) - - -================ end of changes of 'libobj-v0.so'=============== - diff --git a/tests/data/test-diff-pkg/test-dbus-glib-0.80-3.fc12.x86_64-report-0.txt b/tests/data/test-diff-pkg/test-dbus-glib-0.80-3.fc12.x86_64-report-0.txt index 0344d682..e69de29b 100644 --- a/tests/data/test-diff-pkg/test-dbus-glib-0.80-3.fc12.x86_64-report-0.txt +++ b/tests/data/test-diff-pkg/test-dbus-glib-0.80-3.fc12.x86_64-report-0.txt @@ -1,8 +0,0 @@ -================ changes of 'dbus-binding-tool'=============== -No ABI change detected -================ end of changes of 'dbus-binding-tool'=============== - -================ changes of 'libdbus-glib-1.so.2.1.0'=============== -No ABI change detected -================ end of changes of 'libdbus-glib-1.so.2.1.0'=============== - diff --git a/tests/data/test-diff-pkg/test-rpm-report-0.txt b/tests/data/test-diff-pkg/test-rpm-report-0.txt index 95475ccb..3fb8b8cc 100644 --- a/tests/data/test-diff-pkg/test-rpm-report-0.txt +++ b/tests/data/test-diff-pkg/test-rpm-report-0.txt @@ -1,21 +1,3 @@ -================ changes of 'dbus-binding-tool'=============== - Functions changes summary: 2 Removed, 0 Changed, 0 Added functions - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - Function symbols changes summary: 0 Removed, 1 Added function symbol not referenced by debug info - Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info - - 2 Removed functions: - - 'function BaseInfo* base_info_ref(BaseInfo*)' {base_info_ref} - 'function void base_info_unref(BaseInfo*)' {base_info_unref} - - - 1 Added function symbol not referenced by debug info: - - dbus_g_value_build_g_variant - -================ end of changes of 'dbus-binding-tool'=============== - ================ changes of 'libdbus-glib-1.so.2.1.0'=============== Functions changes summary: 0 Removed, 0 Changed, 0 Added function Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -35,3 +17,21 @@ ================ end of changes of 'libdbus-glib-1.so.2.1.0'=============== +================ changes of 'dbus-binding-tool'=============== + Functions changes summary: 2 Removed, 0 Changed, 0 Added functions + Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + Function symbols changes summary: 0 Removed, 1 Added function symbol not referenced by debug info + Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info + + 2 Removed functions: + + 'function BaseInfo* base_info_ref(BaseInfo*)' {base_info_ref} + 'function void base_info_unref(BaseInfo*)' {base_info_unref} + + + 1 Added function symbol not referenced by debug info: + + dbus_g_value_build_g_variant + +================ end of changes of 'dbus-binding-tool'=============== + diff --git a/tests/data/test-diff-pkg/test-rpm-report-1.txt b/tests/data/test-diff-pkg/test-rpm-report-1.txt index d5d4d463..0f7264aa 100644 --- a/tests/data/test-diff-pkg/test-rpm-report-1.txt +++ b/tests/data/test-diff-pkg/test-rpm-report-1.txt @@ -1,20 +1,3 @@ -================ changes of 'dbus-binding-tool'=============== - Functions changes summary: 0 Removed, 0 Changed, 0 Added function - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - Function symbols changes summary: 2 Removed, 1 Added function symbols not referenced by debug info - Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info - - 2 Removed function symbols not referenced by debug info: - - base_info_ref - base_info_unref - - 1 Added function symbol not referenced by debug info: - - dbus_g_value_build_g_variant - -================ end of changes of 'dbus-binding-tool'=============== - ================ changes of 'libdbus-glib-1.so.2.1.0'=============== Functions changes summary: 0 Removed, 0 Changed, 0 Added function Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -34,3 +17,20 @@ ================ end of changes of 'libdbus-glib-1.so.2.1.0'=============== +================ changes of 'dbus-binding-tool'=============== + Functions changes summary: 0 Removed, 0 Changed, 0 Added function + Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + Function symbols changes summary: 2 Removed, 1 Added function symbols not referenced by debug info + Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info + + 2 Removed function symbols not referenced by debug info: + + base_info_ref + base_info_unref + + 1 Added function symbol not referenced by debug info: + + dbus_g_value_build_g_variant + +================ end of changes of 'dbus-binding-tool'=============== + diff --git a/tests/data/test-diff-pkg/test-rpm-report-2.txt b/tests/data/test-diff-pkg/test-rpm-report-2.txt index d5d4d463..0f7264aa 100644 --- a/tests/data/test-diff-pkg/test-rpm-report-2.txt +++ b/tests/data/test-diff-pkg/test-rpm-report-2.txt @@ -1,20 +1,3 @@ -================ changes of 'dbus-binding-tool'=============== - Functions changes summary: 0 Removed, 0 Changed, 0 Added function - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - Function symbols changes summary: 2 Removed, 1 Added function symbols not referenced by debug info - Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info - - 2 Removed function symbols not referenced by debug info: - - base_info_ref - base_info_unref - - 1 Added function symbol not referenced by debug info: - - dbus_g_value_build_g_variant - -================ end of changes of 'dbus-binding-tool'=============== - ================ changes of 'libdbus-glib-1.so.2.1.0'=============== Functions changes summary: 0 Removed, 0 Changed, 0 Added function Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -34,3 +17,20 @@ ================ end of changes of 'libdbus-glib-1.so.2.1.0'=============== +================ changes of 'dbus-binding-tool'=============== + Functions changes summary: 0 Removed, 0 Changed, 0 Added function + Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + Function symbols changes summary: 2 Removed, 1 Added function symbols not referenced by debug info + Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info + + 2 Removed function symbols not referenced by debug info: + + base_info_ref + base_info_unref + + 1 Added function symbol not referenced by debug info: + + dbus_g_value_build_g_variant + +================ end of changes of 'dbus-binding-tool'=============== + diff --git a/tests/data/test-diff-pkg/test-rpm-report-3.txt b/tests/data/test-diff-pkg/test-rpm-report-3.txt index d5d4d463..0f7264aa 100644 --- a/tests/data/test-diff-pkg/test-rpm-report-3.txt +++ b/tests/data/test-diff-pkg/test-rpm-report-3.txt @@ -1,20 +1,3 @@ -================ changes of 'dbus-binding-tool'=============== - Functions changes summary: 0 Removed, 0 Changed, 0 Added function - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - Function symbols changes summary: 2 Removed, 1 Added function symbols not referenced by debug info - Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info - - 2 Removed function symbols not referenced by debug info: - - base_info_ref - base_info_unref - - 1 Added function symbol not referenced by debug info: - - dbus_g_value_build_g_variant - -================ end of changes of 'dbus-binding-tool'=============== - ================ changes of 'libdbus-glib-1.so.2.1.0'=============== Functions changes summary: 0 Removed, 0 Changed, 0 Added function Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -34,3 +17,20 @@ ================ end of changes of 'libdbus-glib-1.so.2.1.0'=============== +================ changes of 'dbus-binding-tool'=============== + Functions changes summary: 0 Removed, 0 Changed, 0 Added function + Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + Function symbols changes summary: 2 Removed, 1 Added function symbols not referenced by debug info + Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info + + 2 Removed function symbols not referenced by debug info: + + base_info_ref + base_info_unref + + 1 Added function symbol not referenced by debug info: + + dbus_g_value_build_g_variant + +================ end of changes of 'dbus-binding-tool'=============== + diff --git a/tests/data/test-fedabipkgdiff/test0-from-fc20-to-fc23-dbus-glib-report-0.txt b/tests/data/test-fedabipkgdiff/test0-from-fc20-to-fc23-dbus-glib-report-0.txt index 0aaf4eec..a3241095 100644 --- a/tests/data/test-fedabipkgdiff/test0-from-fc20-to-fc23-dbus-glib-report-0.txt +++ b/tests/data/test-fedabipkgdiff/test0-from-fc20-to-fc23-dbus-glib-report-0.txt @@ -1,5 +1,16 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.i686.rpm and dbus-glib-0.106-1.fc23.i686.rpm: +================ changes of 'libdbus-glib-1.so.2.2.2'=============== + Functions changes summary: 0 Removed, 0 Changed, 2 Added functions + Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + + 2 Added functions: + + 'function DBusGConnection* dbus_g_connection_open_private(const gchar*, GMainContext*, GError**)' {dbus_g_connection_open_private} + 'function DBusGConnection* dbus_g_method_invocation_get_g_connection(DBusGMethodInvocation*)' {dbus_g_method_invocation_get_g_connection} + +================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== + ================ changes of 'dbus-binding-tool'=============== Functions changes summary: 2 Removed, 0 Changed, 1 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -23,6 +34,9 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.i686.rpm and dbus ================ end of changes of 'dbus-binding-tool'=============== + +Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.x86_64.rpm and dbus-glib-0.106-1.fc23.x86_64.rpm: + ================ changes of 'libdbus-glib-1.so.2.2.2'=============== Functions changes summary: 0 Removed, 0 Changed, 2 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -34,9 +48,6 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.i686.rpm and dbus ================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== - -Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.x86_64.rpm and dbus-glib-0.106-1.fc23.x86_64.rpm: - ================ changes of 'dbus-binding-tool'=============== Functions changes summary: 2 Removed, 0 Changed, 0 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -49,15 +60,4 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.x86_64.rpm and db ================ end of changes of 'dbus-binding-tool'=============== -================ changes of 'libdbus-glib-1.so.2.2.2'=============== - Functions changes summary: 0 Removed, 0 Changed, 2 Added functions - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - - 2 Added functions: - - 'function DBusGConnection* dbus_g_connection_open_private(const gchar*, GMainContext*, GError**)' {dbus_g_connection_open_private} - 'function DBusGConnection* dbus_g_method_invocation_get_g_connection(DBusGMethodInvocation*)' {dbus_g_method_invocation_get_g_connection} - -================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== - diff --git a/tests/data/test-fedabipkgdiff/test1-from-fc20-to-dbus-glib-0.106-1.fc23.x86_64-report-0.txt b/tests/data/test-fedabipkgdiff/test1-from-fc20-to-dbus-glib-0.106-1.fc23.x86_64-report-0.txt index 98998e45..d774e54d 100644 --- a/tests/data/test-fedabipkgdiff/test1-from-fc20-to-dbus-glib-0.106-1.fc23.x86_64-report-0.txt +++ b/tests/data/test-fedabipkgdiff/test1-from-fc20-to-dbus-glib-0.106-1.fc23.x86_64-report-0.txt @@ -1,5 +1,16 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.x86_64.rpm and dbus-glib-0.106-1.fc23.x86_64.rpm: +================ changes of 'libdbus-glib-1.so.2.2.2'=============== + Functions changes summary: 0 Removed, 0 Changed, 2 Added functions + Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + + 2 Added functions: + + 'function DBusGConnection* dbus_g_connection_open_private(const gchar*, GMainContext*, GError**)' {dbus_g_connection_open_private} + 'function DBusGConnection* dbus_g_method_invocation_get_g_connection(DBusGMethodInvocation*)' {dbus_g_method_invocation_get_g_connection} + +================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== + ================ changes of 'dbus-binding-tool'=============== Functions changes summary: 2 Removed, 0 Changed, 0 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -12,15 +23,4 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.x86_64.rpm and db ================ end of changes of 'dbus-binding-tool'=============== -================ changes of 'libdbus-glib-1.so.2.2.2'=============== - Functions changes summary: 0 Removed, 0 Changed, 2 Added functions - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - - 2 Added functions: - - 'function DBusGConnection* dbus_g_connection_open_private(const gchar*, GMainContext*, GError**)' {dbus_g_connection_open_private} - 'function DBusGConnection* dbus_g_method_invocation_get_g_connection(DBusGMethodInvocation*)' {dbus_g_method_invocation_get_g_connection} - -================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== - diff --git a/tests/data/test-fedabipkgdiff/test2-dbus-glib-0.100.2-2.fc20--dbus-glib-0.106-1.fc23-report-0.txt b/tests/data/test-fedabipkgdiff/test2-dbus-glib-0.100.2-2.fc20--dbus-glib-0.106-1.fc23-report-0.txt index 0aaf4eec..a3241095 100644 --- a/tests/data/test-fedabipkgdiff/test2-dbus-glib-0.100.2-2.fc20--dbus-glib-0.106-1.fc23-report-0.txt +++ b/tests/data/test-fedabipkgdiff/test2-dbus-glib-0.100.2-2.fc20--dbus-glib-0.106-1.fc23-report-0.txt @@ -1,5 +1,16 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.i686.rpm and dbus-glib-0.106-1.fc23.i686.rpm: +================ changes of 'libdbus-glib-1.so.2.2.2'=============== + Functions changes summary: 0 Removed, 0 Changed, 2 Added functions + Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + + 2 Added functions: + + 'function DBusGConnection* dbus_g_connection_open_private(const gchar*, GMainContext*, GError**)' {dbus_g_connection_open_private} + 'function DBusGConnection* dbus_g_method_invocation_get_g_connection(DBusGMethodInvocation*)' {dbus_g_method_invocation_get_g_connection} + +================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== + ================ changes of 'dbus-binding-tool'=============== Functions changes summary: 2 Removed, 0 Changed, 1 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -23,6 +34,9 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.i686.rpm and dbus ================ end of changes of 'dbus-binding-tool'=============== + +Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.x86_64.rpm and dbus-glib-0.106-1.fc23.x86_64.rpm: + ================ changes of 'libdbus-glib-1.so.2.2.2'=============== Functions changes summary: 0 Removed, 0 Changed, 2 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -34,9 +48,6 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.i686.rpm and dbus ================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== - -Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.x86_64.rpm and dbus-glib-0.106-1.fc23.x86_64.rpm: - ================ changes of 'dbus-binding-tool'=============== Functions changes summary: 2 Removed, 0 Changed, 0 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -49,15 +60,4 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.x86_64.rpm and db ================ end of changes of 'dbus-binding-tool'=============== -================ changes of 'libdbus-glib-1.so.2.2.2'=============== - Functions changes summary: 0 Removed, 0 Changed, 2 Added functions - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - - 2 Added functions: - - 'function DBusGConnection* dbus_g_connection_open_private(const gchar*, GMainContext*, GError**)' {dbus_g_connection_open_private} - 'function DBusGConnection* dbus_g_method_invocation_get_g_connection(DBusGMethodInvocation*)' {dbus_g_method_invocation_get_g_connection} - -================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== - diff --git a/tests/data/test-fedabipkgdiff/test3-dbus-glib-0.100.2-2.fc20.i686--dbus-glib-0.106-1.fc23.i686-report-0.txt b/tests/data/test-fedabipkgdiff/test3-dbus-glib-0.100.2-2.fc20.i686--dbus-glib-0.106-1.fc23.i686-report-0.txt index c860ff05..fc85920c 100644 --- a/tests/data/test-fedabipkgdiff/test3-dbus-glib-0.100.2-2.fc20.i686--dbus-glib-0.106-1.fc23.i686-report-0.txt +++ b/tests/data/test-fedabipkgdiff/test3-dbus-glib-0.100.2-2.fc20.i686--dbus-glib-0.106-1.fc23.i686-report-0.txt @@ -1,5 +1,16 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.i686.rpm and dbus-glib-0.106-1.fc23.i686.rpm: +================ changes of 'libdbus-glib-1.so.2.2.2'=============== + Functions changes summary: 0 Removed, 0 Changed, 2 Added functions + Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + + 2 Added functions: + + 'function DBusGConnection* dbus_g_connection_open_private(const gchar*, GMainContext*, GError**)' {dbus_g_connection_open_private} + 'function DBusGConnection* dbus_g_method_invocation_get_g_connection(DBusGMethodInvocation*)' {dbus_g_method_invocation_get_g_connection} + +================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== + ================ changes of 'dbus-binding-tool'=============== Functions changes summary: 2 Removed, 0 Changed, 1 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -23,15 +34,4 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.i686.rpm and dbus ================ end of changes of 'dbus-binding-tool'=============== -================ changes of 'libdbus-glib-1.so.2.2.2'=============== - Functions changes summary: 0 Removed, 0 Changed, 2 Added functions - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - - 2 Added functions: - - 'function DBusGConnection* dbus_g_connection_open_private(const gchar*, GMainContext*, GError**)' {dbus_g_connection_open_private} - 'function DBusGConnection* dbus_g_method_invocation_get_g_connection(DBusGMethodInvocation*)' {dbus_g_method_invocation_get_g_connection} - -================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== - diff --git a/tests/data/test-fedabipkgdiff/test4-glib-0.100.2-2.fc20.x86_64.rpm-glib-0.106-1.fc23.x86_64.rpm-report-0.txt b/tests/data/test-fedabipkgdiff/test4-glib-0.100.2-2.fc20.x86_64.rpm-glib-0.106-1.fc23.x86_64.rpm-report-0.txt index 98998e45..d774e54d 100644 --- a/tests/data/test-fedabipkgdiff/test4-glib-0.100.2-2.fc20.x86_64.rpm-glib-0.106-1.fc23.x86_64.rpm-report-0.txt +++ b/tests/data/test-fedabipkgdiff/test4-glib-0.100.2-2.fc20.x86_64.rpm-glib-0.106-1.fc23.x86_64.rpm-report-0.txt @@ -1,5 +1,16 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.x86_64.rpm and dbus-glib-0.106-1.fc23.x86_64.rpm: +================ changes of 'libdbus-glib-1.so.2.2.2'=============== + Functions changes summary: 0 Removed, 0 Changed, 2 Added functions + Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + + 2 Added functions: + + 'function DBusGConnection* dbus_g_connection_open_private(const gchar*, GMainContext*, GError**)' {dbus_g_connection_open_private} + 'function DBusGConnection* dbus_g_method_invocation_get_g_connection(DBusGMethodInvocation*)' {dbus_g_method_invocation_get_g_connection} + +================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== + ================ changes of 'dbus-binding-tool'=============== Functions changes summary: 2 Removed, 0 Changed, 0 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -12,15 +23,4 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.x86_64.rpm and db ================ end of changes of 'dbus-binding-tool'=============== -================ changes of 'libdbus-glib-1.so.2.2.2'=============== - Functions changes summary: 0 Removed, 0 Changed, 2 Added functions - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - - 2 Added functions: - - 'function DBusGConnection* dbus_g_connection_open_private(const gchar*, GMainContext*, GError**)' {dbus_g_connection_open_private} - 'function DBusGConnection* dbus_g_method_invocation_get_g_connection(DBusGMethodInvocation*)' {dbus_g_method_invocation_get_g_connection} - -================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== - diff --git a/tests/data/test-fedabipkgdiff/test5-same-dir-dbus-glib-0.100.2-2.fc20.x86_64--dbus-glib-0.106-1.fc23.x86_64-report-0.txt b/tests/data/test-fedabipkgdiff/test5-same-dir-dbus-glib-0.100.2-2.fc20.x86_64--dbus-glib-0.106-1.fc23.x86_64-report-0.txt index f5f617fb..b3123d3c 100644 --- a/tests/data/test-fedabipkgdiff/test5-same-dir-dbus-glib-0.100.2-2.fc20.x86_64--dbus-glib-0.106-1.fc23.x86_64-report-0.txt +++ b/tests/data/test-fedabipkgdiff/test5-same-dir-dbus-glib-0.100.2-2.fc20.x86_64--dbus-glib-0.106-1.fc23.x86_64-report-0.txt @@ -1,29 +1,29 @@ Comparing the ABI of binaries between dbus-glib-0.100.2-2.fc20.x86_64.rpm and dbus-glib-0.106-1.fc23.x86_64.rpm: -================ changes of 'dbus-binding-tool'=============== +================ changes of 'libdbus-glib-1.so.2.2.2'=============== Functions changes summary: 0 Removed, 0 Changed, 0 Added function Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - Function symbols changes summary: 2 Removed, 0 Added function symbols not referenced by debug info + Function symbols changes summary: 0 Removed, 2 Added function symbols not referenced by debug info Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info - 2 Removed function symbols not referenced by debug info: + 2 Added function symbols not referenced by debug info: - base_info_ref - base_info_unref + dbus_g_connection_open_private + dbus_g_method_invocation_get_g_connection -================ end of changes of 'dbus-binding-tool'=============== +================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== -================ changes of 'libdbus-glib-1.so.2.2.2'=============== +================ changes of 'dbus-binding-tool'=============== Functions changes summary: 0 Removed, 0 Changed, 0 Added function Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - Function symbols changes summary: 0 Removed, 2 Added function symbols not referenced by debug info + Function symbols changes summary: 2 Removed, 0 Added function symbols not referenced by debug info Variable symbols changes summary: 0 Removed, 0 Added variable symbol not referenced by debug info - 2 Added function symbols not referenced by debug info: + 2 Removed function symbols not referenced by debug info: - dbus_g_connection_open_private - dbus_g_method_invocation_get_g_connection + base_info_ref + base_info_unref -================ end of changes of 'libdbus-glib-1.so.2.2.2'=============== +================ end of changes of 'dbus-binding-tool'=============== diff --git a/tests/data/test-fedabipkgdiff/vte291-0.39.1-1.fc22.x86_64--vte291-0.39.90-1.fc22.x86_64-report-0.txt b/tests/data/test-fedabipkgdiff/vte291-0.39.1-1.fc22.x86_64--vte291-0.39.90-1.fc22.x86_64-report-0.txt index fab0271a..0a953a63 100644 --- a/tests/data/test-fedabipkgdiff/vte291-0.39.1-1.fc22.x86_64--vte291-0.39.90-1.fc22.x86_64-report-0.txt +++ b/tests/data/test-fedabipkgdiff/vte291-0.39.1-1.fc22.x86_64--vte291-0.39.90-1.fc22.x86_64-report-0.txt @@ -1,17 +1,5 @@ Comparing the ABI of binaries between vte291-0.39.1-1.fc22.x86_64.rpm and vte291-0.39.90-1.fc22.x86_64.rpm: -================ changes of 'gnome-pty-helper'=============== - Functions changes summary: 0 Removed, 0 Changed, 0 Added function - Variables changes summary: 0 Removed, 0 Changed, 0 Added variable - Function symbols changes summary: 0 Removed, 0 Added function symbol not referenced by debug info - Variable symbols changes summary: 0 Removed, 1 Added variable symbol not referenced by debug info - - 1 Added variable symbol not referenced by debug info: - - stderr - -================ end of changes of 'gnome-pty-helper'=============== - ================ changes of 'libvte-2.91.so.0.3901.0'=============== Functions changes summary: 0 Removed, 0 Changed (81 filtered out), 3 Added functions Variables changes summary: 0 Removed, 0 Changed, 0 Added variable @@ -24,4 +12,16 @@ Comparing the ABI of binaries between vte291-0.39.1-1.fc22.x86_64.rpm and vte291 ================ end of changes of 'libvte-2.91.so.0.3901.0'=============== +================ changes of 'gnome-pty-helper'=============== + Functions changes summary: 0 Removed, 0 Changed, 0 Added function + Variables changes summary: 0 Removed, 0 Changed, 0 Added variable + Function symbols changes summary: 0 Removed, 0 Added function symbol not referenced by debug info + Variable symbols changes summary: 0 Removed, 1 Added variable symbol not referenced by debug info + + 1 Added variable symbol not referenced by debug info: + + stderr + +================ end of changes of 'gnome-pty-helper'=============== + diff --git a/tools/abipkgdiff.cc b/tools/abipkgdiff.cc index 4cc2caf0..54ce7525 100644 --- a/tools/abipkgdiff.cc +++ b/tools/abipkgdiff.cc @@ -59,12 +59,13 @@ // For package configuration macros. #include "config.h" + #include #include #include #include #include -#include +#include #include #include #include @@ -72,8 +73,8 @@ #include #include #include -#include -#include + +#include "abg-workers.h" #include "abg-config.h" #include "abg-tools-utils.h" #include "abg-comparison.h" @@ -88,6 +89,10 @@ using std::vector; using std::map; using std::ostringstream; using std::tr1::shared_ptr; +using std::tr1::dynamic_pointer_cast; +using abigail::workers::task; +using abigail::workers::task_sptr; +using abigail::workers::queue; using abigail::tools_utils::maybe_get_symlink_target_file_path; using abigail::tools_utils::file_exists; using abigail::tools_utils::is_dir; @@ -119,37 +124,6 @@ using abigail::dwarf_reader::get_soname_of_elf_file; using abigail::dwarf_reader::get_type_of_elf_file; using abigail::dwarf_reader::read_corpus_from_elf; -/// Set to true if the user wants to see verbose information about the -/// progress of what's being done. -static bool verbose; - -/// The key for getting the thread-local elf_file_paths vector, which -/// contains the set of files of a given package. The vector is populated -/// by a worker function that is invoked on each file contained in the -/// package, specifically by the -/// {first,second}_package_tree_walker_callback_fn() functions. Its content -/// is relevant only until the mapping of the packages elf files is done. -static pthread_key_t elf_file_paths_tls_key; - -/// A convenience typedef for a map of corpus diffs -typedef map > corpora_report_map; -/// This map is used to gather the computed diffs of ELF pairs -static corpora_report_map reports_map; - -/// This map is used to keep environments for differing corpora -/// referenced. The environment needs to be kept alive longer than -/// all the objects that depend on it. -static map env_map; - -/// This mutex is used to control access to the reports_map -static pthread_mutex_t map_lock = PTHREAD_MUTEX_INITIALIZER; -/// This mutex is used to control access to the pre-computed list of ELF pairs -static pthread_mutex_t arg_lock = PTHREAD_MUTEX_INITIALIZER; - -/// This points to the set of options shared by all the routines of the -/// program. -static struct options *prog_options; - /// The options passed to the current program. class options { @@ -171,6 +145,8 @@ public: string debug_package2; string devel_package1; string devel_package2; + size_t num_workers; + bool verbose; bool drop_private_types; bool show_relative_offset_changes; bool no_default_suppression; @@ -194,6 +170,7 @@ public: nonexistent_file(), abignore(true), parallel(true), + verbose(false), drop_private_types(false), show_relative_offset_changes(true), no_default_suppression(), @@ -207,7 +184,12 @@ public: show_added_binaries(true), fail_if_no_debug_info(), show_identical_binaries() - {} + { + // set num_workers to the default number of threads of the + // underlying maching. This is the default value for the number + // of workers to use in workers queues throughout the code. + num_workers = abigail::workers::get_number_of_threads(); + } }; /// Abstract ELF files from the packages which ABIs ought to be @@ -242,10 +224,6 @@ public: /// A convenience typedef for a shared pointer to elf_file. typedef shared_ptr elf_file_sptr; -/// A convenience typedef for a pointer to a function type that -/// the ftw() function accepts. -typedef int (*ftw_cb_type)(const char *, const struct stat*, int); - /// Abstract the result of comparing two packages. /// /// This contains the the paths of the set of added binaries, removed @@ -457,8 +435,10 @@ public: /// Erase the content of the temporary extraction directory that has /// been populated by the @ref extract_package() function; + /// + /// @param opts the options passed to the current program. void - erase_extraction_directory() const + erase_extraction_directory(const options &opts) const { if (type() == abigail::tools_utils::FILE_TYPE_DIR) // If we are comparing two directories, do not erase the @@ -466,7 +446,7 @@ public: // temporary directory we created ourselves. return; - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "Erasing temporary extraction directory " << extracted_dir_path() @@ -475,37 +455,31 @@ public: string cmd = "rm -rf " + extracted_dir_path(); if (system(cmd.c_str())) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " FAILED\n"; } else { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " DONE\n"; } } /// Erase the content of all the temporary extraction directories. + /// + /// @param opts the options passed to the current program. void - erase_extraction_directories() const + erase_extraction_directories(const options &opts) const { - erase_extraction_directory(); + erase_extraction_directory(opts); if (debug_info_package()) - debug_info_package()->erase_extraction_directory(); + debug_info_package()->erase_extraction_directory(opts); if (devel_package()) - devel_package()->erase_extraction_directory(); + devel_package()->erase_extraction_directory(opts); } -}; +}; // end class package. -/// Arguments passed to the package extraction functions. -struct package_descriptor -{ - package &pkg; - const options& opts; - ftw_cb_type callback; -}; - -/// Arguments passed to the comparison workers. +/// Arguments passed to the comparison tasks. struct compare_args { const elf_file elf1; @@ -541,10 +515,14 @@ struct compare_args private_types_suppr2(priv_types_suppr2), opts(opts) {} -}; +}; // end struct compare_args + /// A convenience typedef for arguments passed to the comparison workers. typedef shared_ptr compare_args_sptr; +static bool extract_package_and_map_its_content(package &pkg, + options &opts); + /// Getter for the path to the parent directory under which packages /// extracted by the current thread are placed. /// @@ -651,12 +629,15 @@ display_usage(const string& prog_name, ostream& out) /// @param extracted_package_dir_path the path where to extract the /// package to. /// +/// @param opts the options passed to the current program. +/// /// @return true upon successful completion, false otherwise. static bool extract_rpm(const string& package_path, - const string& extracted_package_dir_path) + const string& extracted_package_dir_path, + const options &opts) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "Extracting package " << package_path @@ -670,7 +651,7 @@ extract_rpm(const string& package_path, if (system(cmd.c_str())) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "command " << cmd << " FAILED\n"; } @@ -680,12 +661,12 @@ extract_rpm(const string& package_path, if (system(cmd.c_str())) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " FAILED\n"; return false; } - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " DONE\n"; return true; @@ -702,12 +683,15 @@ extract_rpm(const string& package_path, /// @param extracted_package_dir_path the path where to extract the /// package to. /// +/// @param opts the options passed to the current program. +/// /// @return true upon successful completion, false otherwise. static bool extract_deb(const string& package_path, - const string& extracted_package_dir_path) + const string& extracted_package_dir_path, + const options &opts) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "Extracting package " << package_path @@ -721,7 +705,7 @@ extract_deb(const string& package_path, if (system(cmd.c_str())) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "command " << cmd << " FAILED\n"; } @@ -730,12 +714,12 @@ extract_deb(const string& package_path, if (system(cmd.c_str())) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " FAILED\n"; return false; } - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " DONE\n"; return true; @@ -752,12 +736,15 @@ extract_deb(const string& package_path, /// @param extracted_package_dir_path the path where to extract the /// archive to. /// +/// @param opts the options passed to the current program. +/// /// @return true upon successful completion, false otherwise. static bool extract_tar(const string& package_path, - const string& extracted_package_dir_path) + const string& extracted_package_dir_path, + const options &opts) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "Extracting tar archive " << package_path @@ -771,7 +758,7 @@ extract_tar(const string& package_path, if (system(cmd.c_str())) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "command " << cmd << " FAILED\n"; } @@ -780,12 +767,12 @@ extract_tar(const string& package_path, if (system(cmd.c_str())) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " FAILED\n"; return false; } - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " DONE\n"; return true; @@ -798,21 +785,24 @@ extract_tar(const string& package_path, /// /// @param first_package the first package to consider. /// +/// @param opts the options passed to the current program. +/// /// @param second_package the second package to consider. static void erase_created_temporary_directories(const package& first_package, - const package& second_package) + const package& second_package, + const options &opts) { - first_package.erase_extraction_directories(); - second_package.erase_extraction_directories(); + first_package.erase_extraction_directories(opts); + second_package.erase_extraction_directories(opts); } /// Erase the root of all the temporary directories created by the /// current thread. static void -erase_created_temporary_directories_parent() +erase_created_temporary_directories_parent(const options &opts) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "Erasing temporary extraction parent directory " << package::extracted_packages_parent_dir() @@ -821,12 +811,12 @@ erase_created_temporary_directories_parent() string cmd = "rm -rf " + package::extracted_packages_parent_dir(); if (system(cmd.c_str())) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "FAILED\n"; } else { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "DONE\n"; } } @@ -834,14 +824,17 @@ erase_created_temporary_directories_parent() /// Extract the content of a package. /// /// @param package the package we are looking at. +/// +/// @param opts the options passed to the current program. static bool -extract_package(const package& package) +extract_package(const package& package, + const options &opts) { switch(package.type()) { case abigail::tools_utils::FILE_TYPE_RPM: #ifdef WITH_RPM - if (!extract_rpm(package.path(), package.extracted_dir_path())) + if (!extract_rpm(package.path(), package.extracted_dir_path(), opts)) { emit_prefix("abipkgdiff", cerr) << "Error while extracting package" << package.path() << "\n"; @@ -851,13 +844,13 @@ extract_package(const package& package) #else emit_prefix("abipkgdiff", cerr) << "Support for rpm hasn't been enabled. Please consider " - "enabling it at package configure time\n"; + "enabling it at package configure time\n"; return false; #endif // WITH_RPM break; case abigail::tools_utils::FILE_TYPE_DEB: #ifdef WITH_DEB - if (!extract_deb(package.path(), package.extracted_dir_path())) + if (!extract_deb(package.path(), package.extracted_dir_path(), opts)) { emit_prefix("abipkgdiff", cerr) << "Error while extracting package" << package.path() << "\n"; @@ -879,7 +872,7 @@ extract_package(const package& package) case abigail::tools_utils::FILE_TYPE_TAR: #ifdef WITH_TAR - if (!extract_tar(package.path(), package.extracted_dir_path())) + if (!extract_tar(package.path(), package.extracted_dir_path(), opts)) { emit_prefix("abipkgdiff", cerr) << "Error while extracting GNU tar archive " @@ -900,71 +893,6 @@ extract_package(const package& package) } return true; } -/// A wrapper to call extract_package in a separate thread. -/// -/// @param pkg the package we want to extract. -/// -/// @return via pthread_exit() a pointer to a boolean value of true upon -/// successful completion, false otherwise. -static void -pthread_routine_extract_package(void *pkg) -{ - const package &package = *static_cast(pkg); - pthread_exit(new bool(extract_package(package))); -} - -/// A callback function invoked by the ftw() function while walking -/// the directory of files extracted from the first package. -/// -/// @param fpath the path to the file being considered. -/// -/// @param stat the stat struct of the file. -static int -first_package_tree_walker_callback_fn(const char *fpath, - const struct stat *, - int /*flag*/) -{ - string path = fpath; - // If path is a symbolic link, then set it to the path of its target - // file. - maybe_get_symlink_target_file_path(path, path); - if (guess_file_type(path) == abigail::tools_utils::FILE_TYPE_ELF) - { - vector *elf_file_paths - = static_cast*>(pthread_getspecific(elf_file_paths_tls_key)); - elf_file_paths->push_back(path); - } - return 0; -} - -/// A callback function invoked by the ftw() function while walking -/// the directory of files extracted from the second package. -/// -/// @param fpath the path to the file being considered. -/// -/// @param stat the stat struct of the file. -static int -second_package_tree_walker_callback_fn(const char *fpath, - const struct stat *, - int /*flag*/) -{ - string path = fpath; - // If path is a symbolic link, then set it to the path of its target - // file. - maybe_get_symlink_target_file_path(path, path); - if (guess_file_type(path) == abigail::tools_utils::FILE_TYPE_ELF) - { - vector *elf_file_paths - = static_cast*>(pthread_getspecific(elf_file_paths_tls_key)); - elf_file_paths->push_back(path); - } - /// We go through the files of the newer (second) pkg to look for - /// suppression specifications, matching the "*.abignore" name pattern. - else if (prog_options->abignore && string_ends_with(fpath, ".abignore")) - prog_options->suppression_paths.push_back(fpath); - - return 0; -} /// Check that the suppression specification files supplied are /// present. If not, emit an error on stderr. @@ -1061,7 +989,7 @@ compare(const elf_file& elf1, char *di_dir1 = (char*) debug_dir1.c_str(), *di_dir2 = (char*) debug_dir2.c_str(); - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "Comparing the ABIs of file " << elf1.path @@ -1080,7 +1008,7 @@ compare(const elf_file& elf1, if (files_suppressed) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " input file " << elf1.path << " or " << elf2.path @@ -1103,7 +1031,7 @@ compare(const elf_file& elf1, ++i) supprs.push_back(*i); - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " Reading file " << elf1.path @@ -1118,7 +1046,7 @@ compare(const elf_file& elf1, if (!(c1_status & abigail::dwarf_reader::STATUS_OK)) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "Could not read file '" << elf1.path @@ -1139,13 +1067,13 @@ compare(const elf_file& elf1, return abigail::tools_utils::ABIDIFF_ERROR; } - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " DONE reading file " << elf1.path << "\n"; - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " Reading file " << elf2.path @@ -1160,7 +1088,7 @@ compare(const elf_file& elf1, if (!(c2_status & abigail::dwarf_reader::STATUS_OK)) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "Could not find the read file '" << elf2.path @@ -1183,11 +1111,11 @@ compare(const elf_file& elf1, return abigail::tools_utils::ABIDIFF_ERROR; } - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " DONE reading file " << elf2.path << "\n"; - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " Comparing the ABIs of: \n" << " " << elf1.path << "\n" @@ -1195,7 +1123,7 @@ compare(const elf_file& elf1, diff = compute_diff(corpus1, corpus2, ctxt); - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "Comparing the ABIs of file " << elf1.path @@ -1212,71 +1140,218 @@ compare(const elf_file& elf1, return s; } -/// A wrapper to call compare in a separate thread. -/// The result of the comparison is saved to a global corpus map. +/// If devel packages were associated to the main package we are +/// looking at, use the names of the header files (extracted from the +/// package) to generate suppression specification to filter out types +/// that are not defined in those header files. /// -/// @args the vector of argument sets used for comparison. +/// Filtering out types not defined in publi headers amounts to filter +/// out types that are deemed private to the package we are looking +/// at. /// -/// @return the status of the comparison via pthread_exit(). -static void -pthread_routine_compare(vector *args) +/// If the function succeeds, the generated private type suppressions +/// are available by invoking the +/// package::private_types_suppressions() accessor of the @p pkg +/// parameter. +/// +/// @param pkg the main package we are looking at. +/// +/// @param opts the options of the current program. +/// +/// @return true iff suppression specifications were generated for +/// types private to the package. +static bool +maybe_create_private_types_suppressions(package& pkg, const options &opts) { - abidiff_status s, status = abigail::tools_utils::ABIDIFF_OK; - compare_args_sptr a; - corpus_diff_sptr diff; - diff_context_sptr ctxt; + if (!pkg.private_types_suppressions().empty()) + return false; - while (true) - { - pthread_mutex_lock(&arg_lock); - if (args->empty()) - a = compare_args_sptr(); - else - { - a = *args->begin(); - args->erase(args->begin()); - } - pthread_mutex_unlock(&arg_lock); + package_sptr devel_pkg = pkg.devel_package(); + if (!devel_pkg + || !file_exists(devel_pkg->extracted_dir_path()) + || !is_dir(devel_pkg->extracted_dir_path())) + return false; - if (!a) - break; + string headers_path = devel_pkg->extracted_dir_path(); + if (devel_pkg->type() == abigail::tools_utils::FILE_TYPE_RPM + ||devel_pkg->type() == abigail::tools_utils::FILE_TYPE_DEB) + // For RPM and DEB packages, header files are under the + // /usr/include sub-directories. + headers_path += "/usr/include"; - abigail::ir::environment_sptr env(new abigail::ir::environment); - status |= s = compare(a->elf1, a->debug_dir1, a->private_types_suppr1, - a->elf2, a->debug_dir2, a->private_types_suppr2, - a->opts, env, diff, ctxt); + if (!is_dir(headers_path)) + return false; - const string key = a->elf1.path; - if ((s & abigail::tools_utils::ABIDIFF_ABI_CHANGE) - || (verbose && diff->has_changes())) - { - const string prefix = " "; - shared_ptr out(new ostringstream); - diff->report(*out, prefix); - pthread_mutex_lock(&map_lock); - reports_map[key] = out; - // We need to keep the environment around, until the corpus is - // report()-ed. - env_map[diff] = env; - pthread_mutex_unlock(&map_lock); - } - else - { - pthread_mutex_lock(&map_lock); - if (a->opts.show_identical_binaries) - { - shared_ptr out(new ostringstream); - *out << "No ABI change detected\n"; - reports_map[key] = out; - env_map[diff] = env; - } - else - reports_map[key] = shared_ptr(); - pthread_mutex_unlock(&map_lock); - } + suppression_sptr suppr = + gen_suppr_spec_from_headers(headers_path); + + if (suppr) + { + if (opts.drop_private_types) + suppr->set_drops_artifact_from_ir(true); + pkg.private_types_suppressions().push_back(suppr); } - pthread_exit(new abidiff_status(status)); + return suppr; +} + +/// The task that performs the extraction of the content of a package +/// into a temporary directory. +/// +/// Note that several instanaces of tasks can perform their jobs in +/// parallel. +class pkg_extraction_task : public task +{ + pkg_extraction_task(); + +public: + package &pkg; + const options &opts; + bool is_ok; + + pkg_extraction_task(package &p, const options &o) + : pkg(p), opts(o), is_ok(false) + {} + + /// The job performed by the current task. It's to be performed in + /// parallel with other jobs. + virtual void + perform() + { + is_ok = extract_package(pkg, opts); + } +}; //end class pkg_extraction_task + +/// A convenience typedef for a shared pointer to @f pkg_extraction_task. +typedef shared_ptr pkg_extraction_task_sptr; + +/// The worker task which job is to prepares a package. +/// +/// Preparing a package means: +/// +/// 1/ Extract the package and its ancillary packages. +/// +/// 2/ Analyze the extracted content, map that content so that we +/// determine what the ELF files to be analyze are. +class pkg_prepare_task : public abigail::workers::task +{ + pkg_prepare_task(); + +public: + package &pkg; + options &opts; + bool is_ok; + + pkg_prepare_task(package &p, options &o) + : pkg(p), opts(o), is_ok(false) + {} + + /// The job performed by this task. + virtual void + perform() + { + is_ok = extract_package_and_map_its_content(pkg, opts); + } +}; //end class pkg_prepare_task + +/// A convenience typedef for a shared_ptr to @ref pkg_prepare_task +typedef shared_ptr pkg_prepare_task_sptr; + +/// The worker task which job is to compare two ELF binaries +class compare_task : public abigail::workers::task +{ +public: + + compare_args_sptr args; + abidiff_status status; + ostringstream out; + string pretty_output; + + compare_task() + : status(abigail::tools_utils::ABIDIFF_OK) + {} + + compare_task(const compare_args_sptr& a) + : args(a), + status(abigail::tools_utils::ABIDIFF_OK) + {} + + /// The job performed by the task. + /// + /// This compares two ELF files, gets the resulting test report and + /// stores it in an output stream. + virtual void + perform() + { + abigail::ir::environment_sptr env(new abigail::ir::environment); + diff_context_sptr ctxt; + corpus_diff_sptr diff; + + status |= compare(args->elf1, args->debug_dir1, args->private_types_suppr1, + args->elf2, args->debug_dir2, args->private_types_suppr2, + args->opts, env, diff, ctxt); + + if ((status & abigail::tools_utils::ABIDIFF_ABI_CHANGE) + || (args->opts.verbose && diff->has_changes())) + diff->report(out, /*prefix=*/" "); + else + { + if (args->opts.show_identical_binaries) + out << "No ABI change detected\n"; + } + + if (status != abigail::tools_utils::ABIDIFF_OK) + { + string name = args->elf1.name; + + pretty_output = + string("================ changes of '") + name + "'===============\n" + + out.str() + + + "================ end of changes of '" + + name + "'===============\n\n"; + } + } +}; // end class compare_task + +/// Convenience typedef for a shared_ptr of @ref compare_task. +typedef shared_ptr compare_task_sptr; + +/// This function is sub-routine of create_maps_of_package_content. +/// +/// It's called during the walking of the directory tree containing +/// the extracted content of package. It's called with an entry of +/// that directory tree. +/// +/// Depending on the kind of file this function is called on, it +/// updates the vector of paths of the directory and the set of +/// suppression paths found. +/// +/// @param entry the directory entry to analyze. +/// +/// @param opts the options of the current program. +/// +/// @param paths out parameter. This is the set of meaningful paths +/// of the current directory tree being analyzed. These paths are +/// those that are going to be involved in ABI comparison. +static void +maybe_update_vector_of_package_content(const FTSENT *entry, + options &opts, + vector& paths) +{ + if (entry == NULL + || (entry->fts_info != FTS_F && entry->fts_info != FTS_SL) + || entry->fts_info == FTS_ERR + || entry->fts_info == FTS_NS) + return; + + string path = entry->fts_path; + maybe_get_symlink_target_file_path(path, path); + + if (guess_file_type(path) == abigail::tools_utils::FILE_TYPE_ELF) + paths.push_back(path); + else if (opts.abignore && string_ends_with(path, ".abignore")) + opts.suppression_paths.push_back(path); } /// Create maps of the content of a given package. @@ -1292,14 +1367,9 @@ pthread_routine_compare(vector *args) /// /// @param true upon successful completion, false otherwise. static bool -create_maps_of_package_content(package& package, - const options& opts, - ftw_cb_type callback) +create_maps_of_package_content(package& package, options& opts) { - vector *elf_file_paths = new vector; - pthread_setspecific(elf_file_paths_tls_key, elf_file_paths); - - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "Analyzing the content of package " << package.path() @@ -1307,22 +1377,25 @@ create_maps_of_package_content(package& package, << package.extracted_dir_path() << " ...\n"; - if (ftw(package.extracted_dir_path().c_str(), callback, 16)) - { - emit_prefix("abipkgdiff", cerr) - << "Error while inspecting files in package" - << package.extracted_dir_path() << "\n"; - return false; - } + bool is_ok = false; + char* paths[] = {const_cast(package.extracted_dir_path().c_str()), 0}; + + FTS *file_hierarchy = fts_open(paths, FTS_LOGICAL|FTS_NOCHDIR, NULL); + if (!file_hierarchy) + return is_ok; + + vector elf_file_paths; + FTSENT *entry; + while ((entry = fts_read(file_hierarchy))) + maybe_update_vector_of_package_content(entry, opts, elf_file_paths); - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) - << "Found " << elf_file_paths->size() << " files in " + << "Found " << elf_file_paths.size() << " files in " << package.extracted_dir_path() << "\n"; - for (vector::const_iterator file = - elf_file_paths->begin(); - file != elf_file_paths->end(); + for (vector::const_iterator file = elf_file_paths.begin(); + file != elf_file_paths.end(); ++file) { elf_file_sptr e (new elf_file(*file)); @@ -1330,7 +1403,7 @@ create_maps_of_package_content(package& package, { if (e->type != abigail::dwarf_reader::ELF_TYPE_DSO) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "skipping non-DSO file " << e->path << "\n"; continue; @@ -1342,7 +1415,7 @@ create_maps_of_package_content(package& package, && e->type != abigail::dwarf_reader::ELF_TYPE_EXEC && e->type != abigail::dwarf_reader::ELF_TYPE_PI_EXEC) { - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << "skipping non-DSO non-executable file " << e->path << "\n"; continue; @@ -1355,245 +1428,114 @@ create_maps_of_package_content(package& package, package.path_elf_file_sptr_map()[e->soname] = e; } - pthread_setspecific(elf_file_paths_tls_key, /*value=*/NULL); - delete elf_file_paths; - - if (verbose) + if (opts.verbose) emit_prefix("abipkgdiff", cerr) << " Analysis of " << package.path() << " DONE\n"; - return true; -} - -/// If devel packages were associated to the main package we are -/// looking at, use the names of the header files (extracted from the -/// package) to generate suppression specification to filter out types -/// that are not defined in those header files. -/// -/// Filtering out types not defined in publi headers amounts to filter -/// out types that are deemed private to the package we are looking -/// at. -/// -/// If the function succeeds, the generated private type suppressions -/// are available by invoking the -/// package::private_types_suppressions() accessor of the @p pkg -/// parameter. -/// -/// @param pkg the main package we are looking at. -/// -/// @return true iff suppression specifications were generated for -/// types private to the package. -static bool -maybe_create_private_types_suppressions(package_descriptor& desc) -{ - package& pkg = desc.pkg; - if (!pkg.private_types_suppressions().empty()) - return false; - - package_sptr devel_pkg = pkg.devel_package(); - if (!devel_pkg - || !file_exists(devel_pkg->extracted_dir_path()) - || !is_dir(devel_pkg->extracted_dir_path())) - return false; - - string headers_path = devel_pkg->extracted_dir_path(); - if (devel_pkg->type() == abigail::tools_utils::FILE_TYPE_RPM - ||devel_pkg->type() == abigail::tools_utils::FILE_TYPE_DEB) - // For RPM and DEB packages, header files are under the - // /usr/include sub-directories. - headers_path += "/usr/include"; + is_ok = true; - if (!is_dir(headers_path)) - return false; - - suppression_sptr suppr = - gen_suppr_spec_from_headers(headers_path); - - if (suppr) - { - if (desc.opts.drop_private_types) - suppr->set_drops_artifact_from_ir(true); - pkg.private_types_suppressions().push_back(suppr); - } - - return suppr; + return is_ok; } -static inline bool -pthread_join(pthread_t thr) -{ - bool *thread_retval; - if (!pthread_join(thr, reinterpret_cast(&thread_retval))) - { - bool retval = *thread_retval; - delete thread_retval; - return retval; - } - else - return false; -} - -/// Extract the content of a package and map its content. -/// Also extract its accompanying debuginfo package. +/// Extract the content of a package (and its ancillary packages) and +/// map its content. /// -/// The extracting is done to a temporary directory. +/// First, the content of the package and its ancillary packages are +/// extracted, in parallel. /// -/// @param a the set of arguments needed for successful extraction; -/// specifically the package itself, the options the current package has been -/// called with and a callback to traverse the directory structure. +/// Then, after that extraction is done, the content of the package if +/// walked and analyzed. /// -/// @return via pthread_exit() true upon successful completion, false -/// otherwise. -static void -pthread_routine_extract_pkg_and_map_its_content(package_descriptor *a) +/// @param pkg the package to extract and to analyze. +/// +/// @param opts the options of the current program. +/// +/// @return true iff the extraction and analyzing went well. +static bool +extract_package_and_map_its_content(package &pkg, options &opts) { - pthread_t thr_pkg, thr_debug, thr_devel; - package& package = a->pkg; - const options& opts = a->opts; - ftw_cb_type callback = a->callback; - bool has_debug_info_pkg, has_devel_pkg, result = true; - - // The debug-info package usually takes longer to extract than the main - // package plus that package's mapping for ELFs and optionally suppression - // specs, so we run it ASAP. - if ((has_debug_info_pkg = package.debug_info_package())) - { - if (pthread_create(&thr_debug, /*attr=*/NULL, - reinterpret_cast(pthread_routine_extract_package), - package.debug_info_package().get())) - { - result = false; - goto exit; - } - // Wait for debug-info package extraction to complete if we're - // not running in parallel. - if (!opts.parallel) - { - result = pthread_join(thr_debug); - if (!result) - goto exit; - } - } + pkg_extraction_task_sptr main_pkg_extraction; + pkg_extraction_task_sptr dbg_extraction; + pkg_extraction_task_sptr devel_extraction; - if ((has_devel_pkg = package.devel_package())) - { - // A devel package was provided for 'package'. Let's extract it - // too. - if (pthread_create(&thr_devel, /*attr=*/NULL, - reinterpret_cast - (pthread_routine_extract_package), - package.devel_package().get())) - { - result = false; - goto exit; - } + size_t NUM_EXTRACTIONS = 3; - // Wait for devel package extraction to complete if we're - // not running in parallel. - if (!opts.parallel) - { - result = pthread_join(thr_devel); - if (!result) - goto exit; - } - } + main_pkg_extraction.reset(new pkg_extraction_task(pkg, opts)); - // Extract the package itself. - if (pthread_create(&thr_pkg, /*attr=*/NULL, - reinterpret_cast(pthread_routine_extract_package), - &package)) - result = false; + if (package_sptr dbg_pkg = pkg.debug_info_package()) + dbg_extraction.reset(new pkg_extraction_task(*dbg_pkg, opts)); - // We need to wait for the package's successful extraction, if we - // want to do a mapping on its files. - if (result) - result = pthread_join(thr_pkg); + if (package_sptr devel_pkg = pkg.devel_package()) + devel_extraction.reset(new pkg_extraction_task(*devel_pkg, opts)); - // If extracting the package failed, there's no sense in going further. - if (result) - result = create_maps_of_package_content(package, opts, callback); + size_t num_workers = (opts.parallel + ? std::min(opts.num_workers, NUM_EXTRACTIONS) + : 1); + abigail::workers::queue extraction_queue(num_workers); - // Wait for devel package extraction to finish - if (has_devel_pkg && opts.parallel) - result &= pthread_join(thr_devel); + // Perform the extraction of the 3 packages in parallel. + extraction_queue.schedule_task(dbg_extraction); + extraction_queue.schedule_task(main_pkg_extraction); + extraction_queue.schedule_task(devel_extraction); - maybe_create_private_types_suppressions(*a); + // Wait for the extraction to be done. + extraction_queue.wait_for_workers_to_complete(); - // Let's wait for debug package extractions to finish before - // we exit. - if (has_debug_info_pkg && opts.parallel) - result &= pthread_join(thr_debug); + // Analyze and map the content of the extracted package. + bool is_ok = false; + if (main_pkg_extraction->is_ok) + is_ok = create_maps_of_package_content(pkg, opts); -exit: - pthread_exit(new bool(result)); + if (is_ok) + maybe_create_private_types_suppressions(pkg, opts); + return is_ok; } -/// Prepare the packages for comparison. +/// Extract the two packages (and their ancillary packages) and +/// analyze their content, so that we later know what files from the +/// first package to compare against what files from the second +/// package. /// -/// This function extracts the content of each package and maps it. +/// Note that preparing the first package and its ancillary packages +/// happens in parallel with preparing the second package and its +/// ancillary packages. The function then waits for the two +/// preparations to complete before returning. /// -/// @param first_package the first package to prepare. +/// @param first_package the first package to consider. /// -/// @param second_package the second package to prepare. +/// @param second_package the second package to consider. /// -/// @param opts the options the current program has been called with. +/// @param opts the options of the current program. /// -/// @return true upon successful completion, false otherwise. +/// @return true iff the preparation went well. static bool -prepare_packages(package& first_package, - package& second_package, - const options& opts) +prepare_packages(package &first_package, package &second_package, options &opts) { - bool result = true; - const int npkgs = 2; - pthread_t extract_thread[npkgs]; + pkg_prepare_task_sptr first_pkg_prepare; + pkg_prepare_task_sptr second_pkg_prepare; + size_t NUM_PREPARATIONS = 2; - package_descriptor ea[] = - { - { - first_package, - opts, - first_package_tree_walker_callback_fn - }, - { - second_package, - opts, - second_package_tree_walker_callback_fn - }, - }; - - // Since we can't pass custom arguments to the callback of ftw(), - // and we are going to walk two directory trees in parallel, we - // need a separate thread-local vector of files for each package. - pthread_key_create(&elf_file_paths_tls_key, /*destructor=*/NULL); - - for (int i = 0; i < npkgs; ++i) - { - pthread_create(&extract_thread[i], /*attr=*/NULL, - reinterpret_cast(pthread_routine_extract_pkg_and_map_its_content), - &ea[i]); - - if (!opts.parallel) - // We're not running in parallel, so wait for the first package set to - // finish extracting before starting to work on the second one. - result &= pthread_join(extract_thread[i]); - } + first_pkg_prepare.reset(new pkg_prepare_task(first_package, opts)); + second_pkg_prepare.reset(new pkg_prepare_task(second_package, opts)); - if (opts.parallel) - { - // We're running in parallel, so we collect the threads here. - for (int i = 0; i < npkgs; ++i) - result &= pthread_join(extract_thread[i]); - } + size_t num_workers = (opts.parallel + ? std::min(opts.num_workers, NUM_PREPARATIONS) + : 1); + abigail::workers::queue preparation_queue(num_workers); + + preparation_queue.schedule_task(first_pkg_prepare); + preparation_queue.schedule_task(second_pkg_prepare); + + preparation_queue.wait_for_workers_to_complete(); - pthread_key_delete(elf_file_paths_tls_key); - return result; + return first_pkg_prepare->is_ok && second_pkg_prepare->is_ok; } -/// Compare the added sizes of a ELF pair specified by @a1 -/// with the sizes of a ELF pair from @a2. +/// Compare the added sizes of an ELF pair (specified by a comparison +/// task that compares two ELF files) against the added sizes of a +/// second ELF pair. /// /// Larger filesize strongly raises the possibility of larger debug-info, /// hence longer diff time. For a package containing several relatively @@ -1601,20 +1543,66 @@ prepare_packages(package& first_package, /// the larger ones first. This function is used to order the pairs by /// size, starting from the largest. /// -/// @a1 the first set of arguments containing also the size information about -/// the ELF pair being compared. +/// @param t1 the first comparison task that compares a pair of ELF +/// files. /// -/// @a2 the second set of arguments containing also the size information about -/// the ELF pair being compared. +/// @param t2 the second comparison task that compares a pair of ELF +/// files. +/// +/// @return true if @p task1 is greater than @p task2. bool -elf_size_is_greater(const compare_args_sptr &a1, const compare_args_sptr &a2) +elf_size_is_greater(const task_sptr &task1, + const task_sptr &task2) { - off_t s1 = a1->elf1.size + a1->elf2.size; - off_t s2 = a2->elf1.size + a2->elf2.size; + compare_task_sptr t1 = dynamic_pointer_cast(task1); + compare_task_sptr t2 = dynamic_pointer_cast(task2); + + off_t s1 = t1->args->elf1.size + t1->args->elf2.size; + off_t s2 = t2->args->elf1.size + t2->args->elf2.size; return s1 > s2; } +/// This type is used to notify the calling thread that the comparison +/// of two ELF files is done. +class comparison_done_notify : public abigail::workers::queue::task_done_notify +{ + comparison_done_notify(); + +public: + abi_diff& diff; + abidiff_status status; + + comparison_done_notify(abi_diff &d) + : diff(d), + status(abigail::tools_utils::ABIDIFF_OK) + {} + + /// This operator is invoked by the worker queue whenever a + /// comparison task is done. + /// + /// The operator collects the status of the job of the task and also + /// updates the the count of binaries that have ABI changes. + /// + /// @param task_done the task that is done. + virtual void + operator()(const task_sptr& task_done) + { + compare_task_sptr comp_task = dynamic_pointer_cast(task_done); + assert(comp_task); + + status |= comp_task->status; + + if (status != abigail::tools_utils::ABIDIFF_OK) + { + string name = comp_task->args->elf1.name; + + if (status & abigail::tools_utils::ABIDIFF_ABI_CHANGE) + diff.changed_binaries.push_back(name); + } + } +}; // end struct comparison_done_notify + /// Compare the ABI of two packages /// /// @param first_package the first package to consider. @@ -1627,13 +1615,17 @@ elf_size_is_greater(const compare_args_sptr &a1, const compare_args_sptr &a2) /// @param diff out parameter. If this function returns true, then /// this parameter is set to the result of the comparison. /// +/// @param opts the options of the current program. +/// /// @return the status of the comparison. static abidiff_status -compare(package& first_package, - package& second_package, - const options& opts, - abi_diff& diff) +compare(package& first_package, package& second_package, + abi_diff& diff, options& opts) { + // Prepare (extract and analyze the contents) the packages and their + // ancillary packages. + // + // Note that the package preparations happens in parallel. if (!prepare_packages(first_package, second_package, opts)) return abigail::tools_utils::ABIDIFF_ERROR; @@ -1653,7 +1645,7 @@ compare(package& first_package, abidiff_status status = abigail::tools_utils::ABIDIFF_OK; - vector elf_pairs; + abigail::workers::queue::tasks_type compare_tasks; for (map::iterator it = first_package.path_elf_file_sptr_map().begin(); @@ -1668,15 +1660,19 @@ compare(package& first_package, || iter->second->type == abigail::dwarf_reader::ELF_TYPE_EXEC || iter->second->type == abigail::dwarf_reader::ELF_TYPE_PI_EXEC)) { - elf_pairs.push_back - (compare_args_sptr (new compare_args - (*it->second, - debug_dir1, - first_package.private_types_suppressions(), - *iter->second, - debug_dir2, - second_package.private_types_suppressions(), - opts))); + compare_args_sptr args + (new compare_args(*it->second, + debug_dir1, + first_package.private_types_suppressions(), + *iter->second, + debug_dir2, + second_package.private_types_suppressions(), + opts)); + + compare_task_sptr t(new compare_task(args)); + compare_tasks.push_back(t); + + second_package.path_elf_file_sptr_map().erase(iter); } else { @@ -1686,102 +1682,50 @@ compare(package& first_package, } } + if (compare_tasks.empty()) + return abigail::tools_utils::ABIDIFF_OK; + // Larger elfs are processed first, since it's usually safe to assume // their debug-info is larger as well, but the results are still // in a map ordered by looked up in elf.name order. - std::sort(elf_pairs.begin(), elf_pairs.end(), elf_size_is_greater); - - size_t nprocs = opts.parallel ? sysconf(_SC_NPROCESSORS_ONLN) : 1; - assert(nprocs >= 1); - // There's no reason to spawn more threads than there are pairs to be diffed. - nprocs = std::min(nprocs, elf_pairs.size()); - - // if nprocs is zero, it means we have no binary to compare. - - // We've identified the elf couples to compare, let's spawn NPROCS threads - // to do comparisons. - pthread_t thr; - vector waitlist; - for (size_t i = 0; i < nprocs; ++i) - { - if (!pthread_create(&thr, /*attr=*/NULL, - reinterpret_cast(pthread_routine_compare), - &elf_pairs)) - // Record all the threads we will be waiting for. - waitlist.push_back(thr); - } - - // Let's iterate over the valid ELF pairs in-order again, this time - // waiting for their diffs to come up from the other threads and reporting - // them ASAP. - for (map::iterator it = - first_package.path_elf_file_sptr_map().begin(); - it != first_package.path_elf_file_sptr_map().end(); - ++it) - { - map::iterator iter = - second_package.path_elf_file_sptr_map().find(it->first); - - if (iter != second_package.path_elf_file_sptr_map().end() - && (iter->second->type == abigail::dwarf_reader::ELF_TYPE_DSO - || iter->second->type == abigail::dwarf_reader::ELF_TYPE_EXEC - || iter->second->type == abigail::dwarf_reader::ELF_TYPE_PI_EXEC)) - { - second_package.path_elf_file_sptr_map().erase(iter); - while (true) - { - pthread_mutex_lock(&map_lock); - corpora_report_map::iterator d = reports_map.find(it->second->path); - pthread_mutex_unlock(&map_lock); - - if (d == reports_map.end()) - // No result yet. - continue; - if (!d->second) - // The objects match. - break; - else - { - // Report exist, emit it. - string name = it->second->name; - diff.changed_binaries.push_back(name); - const string prefix = " "; - - cout << "================ changes of '" - << name - << "'===============\n"; - cout << d->second->str(); - - cout << "================ end of changes of '" - << name - << "'===============\n\n"; - - pthread_mutex_lock(&map_lock); - reports_map.erase(d); - pthread_mutex_unlock(&map_lock); - - break; - } - } - } - } - - abidiff_status *s; - // Join the comparison threads and collect the statuses. - for (vector::iterator it = waitlist.begin(); it != waitlist.end(); - ++it) + std::sort(compare_tasks.begin(), compare_tasks.end(), elf_size_is_greater); + + // There's no reason to spawn more workers than there are ELF pairs + // to be compared. + size_t num_workers = (opts.parallel + ? std::min(opts.num_workers, compare_tasks.size()) + : 1); + assert(num_workers >= 1); + + comparison_done_notify notifier(diff); + abigail::workers::queue comparison_queue(num_workers, notifier); + + // Compare all the binaries, in parallel and then wait for the + // comparisons to complete. + comparison_queue.schedule_tasks(compare_tasks); + comparison_queue.wait_for_workers_to_complete(); + + // Get the set of comparison tasks that were perform and sort them. + queue::tasks_type& done_tasks = comparison_queue.get_completed_tasks(); + std::sort(done_tasks.begin(), done_tasks.end(), elf_size_is_greater); + + // Print the reports of the comparison to standard output. + for (queue::tasks_type::const_iterator i = done_tasks.begin(); + i != done_tasks.end(); + ++i) { - pthread_join(*it, reinterpret_cast(&s)); - status |= *s; - delete s; + compare_task_sptr t = dynamic_pointer_cast(*i); + cout << t->pretty_output; } + // Update the count of added binaries. for (map::iterator it = second_package.path_elf_file_sptr_map().begin(); it != second_package.path_elf_file_sptr_map().end(); ++it) diff.added_binaries.push_back(it->second); + // Print information about removed binaries on standard output. if (diff.removed_binaries.size()) { cout << "Removed binaries:\n"; @@ -1799,6 +1743,7 @@ compare(package& first_package, } } + // Print information about added binaries on standard output. if (opts.show_added_binaries && diff.added_binaries.size()) { cout << "Added binaries:\n"; @@ -1816,12 +1761,15 @@ compare(package& first_package, } } + // Erase temporary directory tree we might have left behind. if (!opts.keep_tmp_files) { - erase_created_temporary_directories(first_package, second_package); - erase_created_temporary_directories_parent(); + erase_created_temporary_directories(first_package, second_package, opts); + erase_created_temporary_directories_parent(opts); } + status = notifier.status; + return status; } @@ -1835,10 +1783,10 @@ compare(package& first_package, /// /// @return the status of the comparison. static abidiff_status -compare(package& first_package, package& second_package, const options& opts) +compare(package& first_package, package& second_package, options& opts) { abi_diff diff; - return compare(first_package, second_package, opts, diff); + return compare(first_package, second_package, diff, opts); } /// Parse the command line of the current program. @@ -1964,7 +1912,7 @@ parse_command_line(int argc, char* argv[], options& opts) else if (!strcmp(argv[i], "--fail-no-dbg")) opts.fail_if_no_debug_info = true; else if (!strcmp(argv[i], "--verbose")) - verbose = true; + opts.verbose = true; else if (!strcmp(argv[i], "--no-abignore")) opts.abignore = false; else if (!strcmp(argv[i], "--no-parallel")) @@ -2007,8 +1955,7 @@ int main(int argc, char* argv[]) { options opts(argv[0]); - prog_options = &opts; - vector packages; + if (!parse_command_line(argc, argv, opts)) { if (!opts.wrong_option.empty()) -- 2.34.1