pachi_py/pachi/uct/plugins.c (102 lines of code) (raw):
#include <assert.h>
#ifndef WIN32
#include <dlfcn.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "board.h"
#include "debug.h"
#include "move.h"
#include "random.h"
#include "uct/plugins.h"
#include "uct/prior.h"
#include "uct/tree.h"
/* Plugin interface for UCT. External plugins may hook callbacks on various
* events and e.g. bias the tree. */
/* Keep the API typedefs in sync with <uct/plugin.h>. */
struct plugin {
char *path;
char *args;
void *dlh;
void *data;
void *(*init)(char *args, struct board *b, int seed);
void (*prior)(void *data, struct tree_node *node, struct prior_map *map, int eqex);
void (*done)(void *data);
};
struct uct_pluginset {
struct plugin *plugins;
int n_plugins;
struct board *b;
};
#ifdef WIN32
/* We do not support plugins on Windows. Minimal dummy stubs. */
struct uct_pluginset *
pluginset_init(struct board *b)
{
return NULL;
}
void
pluginset_done(struct uct_pluginset *ps)
{
assert(!ps);
}
void
plugin_load(struct uct_pluginset *ps, char *path, char *args)
{
assert(!ps);
}
void
plugin_prior(struct uct_pluginset *ps, struct tree_node *node, struct prior_map *map, int eqex)
{
assert(!ps);
}
#else
struct uct_pluginset *
pluginset_init(struct board *b)
{
struct uct_pluginset *ps = calloc(1, sizeof(*ps));
ps->b = b;
return ps;
}
void
pluginset_done(struct uct_pluginset *ps)
{
for (int i = 0; i < ps->n_plugins; i++) {
struct plugin *p = &ps->plugins[i];
p->done(p->data);
dlclose(p->dlh);
free(p->path);
free(p->args);
}
free(ps);
}
void
plugin_load(struct uct_pluginset *ps, char *path, char *args)
{
ps->plugins = realloc(ps->plugins, ++ps->n_plugins * sizeof(ps->plugins[0]));
struct plugin *p = &ps->plugins[ps->n_plugins - 1];
p->path = strdup(path);
p->args = args ? strdup(args) : args;
p->dlh = dlopen(path, RTLD_NOW);
if (!p->dlh) {
fprintf(stderr, "Cannot load plugin %s: %s\n", path, dlerror());
exit(EXIT_FAILURE);
}
#define loadsym(s_) do {\
p->s_ = dlsym(p->dlh, "pachi_plugin_" #s_); \
if (!p->s_) { \
fprintf(stderr, "Cannot find pachi_plugin_%s in plugin %s: %s\n", #s_, path, dlerror()); \
exit(EXIT_FAILURE); \
} \
} while (0)
loadsym(init);
loadsym(prior);
loadsym(done);
p->data = p->init(p->args, ps->b, fast_random(65536));
}
void
plugin_prior(struct uct_pluginset *ps, struct tree_node *node, struct prior_map *map, int eqex)
{
for (int i = 0; i < ps->n_plugins; i++) {
struct plugin *p = &ps->plugins[i];
p->prior(p->data, node, map, eqex);
}
}
#endif