#include "service_registry.h" #include "m-dict.h" #include "m_cstr_dup.h" #include "mutex.h" #include "service_i.h" #include "service_manifest.h" #include "tactility_core.h" #define TAG "service_registry" DICT_DEF2(ServiceManifestDict, const char*, M_CSTR_DUP_OPLIST, const ServiceManifest*, M_PTR_OPLIST) DICT_DEF2(ServiceInstanceDict, const char*, M_CSTR_DUP_OPLIST, const ServiceData*, M_PTR_OPLIST) #define APP_REGISTRY_FOR_EACH(manifest_var_name, code_to_execute) \ { \ service_registry_manifest_lock(); \ ServiceManifestDict_it_t it; \ for (ServiceManifestDict_it(it, service_manifest_dict); !ServiceManifestDict_end_p(it); ServiceManifestDict_next(it)) { \ const ServiceManifest*(manifest_var_name) = ServiceManifestDict_cref(it)->value; \ code_to_execute; \ } \ service_registry_manifest_unlock(); \ } static ServiceManifestDict_t service_manifest_dict; static ServiceInstanceDict_t service_instance_dict; static Mutex* manifest_mutex = NULL; static Mutex* instance_mutex = NULL; void tt_service_registry_init() { tt_assert(manifest_mutex == NULL); manifest_mutex = tt_mutex_alloc(MutexTypeNormal); ServiceManifestDict_init(service_manifest_dict); tt_assert(instance_mutex == NULL); instance_mutex = tt_mutex_alloc(MutexTypeNormal); ServiceInstanceDict_init(service_instance_dict); } void service_registry_instance_lock() { tt_assert(instance_mutex != NULL); tt_mutex_acquire(instance_mutex, TtWaitForever); } void service_registry_instance_unlock() { tt_assert(instance_mutex != NULL); tt_mutex_release(instance_mutex); } void service_registry_manifest_lock() { tt_assert(manifest_mutex != NULL); tt_mutex_acquire(manifest_mutex, TtWaitForever); } void service_registry_manifest_unlock() { tt_assert(manifest_mutex != NULL); tt_mutex_release(manifest_mutex); } void tt_service_registry_add(const ServiceManifest* manifest) { TT_LOG_I(TAG, "adding %s", manifest->id); service_registry_manifest_lock(); ServiceManifestDict_set_at(service_manifest_dict, manifest->id, manifest); service_registry_manifest_unlock(); } void tt_service_registry_remove(const ServiceManifest* manifest) { TT_LOG_I(TAG, "removing %s", manifest->id); service_registry_manifest_lock(); ServiceManifestDict_erase(service_manifest_dict, manifest->id); service_registry_manifest_unlock(); } const ServiceManifest* _Nullable tt_service_registry_find_manifest_by_id(const char* id) { service_registry_manifest_lock(); const ServiceManifest** _Nullable manifest = ServiceManifestDict_get(service_manifest_dict, id); service_registry_manifest_unlock(); return (manifest != NULL) ? *manifest : NULL; } ServiceData* _Nullable service_registry_find_instance_by_id(const char* id) { service_registry_instance_lock(); const ServiceData** _Nullable service_ptr = ServiceInstanceDict_get(service_instance_dict, id); if (service_ptr == NULL) { return NULL; } ServiceData* service = (ServiceData*)*service_ptr; service_registry_instance_unlock(); return service; } void tt_service_registry_for_each_manifest(ServiceManifestCallback callback, void* _Nullable context) { APP_REGISTRY_FOR_EACH(manifest, { callback(manifest, context); }); } // TODO: return proper error/status instead of BOOL bool tt_service_registry_start(const char* service_id) { TT_LOG_I(TAG, "starting %s", service_id); const ServiceManifest* manifest = tt_service_registry_find_manifest_by_id(service_id); if (manifest == NULL) { TT_LOG_E(TAG, "manifest not found for service %s", service_id); return false; } Service service = tt_service_alloc(manifest); manifest->on_start(service); service_registry_instance_lock(); ServiceInstanceDict_set_at(service_instance_dict, manifest->id, service); service_registry_instance_unlock(); TT_LOG_I(TAG, "started %s", service_id); return true; } Service _Nullable tt_service_find(const char* service_id) { service_registry_instance_lock(); const ServiceData** _Nullable service_ptr = ServiceInstanceDict_get(service_instance_dict, service_id); const ServiceData* service = service_ptr ? *service_ptr : NULL; service_registry_instance_unlock(); return (Service)service; } bool tt_service_registry_stop(const char* service_id) { TT_LOG_I(TAG, "stopping %s", service_id); ServiceData* service = service_registry_find_instance_by_id(service_id); if (service == NULL) { TT_LOG_W(TAG, "service not running: %s", service_id); return false; } service->manifest->on_stop(service); tt_service_free(service); service_registry_instance_lock(); ServiceInstanceDict_erase(service_instance_dict, service_id); service_registry_instance_unlock(); TT_LOG_I(TAG, "stopped %s", service_id); return true; }