#include #include #include #include #include #include #include #include namespace tt::service { constexpr auto* TAG = "ServiceRegistration"; // Bridges the kernel's C ServiceManifest/Service callbacks to the C++ Service // instances they wrap. Declared extern "C" to match the linkage of the C // function-pointer types they're assigned to (see e.g. gpio_controller.cpp). extern "C" { static void cppDestroyServiceTrampoline(const ::ServiceManifest* /*manifest*/, void* data) { delete static_cast*>(data); } static error_t cppOnStartTrampoline(::ServiceInstance* instance, void* data) { auto& servicePtr = *static_cast*>(data); ServiceContext context(instance); return servicePtr->onStart(context) ? ERROR_NONE : ERROR_RESOURCE; } static void cppOnStopTrampoline(::ServiceInstance* instance, void* data) { auto& servicePtr = *static_cast*>(data); ServiceContext context(instance); servicePtr->onStop(context); } } // extern "C" void addService(std::shared_ptr manifest, bool autoStart) { assert(manifest != nullptr); const auto& id = manifest->id; LOG_I(TAG, "Adding %s", id.c_str()); if (service_manager_find_manifest(id.c_str()) != nullptr) { LOG_E(TAG, "Service id in use: %s", id.c_str()); return; } // Intentionally never freed: removeService() only unregisters the manifest // from the kernel, it doesn't own this allocation. Keeps id's backing // string alive for cManifest.id below. auto* persistentManifest = new std::shared_ptr(manifest); auto* cManifest = new ::ServiceManifest { .id = (*persistentManifest)->id.c_str(), .create_service = (*persistentManifest)->createService, .destroy_service = cppDestroyServiceTrampoline, .on_start = cppOnStartTrampoline, .on_stop = cppOnStopTrampoline, }; error_t error = service_manager_add(cManifest, autoStart); if (error != ERROR_NONE) { LOG_E(TAG, "Failed to add service %s: %s", id.c_str(), error_to_string(error)); } } void addService(const ServiceManifest& manifest, bool autoStart) { addService(std::make_shared(manifest), autoStart); } bool removeService(const std::string& id) { if (service_manager_get_state(id.c_str()) != SERVICE_STATE_STOPPED) { LOG_I(TAG, "Stopping %s before removal", id.c_str()); if (!stopService(id)) { LOG_E(TAG, "Failed to stop %s before removal", id.c_str()); return false; } } LOG_I(TAG, "Removing %s", id.c_str()); error_t error = service_manager_remove(id.c_str()); if (error != ERROR_NONE) { LOG_E(TAG, "Failed to remove service %s: %s", id.c_str(), error_to_string(error)); return false; } LOG_I(TAG, "Removed %s", id.c_str()); return true; } bool removeService(const ServiceManifest& manifest) { return removeService(manifest.id); } const ::ServiceManifest* findManifestById(const std::string& id) { return service_manager_find_manifest(id.c_str()); } bool startService(const std::string& id) { LOG_I(TAG, "Starting %s", id.c_str()); const error_t error = service_manager_start(id.c_str()); if (error != ERROR_NONE) { LOG_E(TAG, "Starting %s failed: %s", id.c_str(), error_to_string(error)); return false; } LOG_I(TAG, "Started %s", id.c_str()); return true; } std::shared_ptr findServiceContextById(const std::string& id) { auto* instance = service_manager_find_instance(id.c_str()); if (instance == nullptr) { return nullptr; } return std::make_shared(instance); } std::shared_ptr findServiceById(const std::string& id) { auto* instance = service_manager_find_instance(id.c_str()); if (instance == nullptr) { return nullptr; } return *static_cast*>(instance->data); } bool stopService(const std::string& id) { LOG_I(TAG, "Stopping %s", id.c_str()); error_t error = service_manager_stop(id.c_str()); if (error != ERROR_NONE) { LOG_W(TAG, "Service not running: %s", id.c_str()); return false; } LOG_I(TAG, "Stopped %s", id.c_str()); return true; } State getState(const std::string& id) { return service_manager_get_state(id.c_str()); } } // namespace