module.cc revision f8027005333c88a2f097cfd70d15c3d54c7764ae
172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson/****************************************************************************** 272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * 372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * Copyright (C) 2014 Google, Inc. 472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * 572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * Licensed under the Apache License, Version 2.0 (the "License"); 672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * you may not use this file except in compliance with the License. 772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * You may obtain a copy of the License at: 872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * 972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * http://www.apache.org/licenses/LICENSE-2.0 1072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * 1172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * Unless required by applicable law or agreed to in writing, software 1272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * distributed under the License is distributed on an "AS IS" BASIS, 1372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * See the License for the specific language governing permissions and 1572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * limitations under the License. 1672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson * 1772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson ******************************************************************************/ 1872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 19f8027005333c88a2f097cfd70d15c3d54c7764aeChris Manton#define LOG_TAG "bt_core_module" 2072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 2172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson#include <assert.h> 2272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson#include <dlfcn.h> 2372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson#include <pthread.h> 2472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 250f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/allocator.h" 260f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/hash_map.h" 2795b74f252f534ec757aab1fc08e086e02b2cfe8dSharvil Nanavati#include "btcore/include/module.h" 280f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/osi.h" 2905d0366413bedc16b4189b9e74395fe4b11ba41aZach Johnson#include "osi/include/hash_functions.h" 3044802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h" 3172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 3272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsontypedef enum { 3372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson MODULE_STATE_NONE = 0, 3472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson MODULE_STATE_INITIALIZED = 1, 3572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson MODULE_STATE_STARTED = 2 3672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson} module_state_t; 3772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 3872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonstatic const size_t number_of_metadata_buckets = 42; 3972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonstatic hash_map_t *metadata; 4072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson// Include this lock for now for correctness, while the startup sequence is being refactored 4172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonstatic pthread_mutex_t metadata_lock; 4272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 4372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonstatic bool call_lifecycle_function(module_lifecycle_fn function); 4472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonstatic module_state_t get_module_state(const module_t *module); 4572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonstatic void set_module_state(const module_t *module, module_state_t state); 4672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 4772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonvoid module_management_start(void) { 4872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson metadata = hash_map_new( 4972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson number_of_metadata_buckets, 5072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson hash_function_pointer, 5172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson NULL, 52aa3a0114b6f018d0dd296d5bdb113d2f881cbc51Zach Johnson osi_free, 53aa3a0114b6f018d0dd296d5bdb113d2f881cbc51Zach Johnson NULL 5472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson ); 5572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 5672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson pthread_mutex_init(&metadata_lock, NULL); 5772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson} 5872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 5972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonvoid module_management_stop(void) { 6072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson if (!metadata) 6172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return; 6272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 6372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson hash_map_free(metadata); 6472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson metadata = NULL; 6572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 6672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson pthread_mutex_destroy(&metadata_lock); 6772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson} 6872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 6972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonconst module_t *get_module(const char *name) { 7072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return (module_t *)dlsym(RTLD_DEFAULT, name); 7172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson} 7272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 7372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonbool module_init(const module_t *module) { 7472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(metadata != NULL); 7572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(module != NULL); 7672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(get_module_state(module) == MODULE_STATE_NONE); 7772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 7872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson if (!call_lifecycle_function(module->init)) { 7944802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati LOG_ERROR("%s failed to initialize \"%s\"", __func__, module->name); 8072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return false; 8172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson } 8272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 8372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson set_module_state(module, MODULE_STATE_INITIALIZED); 8472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return true; 8572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson} 8672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 8772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonbool module_start_up(const module_t *module) { 8872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(metadata != NULL); 8972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(module != NULL); 9072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson // TODO(zachoverflow): remove module->init check once automagic order/call is in place. 9172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson // This hack is here so modules which don't require init don't have to have useless calls 9272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson // as we're converting the startup sequence. 9372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(get_module_state(module) == MODULE_STATE_INITIALIZED || module->init == NULL); 9472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 9572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson if (!call_lifecycle_function(module->start_up)) { 9644802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati LOG_ERROR("%s failed to start up \"%s\"", __func__, module->name); 9772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return false; 9872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson } 9972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 10072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson set_module_state(module, MODULE_STATE_STARTED); 10172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return true; 10272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson} 10372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 10472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonvoid module_shut_down(const module_t *module) { 10572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(metadata != NULL); 10672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(module != NULL); 10772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson module_state_t state = get_module_state(module); 10872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(state <= MODULE_STATE_STARTED); 10972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 11072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson // Only something to do if the module was actually started 11172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson if (state < MODULE_STATE_STARTED) 11272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return; 11372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 11472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson if (!call_lifecycle_function(module->shut_down)) 11544802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati LOG_ERROR("%s found \"%s\" reported failure during shutdown. Continuing anyway.", __func__, module->name); 11672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 11772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson set_module_state(module, MODULE_STATE_INITIALIZED); 11872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson} 11972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 12072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonvoid module_clean_up(const module_t *module) { 12172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(metadata != NULL); 12272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(module != NULL); 12372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson module_state_t state = get_module_state(module); 12472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson assert(state <= MODULE_STATE_INITIALIZED); 12572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 12672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson // Only something to do if the module was actually initialized 12772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson if (state < MODULE_STATE_INITIALIZED) 12872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return; 12972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 13072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson if (!call_lifecycle_function(module->clean_up)) 13144802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati LOG_ERROR("%s found \"%s\" reported failure during cleanup. Continuing anyway.", __func__, module->name); 13272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 13372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson set_module_state(module, MODULE_STATE_NONE); 13472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson} 13572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 13672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonstatic bool call_lifecycle_function(module_lifecycle_fn function) { 13772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson // A NULL lifecycle function means it isn't needed, so assume success 13872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson if (!function) 13972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return true; 14072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 14172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson future_t *future = function(); 14272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 14372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson // A NULL future means synchronous success 14472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson if (!future) 14572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return true; 14672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 14772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson // Otherwise fall back to the future 14872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return future_await(future); 14972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson} 15072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 15172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonstatic module_state_t get_module_state(const module_t *module) { 15272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson pthread_mutex_lock(&metadata_lock); 15372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson module_state_t *state_ptr = hash_map_get(metadata, module); 15472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson pthread_mutex_unlock(&metadata_lock); 15572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 15672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson return state_ptr ? *state_ptr : MODULE_STATE_NONE; 15772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson} 15872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 15972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnsonstatic void set_module_state(const module_t *module, module_state_t state) { 16072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson pthread_mutex_lock(&metadata_lock); 16172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 16272f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson module_state_t *state_ptr = hash_map_get(metadata, module); 16372f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson if (!state_ptr) { 16472f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson state_ptr = osi_malloc(sizeof(module_state_t)); 16572f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson hash_map_set(metadata, module, state_ptr); 16672f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson } 16772f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 16872f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson pthread_mutex_unlock(&metadata_lock); 16972f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson 17072f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson *state_ptr = state; 17172f308ee6d3983ae2c0d67be3de2451f2dd72dcbZach Johnson} 1723c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 1733c511e667e593c8ea594ca24b1d7712214245863Zach Johnson// TODO(zachoverflow): remove when everything modulized 1743c511e667e593c8ea594ca24b1d7712214245863Zach Johnson// Temporary callback-wrapper-related code 1753c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 1763c511e667e593c8ea594ca24b1d7712214245863Zach Johnsontypedef struct { 1773c511e667e593c8ea594ca24b1d7712214245863Zach Johnson const module_t *module; 1783c511e667e593c8ea594ca24b1d7712214245863Zach Johnson thread_t *lifecycle_thread; 1793c511e667e593c8ea594ca24b1d7712214245863Zach Johnson thread_t *callback_thread; // we don't own this thread 1803c511e667e593c8ea594ca24b1d7712214245863Zach Johnson thread_fn callback; 1813c511e667e593c8ea594ca24b1d7712214245863Zach Johnson bool success; 1823c511e667e593c8ea594ca24b1d7712214245863Zach Johnson} callbacked_wrapper_t; 1833c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 1843c511e667e593c8ea594ca24b1d7712214245863Zach Johnsonstatic void run_wrapped_start_up(void *context); 1853c511e667e593c8ea594ca24b1d7712214245863Zach Johnsonstatic void post_result_to_callback(void *context); 1863c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 1873c511e667e593c8ea594ca24b1d7712214245863Zach Johnsonvoid module_start_up_callbacked_wrapper( 1883c511e667e593c8ea594ca24b1d7712214245863Zach Johnson const module_t *module, 1893c511e667e593c8ea594ca24b1d7712214245863Zach Johnson thread_t *callback_thread, 1903c511e667e593c8ea594ca24b1d7712214245863Zach Johnson thread_fn callback) { 1913c511e667e593c8ea594ca24b1d7712214245863Zach Johnson callbacked_wrapper_t *wrapper = osi_calloc(sizeof(callbacked_wrapper_t)); 1923c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 1933c511e667e593c8ea594ca24b1d7712214245863Zach Johnson wrapper->module = module; 1943c511e667e593c8ea594ca24b1d7712214245863Zach Johnson wrapper->lifecycle_thread = thread_new("module_wrapper"); 1953c511e667e593c8ea594ca24b1d7712214245863Zach Johnson wrapper->callback_thread = callback_thread; 1963c511e667e593c8ea594ca24b1d7712214245863Zach Johnson wrapper->callback = callback; 1973c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 1983c511e667e593c8ea594ca24b1d7712214245863Zach Johnson // Run the actual module start up 1993c511e667e593c8ea594ca24b1d7712214245863Zach Johnson thread_post(wrapper->lifecycle_thread, run_wrapped_start_up, wrapper); 2003c511e667e593c8ea594ca24b1d7712214245863Zach Johnson} 2013c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 2023c511e667e593c8ea594ca24b1d7712214245863Zach Johnsonstatic void run_wrapped_start_up(void *context) { 2033c511e667e593c8ea594ca24b1d7712214245863Zach Johnson assert(context); 2043c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 2053c511e667e593c8ea594ca24b1d7712214245863Zach Johnson callbacked_wrapper_t *wrapper = context; 2063c511e667e593c8ea594ca24b1d7712214245863Zach Johnson wrapper->success = module_start_up(wrapper->module); 2073c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 2083c511e667e593c8ea594ca24b1d7712214245863Zach Johnson // Post the result back to the callback 2093c511e667e593c8ea594ca24b1d7712214245863Zach Johnson thread_post(wrapper->callback_thread, post_result_to_callback, wrapper); 2103c511e667e593c8ea594ca24b1d7712214245863Zach Johnson} 2113c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 2123c511e667e593c8ea594ca24b1d7712214245863Zach Johnsonstatic void post_result_to_callback(void *context) { 2133c511e667e593c8ea594ca24b1d7712214245863Zach Johnson assert(context); 2143c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 2153c511e667e593c8ea594ca24b1d7712214245863Zach Johnson callbacked_wrapper_t *wrapper = context; 2163c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 2173c511e667e593c8ea594ca24b1d7712214245863Zach Johnson // Save the values we need for callback 2183c511e667e593c8ea594ca24b1d7712214245863Zach Johnson void *result = wrapper->success ? FUTURE_SUCCESS : FUTURE_FAIL; 2193c511e667e593c8ea594ca24b1d7712214245863Zach Johnson thread_fn callback = wrapper->callback; 2203c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 2213c511e667e593c8ea594ca24b1d7712214245863Zach Johnson // Clean up the resources we used 2223c511e667e593c8ea594ca24b1d7712214245863Zach Johnson thread_stop(wrapper->lifecycle_thread); 2233c511e667e593c8ea594ca24b1d7712214245863Zach Johnson osi_free(wrapper); 2243c511e667e593c8ea594ca24b1d7712214245863Zach Johnson 2253c511e667e593c8ea594ca24b1d7712214245863Zach Johnson callback(result); 2263c511e667e593c8ea594ca24b1d7712214245863Zach Johnson} 227