| /* |
| * VMware VMCI Driver |
| * |
| * Copyright (C) 2012 VMware, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation version 2 and no later version. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * for more details. |
| */ |
| |
| #include <linux/slab.h> |
| #include "vmci_handle_array.h" |
| |
| static size_t handle_arr_calc_size(size_t capacity) |
| { |
| return sizeof(struct vmci_handle_arr) + |
| capacity * sizeof(struct vmci_handle); |
| } |
| |
| struct vmci_handle_arr *vmci_handle_arr_create(size_t capacity) |
| { |
| struct vmci_handle_arr *array; |
| |
| if (capacity == 0) |
| capacity = VMCI_HANDLE_ARRAY_DEFAULT_SIZE; |
| |
| array = kmalloc(handle_arr_calc_size(capacity), GFP_ATOMIC); |
| if (!array) |
| return NULL; |
| |
| array->capacity = capacity; |
| array->size = 0; |
| |
| return array; |
| } |
| |
| void vmci_handle_arr_destroy(struct vmci_handle_arr *array) |
| { |
| kfree(array); |
| } |
| |
| void vmci_handle_arr_append_entry(struct vmci_handle_arr **array_ptr, |
| struct vmci_handle handle) |
| { |
| struct vmci_handle_arr *array = *array_ptr; |
| |
| if (unlikely(array->size >= array->capacity)) { |
| /* reallocate. */ |
| struct vmci_handle_arr *new_array; |
| size_t new_capacity = array->capacity * VMCI_ARR_CAP_MULT; |
| size_t new_size = handle_arr_calc_size(new_capacity); |
| |
| new_array = krealloc(array, new_size, GFP_ATOMIC); |
| if (!new_array) |
| return; |
| |
| new_array->capacity = new_capacity; |
| *array_ptr = array = new_array; |
| } |
| |
| array->entries[array->size] = handle; |
| array->size++; |
| } |
| |
| /* |
| * Handle that was removed, VMCI_INVALID_HANDLE if entry not found. |
| */ |
| struct vmci_handle vmci_handle_arr_remove_entry(struct vmci_handle_arr *array, |
| struct vmci_handle entry_handle) |
| { |
| struct vmci_handle handle = VMCI_INVALID_HANDLE; |
| size_t i; |
| |
| for (i = 0; i < array->size; i++) { |
| if (vmci_handle_is_equal(array->entries[i], entry_handle)) { |
| handle = array->entries[i]; |
| array->size--; |
| array->entries[i] = array->entries[array->size]; |
| array->entries[array->size] = VMCI_INVALID_HANDLE; |
| break; |
| } |
| } |
| |
| return handle; |
| } |
| |
| /* |
| * Handle that was removed, VMCI_INVALID_HANDLE if array was empty. |
| */ |
| struct vmci_handle vmci_handle_arr_remove_tail(struct vmci_handle_arr *array) |
| { |
| struct vmci_handle handle = VMCI_INVALID_HANDLE; |
| |
| if (array->size) { |
| array->size--; |
| handle = array->entries[array->size]; |
| array->entries[array->size] = VMCI_INVALID_HANDLE; |
| } |
| |
| return handle; |
| } |
| |
| /* |
| * Handle at given index, VMCI_INVALID_HANDLE if invalid index. |
| */ |
| struct vmci_handle |
| vmci_handle_arr_get_entry(const struct vmci_handle_arr *array, size_t index) |
| { |
| if (unlikely(index >= array->size)) |
| return VMCI_INVALID_HANDLE; |
| |
| return array->entries[index]; |
| } |
| |
| bool vmci_handle_arr_has_entry(const struct vmci_handle_arr *array, |
| struct vmci_handle entry_handle) |
| { |
| size_t i; |
| |
| for (i = 0; i < array->size; i++) |
| if (vmci_handle_is_equal(array->entries[i], entry_handle)) |
| return true; |
| |
| return false; |
| } |
| |
| /* |
| * NULL if the array is empty. Otherwise, a pointer to the array |
| * of VMCI handles in the handle array. |
| */ |
| struct vmci_handle *vmci_handle_arr_get_handles(struct vmci_handle_arr *array) |
| { |
| if (array->size) |
| return array->entries; |
| |
| return NULL; |
| } |