1321936Shselasky/* 2321936Shselasky * Copyright (c) 2011 Intel Corporation. All rights reserved. 3321936Shselasky * 4321936Shselasky * This software is available to you under a choice of one of two 5321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 6321936Shselasky * General Public License (GPL) Version 2, available from the file 7321936Shselasky * COPYING in the main directory of this source tree, or the 8321936Shselasky * OpenIB.org BSD license below: 9321936Shselasky * 10321936Shselasky * Redistribution and use in source and binary forms, with or 11321936Shselasky * without modification, are permitted provided that the following 12321936Shselasky * conditions are met: 13321936Shselasky * 14321936Shselasky * - Redistributions of source code must retain the above 15321936Shselasky * copyright notice, this list of conditions and the following 16321936Shselasky * disclaimer. 17321936Shselasky * 18321936Shselasky * - Redistributions in binary form must reproduce the above 19321936Shselasky * copyright notice, this list of conditions and the following 20321936Shselasky * disclaimer in the documentation and/or other materials 21321936Shselasky * provided with the distribution. 22321936Shselasky * 23321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30321936Shselasky * SOFTWARE. 31321936Shselasky * 32321936Shselasky */ 33321936Shselasky 34321936Shselasky#include <config.h> 35321936Shselasky 36321936Shselasky#include <errno.h> 37321936Shselasky#include <sys/types.h> 38321936Shselasky#include <stdlib.h> 39321936Shselasky 40321936Shselasky#include "indexer.h" 41321936Shselasky 42321936Shselasky/* 43321936Shselasky * Indexer - to find a structure given an index 44321936Shselasky * 45321936Shselasky * We store pointers using a double lookup and return an index to the 46321936Shselasky * user which is then used to retrieve the pointer. The upper bits of 47321936Shselasky * the index are itself an index into an array of memory allocations. 48321936Shselasky * The lower bits specify the offset into the allocated memory where 49321936Shselasky * the pointer is stored. 50321936Shselasky * 51321936Shselasky * This allows us to adjust the number of pointers stored by the index 52321936Shselasky * list without taking a lock during data lookups. 53321936Shselasky */ 54321936Shselasky 55321936Shselaskystatic int idx_grow(struct indexer *idx) 56321936Shselasky{ 57321936Shselasky union idx_entry *entry; 58321936Shselasky int i, start_index; 59321936Shselasky 60321936Shselasky if (idx->size >= IDX_ARRAY_SIZE) 61321936Shselasky goto nomem; 62321936Shselasky 63321936Shselasky idx->array[idx->size] = calloc(IDX_ENTRY_SIZE, sizeof(union idx_entry)); 64321936Shselasky if (!idx->array[idx->size]) 65321936Shselasky goto nomem; 66321936Shselasky 67321936Shselasky entry = idx->array[idx->size]; 68321936Shselasky start_index = idx->size << IDX_ENTRY_BITS; 69321936Shselasky entry[IDX_ENTRY_SIZE - 1].next = idx->free_list; 70321936Shselasky 71321936Shselasky for (i = IDX_ENTRY_SIZE - 2; i >= 0; i--) 72321936Shselasky entry[i].next = start_index + i + 1; 73321936Shselasky 74321936Shselasky /* Index 0 is reserved */ 75321936Shselasky if (start_index == 0) 76321936Shselasky start_index++; 77321936Shselasky idx->free_list = start_index; 78321936Shselasky idx->size++; 79321936Shselasky return start_index; 80321936Shselasky 81321936Shselaskynomem: 82321936Shselasky errno = ENOMEM; 83321936Shselasky return -1; 84321936Shselasky} 85321936Shselasky 86321936Shselaskyint idx_insert(struct indexer *idx, void *item) 87321936Shselasky{ 88321936Shselasky union idx_entry *entry; 89321936Shselasky int index; 90321936Shselasky 91321936Shselasky if ((index = idx->free_list) == 0) { 92321936Shselasky if ((index = idx_grow(idx)) <= 0) 93321936Shselasky return index; 94321936Shselasky } 95321936Shselasky 96321936Shselasky entry = idx->array[idx_array_index(index)]; 97321936Shselasky idx->free_list = entry[idx_entry_index(index)].next; 98321936Shselasky entry[idx_entry_index(index)].item = item; 99321936Shselasky return index; 100321936Shselasky} 101321936Shselasky 102321936Shselaskyvoid *idx_remove(struct indexer *idx, int index) 103321936Shselasky{ 104321936Shselasky union idx_entry *entry; 105321936Shselasky void *item; 106321936Shselasky 107321936Shselasky entry = idx->array[idx_array_index(index)]; 108321936Shselasky item = entry[idx_entry_index(index)].item; 109321936Shselasky entry[idx_entry_index(index)].next = idx->free_list; 110321936Shselasky idx->free_list = index; 111321936Shselasky return item; 112321936Shselasky} 113321936Shselasky 114321936Shselaskyvoid idx_replace(struct indexer *idx, int index, void *item) 115321936Shselasky{ 116321936Shselasky union idx_entry *entry; 117321936Shselasky 118321936Shselasky entry = idx->array[idx_array_index(index)]; 119321936Shselasky entry[idx_entry_index(index)].item = item; 120321936Shselasky} 121321936Shselasky 122321936Shselasky 123321936Shselaskystatic int idm_grow(struct index_map *idm, int index) 124321936Shselasky{ 125321936Shselasky idm->array[idx_array_index(index)] = calloc(IDX_ENTRY_SIZE, sizeof(void *)); 126321936Shselasky if (!idm->array[idx_array_index(index)]) 127321936Shselasky goto nomem; 128321936Shselasky 129321936Shselasky return index; 130321936Shselasky 131321936Shselaskynomem: 132321936Shselasky errno = ENOMEM; 133321936Shselasky return -1; 134321936Shselasky} 135321936Shselasky 136321936Shselaskyint idm_set(struct index_map *idm, int index, void *item) 137321936Shselasky{ 138321936Shselasky void **entry; 139321936Shselasky 140321936Shselasky if (index > IDX_MAX_INDEX) { 141321936Shselasky errno = ENOMEM; 142321936Shselasky return -1; 143321936Shselasky } 144321936Shselasky 145321936Shselasky if (!idm->array[idx_array_index(index)]) { 146321936Shselasky if (idm_grow(idm, index) < 0) 147321936Shselasky return -1; 148321936Shselasky } 149321936Shselasky 150321936Shselasky entry = idm->array[idx_array_index(index)]; 151321936Shselasky entry[idx_entry_index(index)] = item; 152321936Shselasky return index; 153321936Shselasky} 154321936Shselasky 155321936Shselaskyvoid *idm_clear(struct index_map *idm, int index) 156321936Shselasky{ 157321936Shselasky void **entry; 158321936Shselasky void *item; 159321936Shselasky 160321936Shselasky entry = idm->array[idx_array_index(index)]; 161321936Shselasky item = entry[idx_entry_index(index)]; 162321936Shselasky entry[idx_entry_index(index)] = NULL; 163321936Shselasky return item; 164321936Shselasky} 165