From: Youngjae Cho Date: Thu, 11 Jan 2024 08:50:58 +0000 (+0900) Subject: halcc: Add support for hal-api dependency checking X-Git-Tag: accepted/tizen/unified/20240116.155507^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=abd4a834b528bc459849b16a4db492a0b3c0f5cf;p=platform%2Fhal%2Fapi%2Fcommon.git halcc: Add support for hal-api dependency checking Optionally, hal-api can specify dependency, name and version of another hal-api, that it must work with. | | | | | AAA | 1.0 | | | BBB | 1.0 | | ... | | | | BBB | 1.5 | | ... | The halcc-object.c now provides - halcc_manifest_validate_hal_dependency() This validates dependencies between hals within manifest. It try to find compatible hal that specified by hal-api dependency. If it couldn't find compatible one for the dependency, the resolution fails and the hal is regarded as not supported. Let's say a manifest contains below specification about 4 hals - AAA@1.5 : success - BBB@2.3 : success - CCC@3.3 : success - DDD@1.0 : success If there are no dependencies between each other, no problem. Case1] If AAA@1.5 depends on YYY@1.0. - AAA@1.5 -> YYY@1.0 : fail, YYY@1.0 is not specified - BBB@2.3 : success - CCC@3.3 : success - DDD@1.0 : success Case2] If AAA@1.5 depends on BBB@1.0. - AAA@1.5 -> BBB@1.0 : fail, BBB@1.0 isn't compatible with the specified BBB@2.3 - BBB@2.3 : success - CCC@3.3 : success - DDD@1.0 : success Caser3] If AAA@1.5 depends on BBB@2.0, CCC@4.0 - AAA@1.5 -> BBB@2.0, CCC@4.0 : fail, BBB@2.0 is backward compatible with the specified BBB@2.3, but CCC@4.0 isn't compatible with the specified CCC@3.3. - BBB@2.3 : success - CCC@3.3 : success - DDD@1.0 : success If multiple dependencies are specified on a hal, it success only when all the dependencies are satisfied. Case4] If AAA@1.5 depends on BBB@2.0 and BBB@2.3 depends on CCC@3.0 and CCC@3.3 depends on DDD@1.5 - AAA@1.5 -> BBB@2.0 : fail, BBB@2.0 is backward compatible with the specified BBB@2.3, but BBB@2.3 has failed to validate dependency - BBB@2.3 -> CCC@3.0 : fail, CCC@3.0 is backward compatible with the specified CCC@3.3, but CCC@3.3 has failed to validate dependency - CCC@3.3 -> DDD@1.5 : fail, DDD@1.5 isn't compatible with the specified DDD@1.0 - DDD@1.0 : success The failure is propagated to all hals that have dependency on that failed hal. Case5] If AAA@1.5 depends on BBB@2.1 and BBB@2.3 depends on CCC@3.0 and CCC@3.3 depends on AAA@1.0 - AAA@1.5 -> BBB@2.1 : fail, cyclic dependency - BBB@2.3 -> CCC@3.0 : fail, cyclic dependency - CCC@3.3 -> AAA@1.0 : fail, cyclic dependency - DDD@1.0 : success All hals that make dependency cycle are failure. Case6] If AAA@1.5 depends on BBB@2.0 and BBB@2.3 depends on CCC@3.0 - AAA@1.5 -> BBB@2.0 : success - BBB@2.3 -> CCC@3.0 : success - CCC@3.3 : success - DDD@1.0 : success In addition, the tool hal-compatibility-checker has changed to validate dependency, by default, before it checks compatibility. Change-Id: I34ce0f78a9ae9c05f65c77b20199353c93072851 Signed-off-by: Youngjae Cho --- diff --git a/halcc/src/hal-compatibility-checker.c b/halcc/src/hal-compatibility-checker.c index 1ee3f64..38272f6 100644 --- a/halcc/src/hal-compatibility-checker.c +++ b/halcc/src/hal-compatibility-checker.c @@ -94,6 +94,7 @@ static void foreach_hal(void *data, void *user_data) halcc_hal *hal; const char *hal_name = NULL; int major, minor; + halcc_dependency_state_e state; halcc_compatibility_e compatible = HALCC_INCOMPATIBLE; hal = (halcc_hal *) data; @@ -109,6 +110,12 @@ static void foreach_hal(void *data, void *user_data) if (halcc_hal_get_version(hal, &major, &minor, NULL) < 0) return; + if (halcc_hal_get_dependency_state(hal, &state) != 0) + return; + + if (state != HALCC_DEPENDENCY_STATE_SUCCESS) + return; + for (module = HAL_MODULE_UNKNOWN; module < HAL_MODULE_END; ++module) { char module_name[128] = { 0 , }; unsigned int abi_version; @@ -162,6 +169,8 @@ int halcc_check_compatibility(const char *hal_api_manifest_dir, if (ret < 0) goto out; + halcc_manifest_validate_hal_dependency(manifest); + callback_data = (struct callback_data) { callback, user_data }; halcc_manifest_foreach_hal(manifest, foreach_hal, &callback_data); diff --git a/halcc/src/halcc-object.c b/halcc/src/halcc-object.c index 96698db..d9de779 100644 --- a/halcc/src/halcc-object.c +++ b/halcc/src/halcc-object.c @@ -532,6 +532,192 @@ void halcc_manifest_foreach_hal(halcc_manifest *manifest, hashtable_foreach(manifest->hals, cb, user_data); } +static void reset_hal_dependency_state(void *data, void *user_data) +{ + halcc_hal *hal = (halcc_hal *) data; + + assert(hal); + + halcc_hal_set_dependency_state(hal, HALCC_DEPENDENCY_STATE_NONE); +} + +/** + * Check whether the dependencies specified by hal->dependencies are satisfied. + * It sets hal->dependency_state and returns the value. + */ +static halcc_dependency_state_e +__validate_hal_dependency_state(halcc_manifest *manifest, halcc_hal *hal) +{ + halcc_hal *dependency; + halcc_dependency_state_e state = HALCC_DEPENDENCY_STATE_FAIL; + GHashTableIter iter; + + assert(manifest); + assert(hal); + + halcc_hal_get_dependency_state(hal, &state); + + /* It has been checked already, return immediately. */ + if (state != HALCC_DEPENDENCY_STATE_NONE) + return state; + + /** + * Mark it as validating is underway. + * + * The dependency_state will eventually be changed into + * HALCC_DEPENDENCY_STATE_SUCCESS or HALCC_DEPENDENCY_STATE_FAIL + * before going out of this function. + */ + halcc_hal_set_dependency_state(hal, HALCC_DEPENDENCY_STATE_VALIDATING); + + /** + * As the hashtable_foreach() only accepts a single parameter, it is + * annoying that passing multiple parameter to iteration callback. + * So exceptionally iterate the hashtable directly instead of using + * hashtable_foreach(). + * + * Iterate over the dependencies of the given hal. Check if there is compatible + * hal with that dependency in the manifest. It will success only when all of the given + * dependencies is compatible with one of a hal from the manifest. Otherwise, resolution + * fails, setting dependency_state to HALCC_DEPENDENCY_STATE_FAIL. + */ + g_hash_table_iter_init(&iter, hal->dependencies); + while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &dependency)) { + const char *dependency_hal_name = NULL; + int dependency_hal_major = 0; + int dependency_hal_minor = 0; + halcc_hal *found = NULL; + int ret; + + halcc_hal_get_name(dependency, &dependency_hal_name); + halcc_hal_get_version(dependency, &dependency_hal_major, &dependency_hal_minor, NULL); + + ret = halcc_manifest_find_hal_forward_compatible(manifest, + dependency_hal_name, dependency_hal_major, dependency_hal_minor, + &found); + if (ret != 0) { /* There is no hal that meets dependency. */ + halcc_hal_set_dependency_state(hal, HALCC_DEPENDENCY_STATE_FAIL); + return HALCC_DEPENDENCY_STATE_FAIL; + } + + /* Recursively validate dependency of the found hal. */ + state = __validate_hal_dependency_state(manifest, found); + + assert(state != HALCC_DEPENDENCY_STATE_NONE); + + if (state == HALCC_DEPENDENCY_STATE_SUCCESS) + continue; + + /** + * The below two cases are possible and they are all regarded as failure. + * + * 1) state == HALCC_DEPENDENCY_STATE_FAIL + * : The found hal has already failed to validate its dependency, + * thus the current hal is also set to fail. + * + * 2) state == HALCC_DEPENDENCY_STATE_VALIDATING + * : Cyclic dependency, fail. + */ + halcc_hal_set_dependency_state(hal, HALCC_DEPENDENCY_STATE_FAIL); + + return HALCC_DEPENDENCY_STATE_FAIL; + } + + halcc_hal_set_dependency_state(hal, HALCC_DEPENDENCY_STATE_SUCCESS); + + return HALCC_DEPENDENCY_STATE_SUCCESS; +} + +static void validate_hal_dependency_state(void *data, void *user_data) +{ + halcc_manifest *manifest; + halcc_hal *hal; + + manifest = (halcc_manifest *) user_data; + hal = (halcc_hal *) data; + + assert(manifest); + assert(hal); + + __validate_hal_dependency_state(manifest, hal); +} + +/** + * Validate dependencies between hals within manifest. + * + * Let's say a manifest contains below specification about 4 hals + * - AAA@1.5 : success + * - BBB@2.3 : success + * - CCC@3.3 : success + * - DDD@1.0 : success + * If there are no dependencies between each other, no problem. + * + * Case1] If AAA@1.5 depends on YYY@1.0. + * - AAA@1.5 -> YYY@1.0 : fail, YYY@1.0 is not specified + * - BBB@2.3 : success + * - CCC@3.3 : success + * - DDD@1.0 : success + * + * Case2] If AAA@1.5 depends on BBB@1.0. + * - AAA@1.5 -> BBB@1.0 : fail, BBB@1.0 isn't compatible with + * the specified BBB@2.3 + * - BBB@2.3 : success + * - CCC@3.3 : success + * - DDD@1.0 : success + * + * Caser3] If AAA@1.5 depends on BBB@2.0, CCC@4.0 + * - AAA@1.5 -> BBB@2.0, CCC@4.0 : fail, BBB@2.0 is backward compatible + * with the specified BBB@2.3, but CCC@4.0 isn't + * compatible with the specified CCC@3.3. + * - BBB@2.3 : success + * - CCC@3.3 : success + * - DDD@1.0 : success + * If multiple dependencies are specified, it success only when all the + * dependencies are satisfied. + * + * Case4] If AAA@1.5 depends on BBB@2.0 + * and BBB@2.3 depends on CCC@3.0 + * and CCC@3.3 depends on DDD@1.5 + * - AAA@1.5 -> BBB@2.0 : fail, BBB@2.0 is backward compatible with the + * specified BBB@2.3, but BBB@2.3 has failed to + * validate dependency + * - BBB@2.3 -> CCC@3.0 : fail, CCC@3.0 is backward compatible with the + * specified CCC@3.3, but CCC@3.3 has failed to + * validate dependency + * - CCC@3.3 -> DDD@1.5 : fail, DDD@1.5 isn't compatible with the + * specified DDD@1.0 + * - DDD@1.0 : success + * The failure is propagated to all hals that have dependency on that + * failed hal. + * + * Case5] If AAA@1.5 depends on BBB@2.1 + * and BBB@2.3 depends on CCC@3.0 + * and CCC@3.3 depends on AAA@1.0 + * - AAA@1.5 -> BBB@2.1 : fail, cyclic dependency + * - BBB@2.3 -> CCC@3.0 : fail, cyclic dependency + * - CCC@3.3 -> AAA@1.0 : fail, cyclic dependency + * - DDD@1.0 : success + * All hals that make dependency cycle are failure. + * + * Case6] If AAA@1.5 depends on BBB@2.0 + * and BBB@2.3 depends on CCC@3.0 + * - AAA@1.5 -> BBB@2.0 : success + * - BBB@2.3 -> CCC@3.0 : success + * - CCC@3.3 : success + * - DDD@1.0 : success + */ +void halcc_manifest_validate_hal_dependency(halcc_manifest *manifest) +{ + if (!manifest) + return; + + /* Reset all */ + halcc_manifest_foreach_hal(manifest, reset_hal_dependency_state, NULL); + + /* Validate dependency */ + halcc_manifest_foreach_hal(manifest, validate_hal_dependency_state, manifest); +} + int halcc_hal_new(halcc_hal **hal) { halcc_hal *h; @@ -694,6 +880,26 @@ void halcc_hal_foreach_interface(halcc_hal *hal, halcc_iter_cb cb, void *user_da hashtable_foreach(hal->interfaces, cb, user_data); } +int halcc_hal_set_dependency_state(halcc_hal *hal, halcc_dependency_state_e dependency_state) +{ + if (!hal) + return -EINVAL; + + hal->dependency_state = dependency_state; + + return 0; +} + +int halcc_hal_get_dependency_state(halcc_hal *hal, halcc_dependency_state_e *dependency_state) +{ + if (!hal || !dependency_state) + return -EINVAL; + + *dependency_state = hal->dependency_state; + + return 0; +} + int halcc_interface_new(halcc_interface **interface) { halcc_interface *iface; diff --git a/halcc/src/halcc-object.h b/halcc/src/halcc-object.h index 799b984..f657617 100644 --- a/halcc/src/halcc-object.h +++ b/halcc/src/halcc-object.h @@ -76,6 +76,7 @@ void halcc_manifest_remove_hal(halcc_manifest *manifest, const char *hal_name, int major, int minor); void halcc_manifest_foreach_hal(halcc_manifest *manifest, halcc_iter_cb cb, void *user_data); +void halcc_manifest_validate_hal_dependency(halcc_manifest *manifest); int halcc_hal_new(halcc_hal **hal); void halcc_hal_free(halcc_hal *hal); @@ -93,6 +94,8 @@ int halcc_hal_add_interface(halcc_hal *hal, halcc_interface *interface); void halcc_hal_remove_interface(halcc_hal *hal, const char *interface_name, const char *instance_id); void halcc_hal_foreach_interface(halcc_hal *hal, halcc_iter_cb cb, void *user_data); +int halcc_hal_set_dependency_state(halcc_hal *hal, halcc_dependency_state_e dependency_state); +int halcc_hal_get_dependency_state(halcc_hal *hal, halcc_dependency_state_e *dependency_state); int halcc_interface_new(halcc_interface **interface); void halcc_interface_free(halcc_interface *interface);