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;
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;