diff options
| author | Chris Manton <cmanton@google.com> | 2014-08-13 16:38:57 -0700 |
|---|---|---|
| committer | Andre Eisenbach <eisenbach@google.com> | 2015-03-16 16:51:38 -0700 |
| commit | 78a51cb6c9efdc643aa812964adf5de6367eb477 (patch) | |
| tree | 100737a63b80336398be44d0e6ae8fdd05f6926e | |
| parent | f95157c12f7fe1cea51bfe60b9d00d1546236b56 (diff) | |
| download | android_system_bt-78a51cb6c9efdc643aa812964adf5de6367eb477.tar.gz android_system_bt-78a51cb6c9efdc643aa812964adf5de6367eb477.tar.bz2 android_system_bt-78a51cb6c9efdc643aa812964adf5de6367eb477.zip | |
counter implementation
| -rw-r--r-- | btcore/Android.mk | 1 | ||||
| -rw-r--r-- | btcore/include/counter.h (renamed from osi/include/counter.h) | 19 | ||||
| -rw-r--r-- | btcore/src/counter.c | 421 | ||||
| -rwxr-xr-x | main/bte_main.c | 5 |
4 files changed, 433 insertions, 13 deletions
diff --git a/btcore/Android.mk b/btcore/Android.mk index 6519374d4..8426bc072 100644 --- a/btcore/Android.mk +++ b/btcore/Android.mk @@ -26,6 +26,7 @@ LOCAL_C_INCLUDES := \ LOCAL_SRC_FILES := \ src/bdaddr.c \ + src/counter.c \ src/module.c \ src/property.c \ src/uuid.c diff --git a/osi/include/counter.h b/btcore/include/counter.h index 891183ecf..d8295176d 100644 --- a/osi/include/counter.h +++ b/btcore/include/counter.h @@ -21,23 +21,16 @@ #include <stdbool.h> #include <stdint.h> -// Used to iterate across all counters. -typedef bool (*counter_iter_cb)(const char *name, uint64_t val, void *context); +#define COUNTER_MODULE "counter_module" -// Global lifecycle -bool counter_init(); -void counter_exit(); +typedef int64_t counter_data_t; -// Accessors. -uint64_t counter_get(const char *name); +// Used to iterate across all counters. +typedef bool (*counter_iter_cb)(const char *name, counter_data_t val, void *context); // Mutators. -void counter_set(const char *name, uint64_t val); -void counter_clear(const char *name); -void counter_inc(const char *name); -void counter_dec(const char *name); -void counter_add(const char *name, uint64_t val); -void counter_sub(const char *name, uint64_t val); +void counter_set(const char *name, counter_data_t val); +void counter_add(const char *name, counter_data_t val); // Iteration. bool counter_foreach(counter_iter_cb, void *context); diff --git a/btcore/src/counter.c b/btcore/src/counter.c new file mode 100644 index 000000000..da0dcc88a --- /dev/null +++ b/btcore/src/counter.c @@ -0,0 +1,421 @@ +/****************************************************************************** + * + * Copyright (C) 2014 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +#define LOG_TAG "bt_counter" + +#include <assert.h> +#include <cutils/log.h> +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <sys/eventfd.h> + +#include "allocator.h" +#include "atomic.h" +#include "counter.h" +#include "hash_functions.h" +#include "hash_map.h" +#include "list.h" +#include "module.h" +#include "osi.h" +#include "socket.h" +#include "thread.h" + +typedef int (*handler_t)(socket_t * socket); + +typedef struct counter_t { + atomic_s64_t val; +} counter_t; + +typedef struct hash_element_t { + const char *key; + counter_t *val; +} hash_element_t; + +typedef struct counter_data_cb_t { + counter_iter_cb counter_iter_cb; + void *user_context; +} counter_data_cb_t; + +typedef struct { + socket_t *socket; + uint8_t buffer[256]; + size_t buffer_size; +} client_t; + +typedef struct { + const char *name; + const char *help; + handler_t handler; +} command_t; + +// Counter core +static hash_map_t *hash_map_counter_; +static pthread_mutex_t hash_map_lock_; +static int counter_cnt_; + +// Counter port access +static socket_t *listen_socket_; +static thread_t *thread_; +static list_t *clients_; + +static void accept_ready(socket_t *socket, void *context); +static void read_ready(socket_t *socket, void *context); +static void client_free(void *ptr); +static const command_t *find_command(const char *name); +static void output(socket_t *socket, const char* format, ...); + +// Commands +static int help(socket_t *socket); +static int show(socket_t *socket); +static int set(socket_t *socket); +static int quit(socket_t *socket); + +static const command_t commands[] = { + { "help", "<command> - show help text for <command>", help}, + { "quit", "<command> - Quit and exit", quit}, + { "set", "<counter> - Set something", set}, + { "show", "<counter> - Show counters", show}, +}; + +static counter_t *counter_new_(counter_data_t initial_val); +static void counter_free_(counter_t *counter); + +static hash_element_t *hash_element_new_(void); +// NOTE: The parameter datatype is void in order to satisfy the hash +// data free function signature +static void hash_element_free_(void *data); + +static struct counter_t *name_to_counter_(const char *name); +static bool counter_foreach_cb_(hash_map_entry_t *hash_map_entry, void *context); + +static bool counter_socket_open(void); +static void counter_socket_close(void); + +static const int COUNTER_NUM_BUCKETS = 53; + +// TODO(cmanton) Friendly interface, but may remove for automation +const char *WELCOME = "Welcome to counters\n"; +const char *PROMPT = "\n> "; +const char *GOODBYE = "Quitting... Bye !!"; + +// TODO(cmanton) Develop port strategy; or multiplex all bt across single port +static const port_t LISTEN_PORT = 8879; + +static future_t *counter_init(void) { + assert(hash_map_counter_ == NULL); + pthread_mutex_init(&hash_map_lock_, NULL); + hash_map_counter_ = hash_map_new(COUNTER_NUM_BUCKETS, hash_function_string, + NULL, hash_element_free_); + if (hash_map_counter_ == NULL) { + ALOGE("%s unable to allocate resources", __func__); + return future_new_immediate(FUTURE_FAIL); + } + + if (!counter_socket_open()) { + ALOGE("%s unable to open counter port", __func__); + return future_new_immediate(FUTURE_FAIL); + } + return future_new_immediate(FUTURE_SUCCESS); +} + +static future_t *counter_clean_up(void) { + counter_socket_close(); + hash_map_free(hash_map_counter_); + pthread_mutex_destroy(&hash_map_lock_); + hash_map_counter_ = NULL; + return future_new_immediate(FUTURE_SUCCESS); +} + +module_t counter_module = { + .name = COUNTER_MODULE, + .init = counter_init, + .start_up = NULL, + .shut_down = NULL, + .clean_up = counter_clean_up, + .dependencies = {NULL}, +}; + +void counter_set(const char *name, counter_data_t val) { + assert(name != NULL); + counter_t *counter = name_to_counter_(name); + if (counter) + atomic_store_s64(&counter->val, val); +} + +void counter_add(const char *name, counter_data_t val) { + assert(name != NULL); + counter_t *counter = name_to_counter_(name); + if (counter) { + if (val == 1) + atomic_inc_prefix_s64(&counter->val); + else + atomic_add_s64(&counter->val, val); + } +} + +bool counter_foreach(counter_iter_cb cb, void *context) { + assert(cb != NULL); + counter_data_cb_t counter_cb_data = { + cb, + context + }; + + hash_map_foreach(hash_map_counter_, counter_foreach_cb_, &counter_cb_data); + return true; +} + +static counter_t *counter_new_(counter_data_t initial_val) { + counter_t *counter = (counter_t *)osi_calloc(sizeof(counter_t)); + if (!counter) { + return NULL; + } + atomic_store_s64(&counter->val, initial_val); + return counter; +} + +static void counter_free_(counter_t *counter) { + osi_free(counter); +} + +static hash_element_t *hash_element_new_(void) { + return (hash_element_t *)osi_calloc(sizeof(hash_element_t)); +} + +static void hash_element_free_(void *data) { + hash_element_t *hash_element = (hash_element_t *)data; + // We don't own the key + counter_free_(hash_element->val); + osi_free(hash_element); +} + +// Returns a counter from the |hash_map_counter_|. Creates +// a new one if not found and inserts into |hash_map_counter_|. +// Returns NULL upon memory allocation failure. +static counter_t *name_to_counter_(const char *name) { + assert(hash_map_counter_ != NULL); + if (hash_map_has_key(hash_map_counter_, name)) + return (counter_t *)hash_map_get(hash_map_counter_, name); + + pthread_mutex_lock(&hash_map_lock_); + // On the uncommon path double check to make sure that another thread has + // not already created this counter + counter_t *counter = (counter_t *)hash_map_get(hash_map_counter_, name); + if (counter) + goto exit; + + counter = counter_new_(0); + if (!counter) { + ALOGE("%s unable to create new counter name:%s", __func__, name); + goto exit; + } + + hash_element_t *element = hash_element_new_(); + if (!element) { + ALOGE("%s unable to create counter element name:%s", __func__, name); + counter_free_(counter); + counter = NULL; + goto exit; + } + + element->key = name; + element->val = counter; + if (!hash_map_set(hash_map_counter_, name, counter)) { + ALOGE("%s unable to set new counter into hash map name:%s", __func__, name); + hash_element_free_(element); + counter_free_(counter); + counter = NULL; + } + + exit:; + pthread_mutex_unlock(&hash_map_lock_); + return counter; +} + +static bool counter_foreach_cb_(hash_map_entry_t *hash_map_entry, void *context) { + assert(hash_map_entry != NULL); + const char *key = (const char *)hash_map_entry->key; + counter_data_t data = *(counter_data_t *)hash_map_entry->data; + counter_data_cb_t *counter_cb_data = (counter_data_cb_t *)context; + counter_cb_data->counter_iter_cb(key, data, counter_cb_data->user_context); + return true; +} + +static bool counter_socket_open(void) { + assert(listen_socket_ == NULL); + assert(thread_ == NULL); + assert(clients_ == NULL); + + clients_ = list_new(client_free); + if (!clients_) { + ALOGE("%s unable to create counter clients list", __func__); + goto error; + } + + thread_ = thread_new("counter_socket"); + if (!thread_) { + ALOGE("%s unable to create counter thread", __func__); + goto error; + } + + listen_socket_ = socket_new(); + if (!listen_socket_) { + ALOGE("%s unable to create listen socket", __func__); + goto error; + } + + if (!socket_listen(listen_socket_, LISTEN_PORT)) { + ALOGE("%s unable to setup listen socket", __func__); + goto error; + } + + ALOGI("%s opened counter server socket", __func__); + socket_register(listen_socket_, thread_get_reactor(thread_), NULL, accept_ready, NULL); + return true; + +error:; + counter_socket_close(); + return false; +} + +static void counter_socket_close(void) { + socket_free(listen_socket_); + thread_free(thread_); + list_free(clients_); + + listen_socket_ = NULL; + thread_ = NULL; + clients_ = NULL; + + ALOGI("%s closed counter server socket", __func__); +} + +static bool monitor_counter_iter_cb(const char *name, counter_data_t val, void *context) { + socket_t *socket = (socket_t *)context; + output(socket, "counter:%s val:%lld\n", name, val); + return true; +} + +static void client_free(void *ptr) { + if (!ptr) + return; + + client_t *client = (client_t *)ptr; + socket_free(client->socket); + osi_free(client); +} + +static void accept_ready(socket_t *socket, UNUSED_ATTR void *context) { + assert(socket != NULL); + assert(socket == listen_socket_); + + ALOGI("%s accepted OSI monitor socket", __func__); + socket = socket_accept(socket); + if (!socket) + return; + + client_t *client = (client_t *)osi_calloc(sizeof(client_t)); + if (!client) { + ALOGE("%s unable to allocate memory for client", __func__); + socket_free(socket); + return; + } + + client->socket = socket; + + if (!list_append(clients_, client)) { + ALOGE("%s unable to add client to list", __func__); + client_free(client); + return; + } + + socket_register(socket, thread_get_reactor(thread_), client, read_ready, NULL); + + output(socket, WELCOME); + output(socket, PROMPT); +} + +static void read_ready(socket_t *socket, void *context) { + assert(socket != NULL); + + client_t *client = (client_t *)context; + + ssize_t ret = socket_read(socket, client->buffer + client->buffer_size, sizeof(client->buffer) - client->buffer_size); + if (ret == 0 || (ret == -1 && ret != EWOULDBLOCK && ret != EAGAIN)) { + list_remove(clients_, client); + return; + } + + // Replace newline with end of string termination + // TODO(cmanton) Need proper semantics + for (size_t i = ret - 1; i > 0; --i) { + if (client->buffer[i] < 16) + *(client->buffer + i) = 0; + else + break; + } + + const command_t *command = find_command((const char *)client->buffer); + if (!command) { + output(socket, "unable to find command %s\n", client->buffer); + } else { + int rc = command->handler(socket); + if (rc == 1) { + output(socket, GOODBYE); + socket_free(socket); + return; + } + } + output(socket, PROMPT); +} + +static void output(socket_t *socket, const char* format, ...) { + char dest[4096]; + va_list argptr; + va_start(argptr, format); + vsprintf(dest, format, argptr); + va_end(argptr); + socket_write(socket, dest, strlen(dest)); +} + +static int help(UNUSED_ATTR socket_t *socket) { + output(socket, "help command unimplemented\n"); + return 0; +} + +static int quit(UNUSED_ATTR socket_t *socket) { + return 1; +} + +static int set(UNUSED_ATTR socket_t *socket) { + output(socket, "set command unimplemented\n"); + return 0; +} + +static int show(socket_t *socket) { + output(socket, "counter count registered:%d\n", counter_cnt_); + counter_foreach(monitor_counter_iter_cb, (void *)socket); + return 0; +} + +static const command_t *find_command(const char *name) { + for (size_t i = 0; i < ARRAY_SIZE(commands); ++i) + if (!strcmp(commands[i].name, name)) + return &commands[i]; + return NULL; +} diff --git a/main/bte_main.c b/main/bte_main.c index 955a54e3b..e0cc3d50b 100755 --- a/main/bte_main.c +++ b/main/bte_main.c @@ -41,6 +41,7 @@ #include "btu.h" #include "btsnoop.h" #include "bt_utils.h" +#include "counter.h" #include "fixed_queue.h" #include "future.h" #include "gki.h" @@ -92,6 +93,7 @@ fixed_queue_t *btu_hci_msg_queue; void bte_main_boot_entry(void) { module_init(get_module(GKI_MODULE)); + module_init(get_module(COUNTER_MODULE)); hci = hci_layer_get_interface(); if (!hci) @@ -129,6 +131,7 @@ void bte_main_shutdown() module_clean_up(get_module(STACK_CONFIG_MODULE)); + module_clean_up(get_module(COUNTER_MODULE)); module_clean_up(get_module(GKI_MODULE)); } @@ -305,6 +308,8 @@ void bte_main_hci_send (BT_HDR *p_msg, UINT16 event) p_msg->event = event; + counter_add("main.tx.packets", 1); + counter_add("main.tx.bytes", p_msg->len); if((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) || \ (sub_event == LOCAL_BLE_CONTROLLER_ID)) |
