mapi: Add a generic C dispatcher.

The idea is to have an API generate a header using mapi_abi.py.  The API
can then use the header to build a dispatcher.
This commit is contained in:
Chia-I Wu 2010-04-23 16:07:47 +08:00
parent a73c6540d9
commit d4589d3816
12 changed files with 1325 additions and 0 deletions

52
src/mapi/mapi/entry.c Normal file
View file

@ -0,0 +1,52 @@
/*
* Mesa 3-D graphics library
* Version: 7.9
*
* Copyright (C) 2010 LunarG Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Chia-I Wu <olv@lunarg.com>
*/
#include <stdlib.h>
#include "u_current.h"
#include "entry.h"
#include "table.h"
/* C version of the public entries */
#define MAPI_TMP_PUBLIC_ENTRIES
#include "mapi_tmp.h"
void
entry_patch_public(void)
{
}
mapi_func
entry_generate(int slot)
{
return NULL;
}
void
entry_patch(mapi_func entry, int slot)
{
}

49
src/mapi/mapi/entry.h Normal file
View file

@ -0,0 +1,49 @@
/*
* Mesa 3-D graphics library
* Version: 7.9
*
* Copyright (C) 2010 LunarG Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Chia-I Wu <olv@lunarg.com>
*/
#ifndef _ENTRY_H_
#define _ENTRY_H_
#include "u_compiler.h"
#include "stub.h"
/* declare public entries */
#define MAPI_TMP_DEFINES
#define MAPI_TMP_PUBLIC_DECLARES
#include "mapi_tmp.h"
void
entry_patch_public(void);
mapi_func
entry_generate(int slot);
void
entry_patch(mapi_func entry, int slot);
#endif /* _ENTRY_H_ */

191
src/mapi/mapi/mapi.c Normal file
View file

@ -0,0 +1,191 @@
/*
* Mesa 3-D graphics library
* Version: 7.9
*
* Copyright (C) 2010 LunarG Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Chia-I Wu <olv@lunarg.com>
*/
#include <stdlib.h>
#include <string.h>
#include "u_current.h"
#include "u_thread.h"
#include "mapi.h"
#include "stub.h"
#include "table.h"
/* dynamic stubs will run out before this array */
#define MAPI_MAX_STUBS (sizeof(struct mapi_table) / sizeof(mapi_func))
static const struct mapi_stub *mapi_stub_map[MAPI_MAX_STUBS];
static int mapi_num_stubs;
static const struct mapi_stub *
get_stub(const char *name, const struct mapi_stub *alias)
{
const struct mapi_stub *stub;
stub = stub_find_public(name);
if (!stub) {
struct mapi_stub *dyn = stub_find_dynamic(name, 1);
if (dyn) {
stub_fix_dynamic(dyn, alias);
stub = dyn;
}
}
return stub;
}
/**
* Initialize mapi. spec consists of NULL-separated strings. The first string
* denotes the version. It is followed by variable numbers of entries. Each
* entry can have multiple names. An empty name terminates an entry. An empty
* entry terminates the spec. A spec of two entries, Foo and Bar, is as
* follows
*
* "1\0"
* "Foo\0"
* "FooEXT\0"
* "\0"
* "Bar\0"
* "\0"
*/
void
mapi_init(const char *spec)
{
u_mutex_declare_static(mutex);
const char *p;
int ver, count;
u_mutex_lock(mutex);
/* already initialized */
if (mapi_num_stubs) {
u_mutex_unlock(mutex);
return;
}
count = 0;
p = spec;
/* parse version string */
ver = atoi(p);
if (ver != 1) {
u_mutex_unlock(mutex);
return;
}
p += strlen(p) + 1;
while (*p) {
const struct mapi_stub *stub;
stub = get_stub(p, NULL);
/* out of dynamic entries */
if (!stub)
break;
p += strlen(p) + 1;
while (*p) {
get_stub(p, stub);
p += strlen(p) + 1;
}
mapi_stub_map[count++] = stub;
p++;
}
mapi_num_stubs = count;
u_mutex_unlock(mutex);
}
/**
* Return the address of an entry. Optionally generate the entry if it does
* not exist.
*/
mapi_proc
mapi_get_proc_address(const char *name)
{
const struct mapi_stub *stub;
stub = stub_find_public(name);
if (!stub)
stub = stub_find_dynamic(name, 0);
return (stub) ? (mapi_proc) stub->addr : NULL;
}
/**
* Create a dispatch table.
*/
struct mapi_table *
mapi_table_create(void)
{
const struct mapi_table *noop = table_get_noop();
struct mapi_table *tbl;
tbl = malloc(sizeof(*tbl));
if (tbl)
memcpy(tbl, noop, sizeof(*tbl));
return tbl;
}
/**
* Destroy a dispatch table.
*/
void
mapi_table_destroy(struct mapi_table *tbl)
{
free(tbl);
}
/**
* Fill a dispatch table. The order of the procs is determined when mapi_init
* is called.
*/
void
mapi_table_fill(struct mapi_table *tbl, const mapi_proc *procs)
{
const struct mapi_table *noop = table_get_noop();
int i;
for (i = 0; i < mapi_num_stubs; i++) {
const struct mapi_stub *stub = mapi_stub_map[i];
mapi_func func = (mapi_func) procs[i];
if (!func)
func = table_get_func(noop, stub);
table_set_func(tbl, stub, func);
}
}
/**
* Make a dispatch table current.
*/
void
mapi_table_make_current(const struct mapi_table *tbl)
{
u_current_set(tbl);
}

56
src/mapi/mapi/mapi.h Normal file
View file

@ -0,0 +1,56 @@
/*
* Mesa 3-D graphics library
* Version: 7.9
*
* Copyright (C) 2010 LunarG Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Chia-I Wu <olv@lunarg.com>
*/
#ifndef _MAPI_H_
#define _MAPI_H_
#include "u_compiler.h"
typedef void (*mapi_proc)(void);
struct mapi_table;
PUBLIC void
mapi_init(const char *spec);
PUBLIC mapi_proc
mapi_get_proc_address(const char *name);
PUBLIC struct mapi_table *
mapi_table_create(void);
PUBLIC void
mapi_table_destroy(struct mapi_table *tbl);
PUBLIC void
mapi_table_fill(struct mapi_table *tbl, const mapi_proc *procs);
PUBLIC void
mapi_table_make_current(const struct mapi_table *tbl);
#endif /* _MAPI_H_ */

402
src/mapi/mapi/mapi_abi.py Normal file
View file

@ -0,0 +1,402 @@
#!/usr/bin/env python
# Mesa 3-D graphics library
# Version: 7.9
#
# Copyright (C) 2010 LunarG Inc.
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
# Authors:
# Chia-I Wu <olv@lunarg.com>
import sys
import re
from optparse import OptionParser
# number of dynamic entries
ABI_NUM_DYNAMIC_ENTRIES = 256
class ABIEntry(object):
"""Represent an ABI entry."""
_match_c_param = re.compile(
'^(?P<type>[\w\s*]+?)(?P<name>\w+)(\[(?P<array>\d+)\])?$')
def __init__(self, cols, attrs):
self._parse(cols)
self.slot = attrs['slot']
self.hidden = attrs['hidden']
self.alias = attrs['alias']
def c_prototype(self):
return '%s %s(%s)' % (self.c_return(), self.name, self.c_params())
def c_return(self):
ret = self.ret
if not ret:
ret = 'void'
return ret
def c_params(self):
"""Return the parameter list used in the entry prototype."""
c_params = []
for t, n, a in self.params:
sep = '' if t.endswith('*') else ' '
arr = '[%d]' % a if a else ''
c_params.append(t + sep + n + arr)
if not c_params:
c_params.append('void')
return ", ".join(c_params)
def c_args(self):
"""Return the argument list used in the entry invocation."""
c_args = []
for t, n, a in self.params:
c_args.append(n)
return ", ".join(c_args)
def _parse(self, cols):
ret = cols.pop(0)
if ret == 'void':
ret = None
name = cols.pop(0)
params = []
if not cols:
raise Exception(cols)
elif len(cols) == 1 and cols[0] == 'void':
pass
else:
for val in cols:
params.append(self._parse_param(val))
self.ret = ret
self.name = name
self.params = params
def _parse_param(self, c_param):
m = self._match_c_param.match(c_param)
if not m:
raise Exception('unrecognized param ' + c_param)
c_type = m.group('type').strip()
c_name = m.group('name')
c_array = m.group('array')
c_array = int(c_array) if c_array else 0
return (c_type, c_name, c_array)
def __str__(self):
return self.c_prototype()
def __cmp__(self, other):
# compare slot, alias, and then name
res = cmp(self.slot, other.slot)
if not res:
if not self.alias:
res = -1
elif not other.alias:
res = 1
if not res:
res = cmp(self.name, other.name)
return res
def abi_parse_line(line):
cols = [col.strip() for col in line.split(',')]
attrs = {
'slot': -1,
'hidden': False,
'alias': None,
}
# extract attributes from the first column
vals = cols[0].split(':')
while len(vals) > 1:
val = vals.pop(0)
if val.startswith('slot='):
attrs['slot'] = int(val[5:])
elif val == 'hidden':
attrs['hidden'] = True
elif val.startswith('alias='):
attrs['alias'] = val[6:]
elif not val:
pass
else:
raise Exception('unknown attribute %s' % val)
cols[0] = vals[0]
return (attrs, cols)
def abi_parse(filename):
"""Parse a CSV file for ABI entries."""
fp = open(filename) if filename != '-' else sys.stdin
lines = [line.strip() for line in fp.readlines()
if not line.startswith('#') and line.strip()]
entry_dict = {}
next_slot = 0
for line in lines:
attrs, cols = abi_parse_line(line)
# post-process attributes
if attrs['alias']:
try:
ent = entry_dict[attrs['alias']]
slot = ent.slot
except KeyError:
raise Exception('failed to alias %s' % attrs['alias'])
else:
slot = next_slot
next_slot += 1
if attrs['slot'] < 0:
attrs['slot'] = slot
elif attrs['slot'] != slot:
raise Exception('invalid slot in %s' % (line))
ent = ABIEntry(cols, attrs)
if entry_dict.has_key(ent.name):
raise Exception('%s is duplicated' % (ent.name))
entry_dict[ent.name] = ent
entries = entry_dict.values()
entries.sort()
# sanity check
i = 0
for slot in xrange(next_slot):
if entries[i].slot != slot:
raise Exception('entries are not ordered by slots')
if entries[i].alias:
raise Exception('first entry of slot %d aliases %s'
% (slot, entries[i].alias))
while i < len(entries) and entries[i].slot == slot:
i += 1
if i < len(entries):
raise Exception('there are %d invalid entries' % (len(entries) - 1))
return entries
def abi_dynamics():
"""Return the dynamic entries."""
entries = []
for i in xrange(ABI_NUM_DYNAMIC_ENTRIES):
cols = ['void', 'dynamic%d' % (i), 'void']
attrs = { 'slot': -1, 'hidden': False, 'alias': None }
entries.append(ABIEntry(cols, attrs))
return entries
class ABIPrinter(object):
"""ABIEntry Printer"""
def __init__(self, entries, options):
self.entries = entries
self.options = options
self._undefs = []
def _add_undefs(self, undefs):
self._undefs.extend(undefs)
def output_header(self):
print '/* This file is automatically generated. Do not modify. */'
print
def output_footer(self):
print '/* clean up */'
for m in self._undefs:
print '#undef %s' % (m)
def output_entry(self, ent):
if ent.slot < 0:
out_ent = 'MAPI_DYNAMIC_ENTRY(%s, %s, (%s))' % \
(ent.c_return(), ent.name, ent.c_params())
out_code = ''
else:
if ent.alias:
macro_ent = 'MAPI_ALIAS_ENTRY'
macro_code = 'MAPI_ALIAS_CODE'
else:
macro_ent = 'MAPI_ABI_ENTRY'
macro_code = 'MAPI_ABI_CODE'
if ent.ret:
macro_code += '_RETURN'
if ent.hidden:
macro_ent += '_HIDDEN'
macro_code += '_HIDDEN'
if ent.alias:
out_ent = '%s(%s, %s, %s, (%s))' % (macro_ent,
ent.alias, ent.c_return(), ent.name, ent.c_params())
out_code = '%s(%s, %s, %s, (%s))' % (macro_code,
ent.alias, ent.c_return(), ent.name, ent.c_args())
else:
out_ent = '%s(%s, %s, (%s))' % (macro_ent,
ent.c_return(), ent.name, ent.c_params())
out_code = '%s(%s, %s, (%s))' % (macro_code,
ent.c_return(), ent.name, ent.c_args())
print out_ent
if out_code:
print ' ' + out_code
def output_entries(self, pool_offsets):
defs = [
# normal entries
('MAPI_ABI_ENTRY', '(ret, name, params)', ''),
('MAPI_ABI_CODE', '(ret, name, args)', ''),
('MAPI_ABI_CODE_RETURN', '', 'MAPI_ABI_CODE'),
# alias entries
('MAPI_ALIAS_ENTRY', '(alias, ret, name, params)', ''),
('MAPI_ALIAS_CODE', '(alias, ret, name, args)', ''),
('MAPI_ALIAS_CODE_RETURN', '', 'MAPI_ALIAS_CODE'),
# hidden normal entries
('MAPI_ABI_ENTRY_HIDDEN', '', 'MAPI_ABI_ENTRY'),
('MAPI_ABI_CODE_HIDDEN', '', 'MAPI_ABI_CODE'),
('MAPI_ABI_CODE_RETURN_HIDDEN', '', 'MAPI_ABI_CODE_RETURN'),
# hidden alias entries
('MAPI_ALIAS_ENTRY_HIDDEN', '', 'MAPI_ALIAS_ENTRY'),
('MAPI_ALIAS_CODE_HIDDEN', '', 'MAPI_ALIAS_CODE'),
('MAPI_ALIAS_CODE_RETURN_HIDDEN', '', 'MAPI_ALIAS_CODE_RETURN'),
# dynamic entries
('MAPI_DYNAMIC_ENTRY', '(ret, name, params)', ''),
]
undefs = [d[0] for d in defs]
print '#if defined(MAPI_ABI_ENTRY) || defined(MAPI_ABI_ENTRY_HIDDEN)'
print
for d in defs:
print '#ifndef %s' % (d[0])
if d[2]:
print '#define %s%s %s' % d
else:
print '#define %s%s' % d[:2]
print '#endif'
print
print '/* see MAPI_TMP_TABLE */'
for ent in self.entries:
print '#define MAPI_SLOT_%s %d' % (ent.name, ent.slot)
print
print '/* see MAPI_TMP_PUBLIC_STUBS */'
for ent in self.entries:
print '#define MAPI_POOL_%s %d' % (ent.name, pool_offsets[ent])
print
# define macros that generate code
for ent in self.entries:
self.output_entry(ent)
print
dynamics = abi_dynamics()
for ent in dynamics:
self.output_entry(ent)
print
for ent in self.entries:
print '#undef MAPI_SLOT_%s' % (ent.name)
for ent in self.entries:
print '#undef MAPI_POOL_%s' % (ent.name)
print
print '#endif /* defined(MAPI_ABI_ENTRY) || defined(MAPI_ABI_ENTRY_HIDDEN) */'
print
self._add_undefs(undefs)
def _get_string_pool(self):
"""Get the string pool."""
pool = []
offsets = {}
count = 0
for ent in self.entries:
offsets[ent] = count
pool.append(ent.name + '\\0')
count += len(ent.name) + 1
return (pool, offsets)
def output_sorted_indices(self):
entry_index_pairs = []
for i in xrange(len(self.entries)):
entry_index_pairs.append((self.entries[i], i))
entry_index_pairs.sort(lambda x, y: cmp(x[0].name, y[0].name))
print '/* see MAPI_TMP_PUBLIC_STUBS */'
print '#ifdef MAPI_ABI_SORTED_INDICES'
print
print 'static const int MAPI_ABI_SORTED_INDICES[] = {'
for ent, idx in entry_index_pairs:
print ' %d, /* %s */' % (idx, ent.name)
print ' -1'
print '};'
print
print '#endif /* MAPI_ABI_SORTED_INDICES */'
print
self._add_undefs(['MAPI_ABI_SORTED_INDICES'])
def output_defines(self):
print '/* ABI defines */'
print '#ifdef MAPI_ABI_DEFINES'
print '#include "%s"' % (self.options.include)
print '#endif /* MAPI_ABI_DEFINES */'
print
self._add_undefs(['MAPI_ABI_DEFINES'])
def output(self):
pool, pool_offsets = self._get_string_pool()
self.output_header()
self.output_defines()
self.output_entries(pool_offsets)
self.output_sorted_indices()
self.output_footer()
def parse_args():
parser = OptionParser(usage='usage: %prog [options] <filename>')
parser.add_option('-i', '--include', dest='include',
help='include the header for API defines')
options, args = parser.parse_args()
if not args or not options.include:
parser.print_help()
sys.exit(1)
return (args[0], options)
def main():
filename, options = parse_args()
entries = abi_parse(filename)
printer = ABIPrinter(entries, options)
printer.output()
if __name__ == '__main__':
main()

186
src/mapi/mapi/mapi_tmp.h Normal file
View file

@ -0,0 +1,186 @@
/*
* Mesa 3-D graphics library
* Version: 7.9
*
* Copyright (C) 2010 LunarG Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Chia-I Wu <olv@lunarg.com>
*/
#include "u_macros.h"
#ifndef MAPI_ABI_HEADER
#error "MAPI_ABI_HEADER must be defined"
#endif
/**
* Get API defines.
*/
#ifdef MAPI_TMP_DEFINES
# define MAPI_ABI_DEFINES
# include MAPI_ABI_HEADER
#ifndef MAPI_ABI_PREFIX
#error "MAPI_ABI_PREFIX must be defined"
#endif
#ifndef MAPI_ABI_PUBLIC
#error "MAPI_ABI_PUBLIC must be defined"
#endif
#ifndef MAPI_ABI_ATTR
#error "MAPI_ABI_ATTR must be defined"
#endif
#undef MAPI_TMP_DEFINES
#endif /* MAPI_TMP_DEFINES */
/**
* Generate fields of struct mapi_table.
*/
#ifdef MAPI_TMP_TABLE
# define MAPI_ABI_ENTRY(ret, name, params) \
ret (MAPI_ABI_ATTR *name) params;
# define MAPI_DYNAMIC_ENTRY(ret, name, params) \
ret (MAPI_ABI_ATTR *name) params;
# include MAPI_ABI_HEADER
#undef MAPI_TMP_TABLE
#endif /* MAPI_TMP_TABLE */
/**
* Declare public entries.
*/
#ifdef MAPI_TMP_PUBLIC_DECLARES
# define MAPI_ABI_ENTRY(ret, name, params) \
MAPI_ABI_PUBLIC ret MAPI_ABI_ATTR U_CONCAT(MAPI_ABI_PREFIX, name) params;
# define MAPI_ALIAS_ENTRY(alias, ret, name, params) \
MAPI_ABI_ENTRY(ret, name, params);
# define MAPI_ABI_ENTRY_HIDDEN(ret, name, params) \
HIDDEN ret MAPI_ABI_ATTR U_CONCAT(MAPI_ABI_PREFIX, name) params;
# define MAPI_ALIAS_ENTRY_HIDDEN(alias, ret, name, params) \
MAPI_ABI_ENTRY_HIDDEN(ret, name, params)
# include MAPI_ABI_HEADER
#undef MAPI_TMP_PUBLIC_DECLARES
#endif /* MAPI_TMP_PUBLIC_DECLARES */
/**
* Generate string pool and public stubs.
*/
#ifdef MAPI_TMP_PUBLIC_STUBS
/* define the string pool */
static const char public_string_pool[] =
# define MAPI_ABI_ENTRY(ret, name, params) \
U_STRINGIFY(name) "\0"
# define MAPI_ALIAS_ENTRY(alias, ret, name, params) \
MAPI_ABI_ENTRY(ret, name, params)
# include MAPI_ABI_HEADER
;
/* define public_sorted_indices */
# define MAPI_ABI_SORTED_INDICES public_sorted_indices
# include MAPI_ABI_HEADER
/* define public_stubs */
static const struct mapi_stub public_stubs[] = {
# define MAPI_ABI_ENTRY(ret, name, params) \
{ (mapi_func) U_CONCAT(MAPI_ABI_PREFIX, name), \
MAPI_SLOT_ ## name, (void *) MAPI_POOL_ ## name },
# define MAPI_ALIAS_ENTRY(alias, ret, name, params) \
MAPI_ABI_ENTRY(ret, name, params)
# include MAPI_ABI_HEADER
{ NULL, -1, (void *) -1 }
};
#undef MAPI_TMP_PUBLIC_STUBS
#endif /* MAPI_TMP_PUBLIC_STUBS */
/**
* Generate public entries.
*/
#ifdef MAPI_TMP_PUBLIC_ENTRIES
# define MAPI_ABI_ENTRY(ret, name, params) \
ret MAPI_ABI_ATTR U_CONCAT(MAPI_ABI_PREFIX, name) params
# define MAPI_ABI_CODE(ret, name, args) \
{ \
const struct mapi_table *tbl = u_current_get(); \
tbl->name args; \
}
# define MAPI_ABI_CODE_RETURN(ret, name, args) \
{ \
const struct mapi_table *tbl = u_current_get(); \
return tbl->name args; \
}
# define MAPI_ALIAS_ENTRY(alias, ret, name, params) \
MAPI_ABI_ENTRY(ret, name, params)
# define MAPI_ALIAS_CODE(alias, ret, name, args) \
MAPI_ABI_CODE(ret, alias, args)
# define MAPI_ALIAS_CODE_RETURN(alias, ret, name, args) \
MAPI_ABI_CODE_RETURN(ret, alias, args)
# include MAPI_ABI_HEADER
#undef MAPI_TMP_PUBLIC_ENTRIES
#endif /* MAPI_TMP_PUBLIC_ENTRIES */
/**
* Generate noop entries.
*/
#ifdef MAPI_TMP_NOOP_ARRAY
#ifdef DEBUG
# define MAPI_ABI_ENTRY(ret, name, params) \
static ret MAPI_ABI_ATTR U_CONCAT(noop_, name) params
# define MAPI_ABI_CODE(ret, name, args) \
{ \
noop_warn(U_CONCAT_STR(MAPI_ABI_PREFIX, name)); \
}
# define MAPI_ABI_CODE_RETURN(ret, name, args) \
{ \
noop_warn(U_CONCAT_STR(MAPI_ABI_PREFIX, name)); \
return (ret) 0; \
}
# include MAPI_ABI_HEADER
/* define the noop function array that may be casted to mapi_table */
const mapi_func table_noop_array[] = {
# define MAPI_ABI_ENTRY(ret, name, params) \
(mapi_func) U_CONCAT(noop_, name),
# define MAPI_DYNAMIC_ENTRY(ret, name, params) \
(mapi_func) noop_generic,
# include MAPI_ABI_HEADER
(mapi_func) noop_generic
};
#else /* DEBUG */
const mapi_func table_noop_array[] = {
# define MAPI_ABI_ENTRY(ret, name, params) \
(mapi_func) noop_generic,
# define MAPI_DYNAMIC_ENTRY(ret, name, params) \
(mapi_func) noop_generic,
# include MAPI_ABI_HEADER
(mapi_func) noop_generic
};
#endif /* DEBUG */
#undef MAPI_TMP_NOOP_ARRAY
#endif /* MAPI_TMP_NOOP_ARRAY */

View file

@ -1,6 +1,19 @@
# src/mapi/mapi/sources.mak
#
# When MAPI_GLAPI_CURRENT is defined, MAPI_GLAPI_SOURCES can be built without
# MAPI_SOURCES and it is used by glapi.
#
# Otherwise, MAPI_ABI_HEADER must be defined. It should expand to the header
# generated by mapi_abi.py.
MAPI_GLAPI_SOURCES = \
u_current.c \
u_execmem.c \
u_thread.c
MAPI_SOURCES = \
entry.c \
mapi.c \
stub.c \
table.c \
$(MAPI_GLAPI_SOURCES)

180
src/mapi/mapi/stub.c Normal file
View file

@ -0,0 +1,180 @@
/*
* Mesa 3-D graphics library
* Version: 7.9
*
* Copyright (C) 2010 LunarG Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Chia-I Wu <olv@lunarg.com>
*/
#include <stdlib.h>
#include <stddef.h> /* for offsetof */
#include <string.h>
#include <assert.h>
#include "u_current.h"
#include "u_thread.h"
#include "entry.h"
#include "stub.h"
#include "table.h"
#define MAPI_TABLE_FIRST_DYNAMIC \
(offsetof(struct mapi_table, dynamic0) / sizeof(mapi_func))
#define MAPI_TABLE_NUM_DYNAMIC \
((offsetof(struct mapi_table, last) - \
offsetof(struct mapi_table, dynamic0)) / sizeof(mapi_func))
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
/*
* This will define public_string_pool, public_sorted_indices, and
* public_stubs.
*/
#define MAPI_TMP_PUBLIC_STUBS
#include "mapi_tmp.h"
static struct mapi_stub dynamic_stubs[MAPI_TABLE_NUM_DYNAMIC];
static int num_dynamic_stubs;
static int next_dynamic_slot = MAPI_TABLE_FIRST_DYNAMIC;
void
stub_init_once(void)
{
#ifdef PTHREADS
static pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_once(&once, entry_patch_public);
#else
static int first = 1;
if (first) {
first = 0;
entry_patch_public();
}
#endif
}
static int
stub_compare(const void *key, const void *elem)
{
const char *name = (const char *) key;
const int *index = (const int *) elem;
const struct mapi_stub *stub;
const char *stub_name;
stub = &public_stubs[*index];
stub_name = &public_string_pool[(unsigned long) stub->name];
return strcmp(name, stub_name);
}
/**
* Return the public stub with the given name.
*/
const struct mapi_stub *
stub_find_public(const char *name)
{
const int *index;
index = (const int *) bsearch(name, public_sorted_indices,
ARRAY_SIZE(public_sorted_indices) - 1,
sizeof(public_sorted_indices[0]), stub_compare);
return (index) ? &public_stubs[*index] : NULL;
}
/**
* Add a dynamic stub.
*/
static struct mapi_stub *
stub_add_dynamic(const char *name)
{
struct mapi_stub *stub;
int idx;
idx = num_dynamic_stubs;
if (idx >= MAPI_TABLE_NUM_DYNAMIC)
return NULL;
stub = &dynamic_stubs[idx];
/* dispatch to mapi_table->last, which is always no-op */
stub->addr =
entry_generate(MAPI_TABLE_FIRST_DYNAMIC + MAPI_TABLE_NUM_DYNAMIC);
if (!stub->addr)
return NULL;
stub->name = (const void *) name;
/* to be fixed later */
stub->slot = -1;
num_dynamic_stubs = idx + 1;
return stub;
}
/**
* Return the dynamic stub with the given name. If no such stub exists and
* generate is true, a new stub is generated.
*/
struct mapi_stub *
stub_find_dynamic(const char *name, int generate)
{
u_mutex_declare_static(dynamic_mutex);
struct mapi_stub *stub = NULL;
int count, i;
u_mutex_lock(dynamic_mutex);
if (generate)
assert(!stub_find_public(name));
count = num_dynamic_stubs;
for (i = 0; i < count; i++) {
if (strcmp(name, (const char *) dynamic_stubs[i].name) == 0) {
stub = &dynamic_stubs[i];
break;
}
}
/* generate a dynamic stub */
if (generate && !stub)
stub = stub_add_dynamic(name);
u_mutex_unlock(dynamic_mutex);
return stub;
}
void
stub_fix_dynamic(struct mapi_stub *stub, const struct mapi_stub *alias)
{
int slot;
if (stub->slot >= 0)
return;
if (alias)
slot = alias->slot;
else
slot = next_dynamic_slot++;
entry_patch(stub->addr, slot);
stub->slot = slot;
}

52
src/mapi/mapi/stub.h Normal file
View file

@ -0,0 +1,52 @@
/*
* Mesa 3-D graphics library
* Version: 7.9
*
* Copyright (C) 2010 LunarG Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Chia-I Wu <olv@lunarg.com>
*/
#ifndef _STUB_H_
#define _STUB_H_
typedef void (*mapi_func)(void);
struct mapi_stub {
mapi_func addr;
int slot;
const void *name;
};
void
stub_init_once(void);
const struct mapi_stub *
stub_find_public(const char *name);
struct mapi_stub *
stub_find_dynamic(const char *name, int generate);
void
stub_fix_dynamic(struct mapi_stub *stub, const struct mapi_stub *alias);
#endif /* _STUB_H_ */

56
src/mapi/mapi/table.c Normal file
View file

@ -0,0 +1,56 @@
/*
* Mesa 3-D graphics library
* Version: 7.9
*
* Copyright (C) 2010 LunarG Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Chia-I Wu <olv@lunarg.com>
*/
#include <stdlib.h>
#include <stdio.h>
#include "stub.h"
#include "table.h"
static void
noop_warn(const char *name)
{
static int debug = -1;
if (debug < 0)
debug = (getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG"));
if (debug)
fprintf(stderr, "%s is no-op", name);
}
static int
noop_generic(void)
{
noop_warn("function");
return 0;
}
/* define noop_array */
#define MAPI_TMP_NOOP_ARRAY
#include "mapi_tmp.h"

76
src/mapi/mapi/table.h Normal file
View file

@ -0,0 +1,76 @@
/*
* Mesa 3-D graphics library
* Version: 7.9
*
* Copyright (C) 2010 LunarG Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* Authors:
* Chia-I Wu <olv@lunarg.com>
*/
#ifndef _TABLE_H_
#define _TABLE_H_
#include "u_compiler.h"
#include "stub.h"
#define MAPI_TMP_DEFINES
#include "mapi_tmp.h"
struct mapi_table {
#define MAPI_TMP_TABLE
#include "mapi_tmp.h"
mapi_func last;
};
extern const mapi_func table_noop_array[];
/**
* Get the no-op dispatch table.
*/
static INLINE const struct mapi_table *
table_get_noop(void)
{
return (const struct mapi_table *) table_noop_array;
}
/**
* Update the dispatch table to dispatch a stub to the given function.
*/
static INLINE void
table_set_func(struct mapi_table *tbl,
const struct mapi_stub *stub, mapi_func func)
{
mapi_func *funcs = (mapi_func *) tbl;
funcs[stub->slot] = func;
}
/**
* Return the dispatched function of a stub.
*/
static INLINE mapi_func
table_get_func(const struct mapi_table *tbl, const struct mapi_stub *stub)
{
const mapi_func *funcs = (const mapi_func *) tbl;
return funcs[stub->slot];
}
#endif /* _TABLE_H_ */

12
src/mapi/mapi/u_macros.h Normal file
View file

@ -0,0 +1,12 @@
#ifndef _U_MACROS_
#define _U_MACROS_
#define _U_STRINGIFY(x) #x
#define _U_CONCAT(x, y) x ## y
#define _U_CONCAT_STR(x, y) #x#y
#define U_STRINGIFY(x) _U_STRINGIFY(x)
#define U_CONCAT(x, y) _U_CONCAT(x, y)
#define U_CONCAT_STR(x, y) _U_CONCAT_STR(x, y)
#endif /* _U_MACROS_ */