Home | History | Annotate | Download | only in mapi
      1 /*
      2  * Mesa 3-D graphics library
      3  *
      4  * Copyright (C) 2010 LunarG Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included
     14  * in all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     22  * DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors:
     25  *    Chia-I Wu <olv (at) lunarg.com>
     26  */
     27 
     28 #include <stdlib.h>
     29 #include <string.h>
     30 #include <assert.h>
     31 #include "c11/threads.h"
     32 
     33 #include "util/macros.h"
     34 #include "u_current.h"
     35 #include "entry.h"
     36 #include "stub.h"
     37 #include "table.h"
     38 
     39 
     40 struct mapi_stub {
     41    const void *name;
     42    int slot;
     43    mapi_func addr;
     44 };
     45 
     46 /* define public_string_pool and public_stubs */
     47 #define MAPI_TMP_PUBLIC_STUBS
     48 #include "mapi_tmp.h"
     49 
     50 static struct mapi_stub dynamic_stubs[MAPI_TABLE_NUM_DYNAMIC];
     51 static int num_dynamic_stubs;
     52 static int next_dynamic_slot = MAPI_TABLE_NUM_STATIC;
     53 
     54 void
     55 stub_init_once(void)
     56 {
     57    static once_flag flag = ONCE_FLAG_INIT;
     58    call_once(&flag, entry_patch_public);
     59 }
     60 
     61 static int
     62 stub_compare(const void *key, const void *elem)
     63 {
     64    const char *name = (const char *) key;
     65    const struct mapi_stub *stub = (const struct mapi_stub *) elem;
     66    const char *stub_name;
     67 
     68    stub_name = &public_string_pool[(unsigned long) stub->name];
     69 
     70    return strcmp(name, stub_name);
     71 }
     72 
     73 /**
     74  * Return the public stub with the given name.
     75  */
     76 const struct mapi_stub *
     77 stub_find_public(const char *name)
     78 {
     79    return (const struct mapi_stub *) bsearch(name, public_stubs,
     80          ARRAY_SIZE(public_stubs), sizeof(public_stubs[0]), stub_compare);
     81 }
     82 
     83 /**
     84  * Add a dynamic stub.
     85  */
     86 static struct mapi_stub *
     87 stub_add_dynamic(const char *name)
     88 {
     89    struct mapi_stub *stub;
     90    int idx;
     91 
     92    idx = num_dynamic_stubs;
     93    /* minus 1 to make sure we can never reach the last slot */
     94    if (idx >= MAPI_TABLE_NUM_DYNAMIC - 1)
     95       return NULL;
     96 
     97    stub = &dynamic_stubs[idx];
     98 
     99    /* dispatch to the last slot, which is reserved for no-op */
    100    stub->addr = entry_generate(
    101          MAPI_TABLE_NUM_STATIC + MAPI_TABLE_NUM_DYNAMIC - 1);
    102    if (!stub->addr)
    103       return NULL;
    104 
    105    stub->name = (const void *) strdup(name);
    106    /* to be fixed later */
    107    stub->slot = -1;
    108 
    109    num_dynamic_stubs = idx + 1;
    110 
    111    return stub;
    112 }
    113 
    114 /**
    115  * Return the dynamic stub with the given name.  If no such stub exists and
    116  * generate is true, a new stub is generated.
    117  */
    118 struct mapi_stub *
    119 stub_find_dynamic(const char *name, int generate)
    120 {
    121    static mtx_t dynamic_mutex = _MTX_INITIALIZER_NP;
    122    struct mapi_stub *stub = NULL;
    123    int count, i;
    124 
    125    mtx_lock(&dynamic_mutex);
    126 
    127    if (generate)
    128       assert(!stub_find_public(name));
    129 
    130    count = num_dynamic_stubs;
    131    for (i = 0; i < count; i++) {
    132       if (strcmp(name, (const char *) dynamic_stubs[i].name) == 0) {
    133          stub = &dynamic_stubs[i];
    134          break;
    135       }
    136    }
    137 
    138    /* generate a dynamic stub */
    139    if (generate && !stub)
    140          stub = stub_add_dynamic(name);
    141 
    142    mtx_unlock(&dynamic_mutex);
    143 
    144    return stub;
    145 }
    146 
    147 static const struct mapi_stub *
    148 search_table_by_slot(const struct mapi_stub *table, size_t num_entries,
    149                      int slot)
    150 {
    151    size_t i;
    152    for (i = 0; i < num_entries; ++i) {
    153       if (table[i].slot == slot)
    154          return &table[i];
    155    }
    156    return NULL;
    157 }
    158 
    159 const struct mapi_stub *
    160 stub_find_by_slot(int slot)
    161 {
    162    const struct mapi_stub *stub =
    163       search_table_by_slot(public_stubs, ARRAY_SIZE(public_stubs), slot);
    164    if (stub)
    165       return stub;
    166    return search_table_by_slot(dynamic_stubs, num_dynamic_stubs, slot);
    167 }
    168 
    169 void
    170 stub_fix_dynamic(struct mapi_stub *stub, const struct mapi_stub *alias)
    171 {
    172    int slot;
    173 
    174    if (stub->slot >= 0)
    175       return;
    176 
    177    if (alias)
    178       slot = alias->slot;
    179    else
    180       slot = next_dynamic_slot++;
    181 
    182    entry_patch(stub->addr, slot);
    183    stub->slot = slot;
    184 }
    185 
    186 /**
    187  * Return the name of a stub.
    188  */
    189 const char *
    190 stub_get_name(const struct mapi_stub *stub)
    191 {
    192    const char *name;
    193 
    194    if (stub >= public_stubs &&
    195        stub < public_stubs + ARRAY_SIZE(public_stubs))
    196       name = &public_string_pool[(unsigned long) stub->name];
    197    else
    198       name = (const char *) stub->name;
    199 
    200    return name;
    201 }
    202 
    203 /**
    204  * Return the slot of a stub.
    205  */
    206 int
    207 stub_get_slot(const struct mapi_stub *stub)
    208 {
    209    return stub->slot;
    210 }
    211 
    212 /**
    213  * Return the address of a stub.
    214  */
    215 mapi_func
    216 stub_get_addr(const struct mapi_stub *stub)
    217 {
    218    assert(stub->addr || (unsigned int) stub->slot < MAPI_TABLE_NUM_STATIC);
    219    return (stub->addr) ? stub->addr : entry_get_public(stub->slot);
    220 }
    221