Compare commits

...

2 Commits

Author SHA1 Message Date
be43c289b6 Merge branch 'vmfhrmfoaj-main' containing the new memcached client module
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-06 15:30:53 +09:00
Jinseop Kim
96ece751f7 added memcached module 2024-05-08 10:35:59 +09:00
6 changed files with 566 additions and 1 deletions

View File

@ -253,7 +253,7 @@ AC_CHECK_HEADERS([netinet/in.h sys/un.h netpacket/packet.h net/if.h net/if_dl.h
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h>]) #include <sys/socket.h>])
AC_CHECK_HEADERS([sys/stropts.h sys/macstat.h linux/ethtool.h linux/sockios.h]) AC_CHECK_HEADERS([sys/stropts.h sys/macstat.h linux/ethtool.h linux/sockios.h])
AC_CHECK_HEADERS([ffi.h libunwind.h quadmath.h crt_externs.h uci.h]) AC_CHECK_HEADERS([ffi.h libunwind.h quadmath.h crt_externs.h uci.h libmemcached/memcached.h])
dnl check data types dnl check data types
dnl AC_CHECK_TYPE([wchar_t], dnl AC_CHECK_TYPE([wchar_t],
@ -384,6 +384,14 @@ AC_CHECK_LIB([uci], [uci_alloc_context], [UCI_LIBS="-luci"])
AC_SUBST(UCI_LIBS) AC_SUBST(UCI_LIBS)
AM_CONDITIONAL(HAVE_LIBUCI, test "x${ac_cv_lib_uci_uci_alloc_context}" = "xyes" -a "x${ac_cv_header_uci_h}" = "xyes") AM_CONDITIONAL(HAVE_LIBUCI, test "x${ac_cv_lib_uci_uci_alloc_context}" = "xyes" -a "x${ac_cv_header_uci_h}" = "xyes")
dnl libmemcachd (optional)
AC_CHECK_LIB([memcached], [memcached],
[
MEMCACHED_LIBS="-lmemcached"
AC_DEFINE([HAVE_MEMCACHED_LIB], [1], [libmemcached library is available])
])
AC_SUBST(MEMCACHED_LIBS)
AC_MSG_CHECKING([for va_copy]) AC_MSG_CHECKING([for va_copy])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdarg.h>]], [[ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <stdarg.h>]], [[
va_list x, y; va_list x, y;
@ -1059,6 +1067,30 @@ then
fi fi
AM_CONDITIONAL(ENABLE_MOD_UCI, test "${enable_mod_uci_is}" = "yes") AM_CONDITIONAL(ENABLE_MOD_UCI, test "${enable_mod_uci_is}" = "yes")
dnl ===== enable-mod-memc =====
AC_ARG_ENABLE([mod-memc],
[AS_HELP_STRING([--enable-mod-memc],[enable mod/memc. one of auto, yes, no (default. auto)])],
enable_mod_memc_is=$enableval,
enable_mod_memc_is=auto
)
if test "x${enable_mod_memc_is}" = "xauto"
then
if test "x${ac_cv_header_libmemcached_memcached_h}" != "xyes"
then
enable_mod_memc_is="no"
elif test "x${ac_cv_lib_memcached_memcached}" != "xyes"
then
enable_mod_memc_is="no"
else
enable_mod_memc_is="yes"
fi
fi
if test "x${enable_mod_memc_is}" = "xyes"
then
AC_DEFINE([HAWK_ENABLE_MOD_MEMC],[1],[build mod/memc])
fi
AM_CONDITIONAL(ENABLE_MOD_MEMC, test "${enable_mod_memc_is}" = "yes")
dnl ==== include pthread options to the default flags ==== dnl ==== include pthread options to the default flags ====
dnl keep this as the last option as it changes the default compile flags. dnl otherwise, other tests may get affected if this option is on. dnl keep this as the last option as it changes the default compile flags. dnl otherwise, other tests may get affected if this option is on.
@ -1112,5 +1144,6 @@ echo " Math library: ${LIBM}"
echo " Socket library: ${SOCKET_LIBS}" echo " Socket library: ${SOCKET_LIBS}"
echo " Native function call library: ${FFI_LIBS}" echo " Native function call library: ${FFI_LIBS}"
echo " Thraed library: ${PTHREAD_LIBS}" echo " Thraed library: ${PTHREAD_LIBS}"
echo " Memcached library: ${MEMCACHED_LIBS}"
echo "-------------------------------------------------------------------------" echo "-------------------------------------------------------------------------"
] ]

View File

@ -236,6 +236,10 @@ if ENABLE_MOD_UCI
libhawk_la_LIBADD += ../mod/libhawk-uci.la libhawk_la_LIBADD += ../mod/libhawk-uci.la
endif endif
if ENABLE_MOD_MEMC
libhawk_la_LIBADD += ../mod/libhawk-memc.la
endif
else else
################################################## ##################################################
# DYNAMIC MODULES # DYNAMIC MODULES

View File

@ -7475,6 +7475,10 @@ int hawk_putsrcoochars (hawk_t* hawk, const hawk_ooch_t* str, hawk_oow_t len)
#include "../mod/mod-uci.h" #include "../mod/mod-uci.h"
#endif #endif
#if defined(HAWK_ENABLE_MOD_MEMC)
#include "../mod/mod-memc.h"
#endif
/* /*
* if modules are linked statically into the main hawk module, * if modules are linked statically into the main hawk module,
* this table is used to find the entry point of the modules. * this table is used to find the entry point of the modules.
@ -7503,6 +7507,9 @@ static struct
#if defined(HAWK_ENABLE_MOD_UCI) #if defined(HAWK_ENABLE_MOD_UCI)
{ HAWK_T("uci"), hawk_mod_uci } { HAWK_T("uci"), hawk_mod_uci }
#endif #endif
#if defined(HAWK_ENABLE_MOD_MEMC)
{ HAWK_T("memc"), hawk_mod_memc }
#endif
}; };
#endif #endif

View File

@ -37,6 +37,10 @@ if ENABLE_MOD_UCI
noinst_LTLIBRARIES += libhawk-uci.la noinst_LTLIBRARIES += libhawk-uci.la
endif endif
if ENABLE_MOD_MEMC
noinst_LTLIBRARIES += libhawk-memc.la
endif
################################################## ##################################################
else else
################################################## ##################################################
@ -66,6 +70,10 @@ if ENABLE_MOD_UCI
pkgmodexec_LTLIBRARIES += libhawk-uci.la pkgmodexec_LTLIBRARIES += libhawk-uci.la
endif endif
if ENABLE_MOD_MEMC
pkgmodexec_LTLIBRARIES += libhawk-memc.la
endif
################################################## ##################################################
endif endif
################################################## ##################################################
@ -105,3 +113,11 @@ libhawk_uci_la_CFLAGS = $(CFLAGS_COMMON)
libhawk_uci_la_LDFLAGS = $(LDFLAGS_COMMON) libhawk_uci_la_LDFLAGS = $(LDFLAGS_COMMON)
libhawk_uci_la_LIBADD = $(LIBADD_COMMON) $(UCI_LIBS) libhawk_uci_la_LIBADD = $(LIBADD_COMMON) $(UCI_LIBS)
endif endif
if ENABLE_MOD_MEMC
libhawk_memc_la_SOURCES = mod-memc.c mod-memc.h
libhawk_memc_la_CPPFLAGS = $(CPPFLAGS_COMMON) $(MEMCACHED_CFLAGS)
libhawk_memc_la_CFLAGS = $(CFLAGS_COMMON)
libhawk_memc_la_LDFLAGS = $(LDFLAGS_COMMON) $(MEMCACHED_LDFLAGS)
libhawk_memc_la_LIBADD = $(LIBADD_COMMON) $(MEMCACHED_LIBS)
endif

462
mod/mod-memc.c Normal file
View File

@ -0,0 +1,462 @@
/*
* $Id$
*
Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "mod-memc.h"
#include "../lib/hawk-prv.h"
#include <libmemcached/memcached.h>
#define __IDMAP_NODE_T_DATA memcached_st *memc;
#define __IDMAP_LIST_T_DATA memcached_return_t rc; hawk_ooch_t errmsg[256];
#define __IDMAP_LIST_T memc_list_t
#define __IDMAP_NODE_T memc_node_t
#define __INIT_IDMAP_LIST __init_memc_list
#define __FINI_IDMAP_LIST __fini_memc_list
#define __MAKE_IDMAP_NODE __new_memc_node
#define __FREE_IDMAP_NODE __free_memc_node
#include "../lib/idmap-imp.h"
struct rtx_data_t
{
memc_list_t memc_list;
};
typedef struct rtx_data_t rtx_data_t;
/* ------------------------------------------------------------------------ */
static memc_node_t* new_memc_node (hawk_rtx_t* rtx, memc_list_t* memc_list)
{
memc_node_t* memc_node;
memc_node = __new_memc_node(rtx, memc_list);
if (!memc_node) return HAWK_NULL;
memc_node->memc = HAWK_NULL;
return memc_node;
}
static void free_memc_node (hawk_rtx_t* rtx, memc_list_t* memc_list, memc_node_t* memc_node)
{
if (memc_node->memc != HAWK_NULL) {
memcached_free (memc_node->memc);
memc_node->memc = HAWK_NULL;
}
__free_memc_node (rtx, memc_list, memc_node);
}
static HAWK_INLINE memc_list_t* rtx_to_memc_list (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
{
hawk_rbt_pair_t* pair;
rtx_data_t* data;
pair = hawk_rbt_search((hawk_rbt_t*)fi->mod->ctx, &rtx, HAWK_SIZEOF(rtx));
HAWK_ASSERT (pair != HAWK_NULL);
data = (rtx_data_t*)HAWK_RBT_VPTR(pair);
return &data->memc_list;
}
static void set_error_on_memc_list (hawk_rtx_t* rtx, memc_list_t* memc_list, const hawk_ooch_t* errfmt, ...)
{
if (errfmt)
{
va_list ap;
va_start (ap, errfmt);
hawk_rtx_vfmttooocstr (rtx, memc_list->errmsg, HAWK_COUNTOF(memc_list->errmsg), errfmt, ap);
va_end (ap);
}
else
{
hawk_copy_oocstr (memc_list->errmsg, HAWK_COUNTOF(memc_list->errmsg), hawk_rtx_geterrmsg(rtx));
}
}
static HAWK_INLINE memc_node_t* get_memc_list_node (memc_list_t* memc_list, hawk_int_t id)
{
if (id < 0 || id >= memc_list->map.high || !memc_list->map.tab[id]) return HAWK_NULL;
return memc_list->map.tab[id];
}
static memc_node_t* get_memc_list_node_with_arg (hawk_rtx_t* rtx, memc_list_t* memc_list, hawk_val_t* arg)
{
hawk_int_t id;
memc_node_t* memc_node;
if (hawk_rtx_valtoint(rtx, arg, &id) <= -1)
{
set_error_on_memc_list (rtx, memc_list, HAWK_T("illegal instance id"));
return HAWK_NULL;
}
else if (!(memc_node = get_memc_list_node(memc_list, id)))
{
set_error_on_memc_list (rtx, memc_list, HAWK_T("invalid instance id - %zd"), (hawk_oow_t)id);
return HAWK_NULL;
}
return memc_node;
}
/* ------------------------------------------------------------------------ */
static int fnc_new (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
{
memc_list_t* memc_list;
memc_node_t* memc_node = HAWK_NULL;
hawk_int_t ret = -1;
hawk_val_t* retv;
memc_list = rtx_to_memc_list(rtx, fi);
memc_node = new_memc_node(rtx, memc_list);
if (memc_node) ret = memc_node->id;
else set_error_on_memc_list (rtx, memc_list, HAWK_NULL);
/* ret may not be a statically managed number.
* error checking is required */
retv = hawk_rtx_makeintval(rtx, ret);
if (retv == HAWK_NULL)
{
if (memc_node) free_memc_node (rtx, memc_list, memc_node);
return -1;
}
hawk_rtx_setretval (rtx, retv);
return 0;
}
static int fnc_connect (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
{
memc_list_t* memc_list;
memc_node_t* memc_node;
hawk_val_t* a0;
hawk_bch_t* conf = HAWK_NULL;
hawk_oow_t conf_len = 0;
int ret = -1, take_rtx_err = 0;
memc_list = rtx_to_memc_list(rtx, fi);
memc_node = get_memc_list_node_with_arg(rtx, memc_list, hawk_rtx_getarg(rtx, 0));
if (memc_node)
{
a0 = hawk_rtx_getarg(rtx, 0);
if (!(conf = hawk_rtx_getvalbcstr(rtx, a0, &conf_len)))
{
take_rtx_err = 1;
goto done;
}
memc_node->memc = memcached (conf, conf_len);
if (memc_node->memc == HAWK_NULL)
{
set_error_on_memc_list (rtx, memc_list, HAWK_T("unable to connect to %hs"), conf);
goto done;
}
ret = 0;
}
done:
if (take_rtx_err) set_error_on_memc_list (rtx, memc_list, HAWK_NULL);
if (conf) hawk_rtx_freevalbcstr (rtx, a0, conf);
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
return 0;
}
static int fnc_close (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
{
memc_list_t* memc_list;
memc_node_t* memc_node;
int ret = -1;
memc_list = rtx_to_memc_list(rtx, fi);
memc_node = get_memc_list_node_with_arg(rtx, memc_list, hawk_rtx_getarg(rtx, 0));
if (memc_node)
{
free_memc_node (rtx, memc_list, memc_node);
ret = 0;
}
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
return 0;
}
static int fnc_errmsg (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
{
memc_list_t* memc_list;
hawk_val_t* retv;
memc_list = rtx_to_memc_list(rtx, fi);
retv = hawk_rtx_makestrvalwithoocstr(rtx, memc_list->errmsg);
if (!retv) return -1;
hawk_rtx_setretval (rtx, retv);
return 0;
}
static int fnc_get (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
{
memc_list_t* memc_list;
memc_node_t* memc_node;
int take_rtx_err = 0;
hawk_val_t* a1, * a2;
hawk_bch_t* key = HAWK_NULL;
hawk_bch_t* def_val = HAWK_NULL;
hawk_bch_t* rv = HAWK_NULL;
hawk_oow_t key_len = 0;
hawk_oow_t def_val_len = 0;
hawk_oow_t rv_len = 0;
char* val = HAWK_NULL;
size_t val_len = 0;
memc_list = rtx_to_memc_list(rtx, fi);
memc_node = get_memc_list_node_with_arg(rtx, memc_list, hawk_rtx_getarg(rtx, 0));
if (!memc_node)
{
goto done;
}
else
{
uint32_t flags;
memcached_return_t rc;
hawk_oow_t nargs;
nargs = hawk_rtx_getnargs(rtx);
a1 = hawk_rtx_getarg(rtx, 1);
if (!(key = hawk_rtx_getvalbcstr(rtx, a1, &key_len)))
{
take_rtx_err = 1;
goto done;
}
if (nargs >= 3)
{
a2 = hawk_rtx_getarg(rtx, 2);
if (!(def_val = hawk_rtx_getvalbcstr(rtx, a2, &def_val_len)))
{
take_rtx_err = 1;
goto done;
}
}
val = memcached_get(memc_node->memc, key, key_len, &val_len, &flags, &rc);
if (val == HAWK_NULL) goto done;
rv = val;
rv_len = val_len;
}
done:
if (rv == HAWK_NULL)
{
if (def_val != HAWK_NULL) rv = "";
else
{
rv = def_val;
rv_len = def_val_len;
}
}
hawk_rtx_setretval (rtx, hawk_rtx_makestrvalwithbchars(rtx, rv, rv_len));
if (take_rtx_err) set_error_on_memc_list (rtx, memc_list, HAWK_NULL);
if (key) hawk_rtx_freevalbcstr (rtx, a1, key);
if (def_val) hawk_rtx_freevalbcstr (rtx, a2, def_val);
if (val) free(val);
return 0;
}
static int fnc_set (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
{
memc_list_t* memc_list;
memc_node_t* memc_node;
int ret = -1;
int take_rtx_err = 0;
hawk_val_t* a1, * a2, * a3, * a4;
hawk_bch_t* key = HAWK_NULL;
hawk_bch_t* val = HAWK_NULL;
hawk_oow_t key_len = 0;
hawk_oow_t val_len = 0;
hawk_int_t ttl = 0;
hawk_int_t flag = 0;
memc_list = rtx_to_memc_list(rtx, fi);
memc_node = get_memc_list_node_with_arg(rtx, memc_list, hawk_rtx_getarg(rtx, 0));
if (!memc_node)
{
goto done;
}
else
{
hawk_oow_t nargs;
memcached_return_t rc;
a1 = hawk_rtx_getarg(rtx, 1);
a2 = hawk_rtx_getarg(rtx, 2);
a3 = hawk_rtx_getarg(rtx, 3);
if (!(key = hawk_rtx_getvalbcstr(rtx, a1, &key_len)) ||
!(val = hawk_rtx_getvalbcstr(rtx, a2, &val_len)) ||
(hawk_rtx_valtoint(rtx, a3, &ttl) <= -1))
{
take_rtx_err = 1;
goto done;
}
nargs = hawk_rtx_getnargs(rtx);
if (nargs >= 5) {
a4 = hawk_rtx_getarg(rtx, 4);
if (hawk_rtx_valtoint(rtx, a4, &flag) <= -1)
{
take_rtx_err = 1;
goto done;
}
}
rc = memcached_set(memc_node->memc, key, key_len, val, val_len, ttl, flag);
if (rc != MEMCACHED_SUCCESS) {
goto done;
}
ret = 0;
}
done:
if (take_rtx_err) set_error_on_memc_list (rtx, memc_list, HAWK_NULL);
if (key) hawk_rtx_freevalbcstr (rtx, a1, key);
if (val) hawk_rtx_freevalbcstr (rtx, a2, val);
hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, ret));
return 0;
}
/* ------------------------------------------------------------------------ */
static hawk_mod_fnc_tab_t fnctab[] =
{
/* keep this table sorted for binary search in query(). */
{ HAWK_T("close"), { { 1, 1, HAWK_NULL }, fnc_close, 0 } },
{ HAWK_T("connect"), { { 1, 1, HAWK_NULL }, fnc_connect, 0 } },
{ HAWK_T("errmsg"), { { 0, 0, HAWK_NULL }, fnc_errmsg, 0 } },
{ HAWK_T("get"), { { 2, 3, HAWK_NULL }, fnc_get, 0 } },
{ HAWK_T("new"), { { 0, 0, HAWK_NULL }, fnc_new, 0 } },
{ HAWK_T("set"), { { 4, 5, HAWK_NULL }, fnc_set, 0 } },
};
static int query (hawk_mod_t* mod, hawk_t* hawk, const hawk_ooch_t* name, hawk_mod_sym_t* sym)
{
return hawk_findmodsymfnc(hawk, fnctab, HAWK_COUNTOF(fnctab), name, sym);
}
static int init (hawk_mod_t* mod, hawk_rtx_t* rtx)
{
hawk_rbt_t* rbt;
rtx_data_t data, * datap;
hawk_rbt_pair_t* pair;
rbt = (hawk_rbt_t*)mod->ctx;
HAWK_MEMSET (&data, 0, HAWK_SIZEOF(data));
pair = hawk_rbt_insert(rbt, &rtx, HAWK_SIZEOF(rtx), &data, HAWK_SIZEOF(data));
if (HAWK_UNLIKELY(!pair)) return -1;
datap = (rtx_data_t*)HAWK_RBT_VPTR(pair);
__init_memc_list (rtx, &datap->memc_list);
return 0;
}
static void fini (hawk_mod_t* mod, hawk_rtx_t* rtx)
{
hawk_rbt_t* rbt;
hawk_rbt_pair_t* pair;
rbt = (hawk_rbt_t*)mod->ctx;
/* garbage clean-up */
pair = hawk_rbt_search(rbt, &rtx, HAWK_SIZEOF(rtx));
if (pair)
{
rtx_data_t* data;
data = (rtx_data_t*)HAWK_RBT_VPTR(pair);
__fini_memc_list (rtx, &data->memc_list);
hawk_rbt_delete (rbt, &rtx, HAWK_SIZEOF(rtx));
}
}
static void unload (hawk_mod_t* mod, hawk_t* hawk)
{
hawk_rbt_t* rbt;
rbt = (hawk_rbt_t*)mod->ctx;
HAWK_ASSERT (HAWK_RBT_SIZE(rbt) == 0);
hawk_rbt_close (rbt);
}
int hawk_mod_memc (hawk_mod_t* mod, hawk_t* hawk)
{
hawk_rbt_t* rbt;
mod->query = query;
mod->unload = unload;
mod->init = init;
mod->fini = fini;
rbt = hawk_rbt_open(hawk_getgem(hawk), 0, 1, 1);
if (HAWK_UNLIKELY(!rbt)) return -1;
hawk_rbt_setstyle (rbt, hawk_get_rbt_style(HAWK_RBT_STYLE_INLINE_COPIERS));
mod->ctx = rbt;
return 0;
}
/* ------------------------------------------------------------------------ */
/*
BEGIN {
conn = memc::new();
if (memc::connect("--SERVER=localhost") <= -1)
{
print "connect error -", memc::errmsg();
return -1;
}
rc = memc::set(conn, "key", "val", 900);
if (rc <= -1) {
print "store result error - ", memc::errmsg();
}
val = memc::get(conn, "key"); print val;
val = memc::get(conn, "key", "default"); print val;
memc::close(conn);
}
*/

43
mod/mod-memc.h Normal file
View File

@ -0,0 +1,43 @@
/*
* $Id$
*
Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _HAWK_MOD_MEMC_H_
#define _HAWK_MOD_MEMC_H_
#include <hawk.h>
#if defined(__cplusplus)
extern "C" {
#endif
HAWK_EXPORT int hawk_mod_memc (hawk_mod_t* mod, hawk_t* hawk);
#if defined(__cplusplus)
}
#endif
#endif