/* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://lammps.sandia.gov/, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ #include "plugin.h" #include "comm.h" #include "error.h" #include "force.h" #include "lammps.h" #include "modify.h" #include "pair.h" #include #include #ifdef _WIN32 #include #else #include #endif namespace LAMMPS_NS { // store list of plugin information data for loaded styles static std::list pluginlist; // map of dso handles static std::map dso_refcounter; // load DSO and call included registration function void plugin_load(const char *file, LAMMPS *lmp) { int me = lmp->comm->me; #if defined(WIN32) lmp->error->all(FLERR,"Loading of plugins on Windows not yet supported\n"); #else // open DSO file from given path load symbols globally void *dso = dlopen(file,RTLD_NOW|RTLD_GLOBAL); if (dso == nullptr) { if (me == 0) utils::logmesg(lmp,fmt::format("Open of plugin file {} failed: {}", file,utils::getsyserror())); return; } // look up lammpsplugin_init() function in DSO. must have C bindings. void *initfunc = dlsym(dso,"lammpsplugin_init"); if (initfunc == nullptr) { dlclose(dso); if (me == 0) utils::logmesg(lmp,fmt::format("Plugin symbol lookup failure in " "file {}\n",file)); return; } // call initializer function loaded from DSO and pass a pointer // to the LAMMPS instance, the DSO handle (for reference counting) // and plugin registration function pointer ((lammpsplugin_initfunc)(initfunc))((void *)lmp, dso, (void *)&plugin_register); #endif } // register a new style from a plugin with LAMMPS // this is the callback function that is called from within // the plugin initializer function. all plugin information // is taken from the lammpsplugin_t struct. void plugin_register(lammpsplugin_t *plugin, void *ptr) { LAMMPS *lmp = (LAMMPS *)ptr; int me = lmp->comm->me; if (plugin == nullptr) return; if (me == 0) { utils::logmesg(lmp,fmt::format("Loading plugin: {} by {}\n", plugin->info, plugin->author)); // print version info only if the versions of host and plugin don't match if ((plugin->version) && (strcmp(plugin->version,lmp->version) != 0)) utils::logmesg(lmp,fmt::format(" compiled for LAMMPS version {} " "loaded into LAMMPS version {}\n", plugin->version, lmp->version)); } pluginlist.push_back(*plugin); if (dso_refcounter.find(plugin->handle) != dso_refcounter.end()) { ++ dso_refcounter[plugin->handle]; } else { dso_refcounter[plugin->handle] = 1; } std::string pstyle = plugin->style; if (pstyle == "pair") { auto pair_map = lmp->force->pair_map; if (pair_map->find(plugin->name) != pair_map->end()) { if (lmp->comm->me == 0) lmp->error->warning(FLERR,fmt::format("Overriding built-in pair " "style {} from plugin", plugin->name)); } (*pair_map)[plugin->name] = (Force::PairCreator)plugin->creator; } else { utils::logmesg(lmp,fmt::format("Loading plugin for {} styles not " "yet implemented\n", pstyle)); pluginlist.pop_back(); } } // number of styles loaded from plugin files int plugin_get_num_plugins() { return pluginlist.size(); } // return position index in list of given plugin of given style int plugin_find(const char *style, const char *name) { int i=0; for (auto entry : pluginlist) { if ((strcmp(style,entry.style) == 0) && (strcmp(name,entry.name) == 0)) return i; ++i; } return -1; } // get pointer to plugin initializer struct at position idx const lammpsplugin_t *plugin_get_info(int idx) { int i=0; for (auto p=pluginlist.begin(); p != pluginlist.end(); ++p) { if (i == idx) return &(*p); ++i; } return nullptr; } // remove plugin of given name and style from internal lists void plugin_erase(const char *style, const char *name) { for (auto p=pluginlist.begin(); p != pluginlist.end(); ++p) { if ((strcmp(style,p->style) == 0) && (strcmp(name,p->name) == 0)) { pluginlist.erase(p); return; } } } // remove plugin from given style table and plugin list. // optionally close the DSO handle if last plugin from that DSO // must delete style instance if style is currently active. void plugin_unload(const char *style, const char *name, LAMMPS *lmp) { int me = lmp->comm->me; // ignore unload request if not loaded from a plugin int idx = plugin_find(style,name); if (idx < 0) { if (me == 0) utils::logmesg(lmp,fmt::format("Ignoring unload of {} style {}: not " "loaded from a plugin\n", style, name)); return; } // copy of DSO handle for later void *handle = plugin_get_info(idx)->handle; // remove selected plugin from list of plugins if (me == 0) utils::logmesg(lmp,fmt::format("Unloading {} style {}\n",style,name)); plugin_erase(style,name); // remove style of given name from corresponding map // must delete style instance if currently active so // we can close the DSO handle if the last reference is gone. std::string pstyle = style; if (pstyle == "pair") { auto found = lmp->force->pair_map->find(name); if (found != lmp->force->pair_map->end()) lmp->force->pair_map->erase(found); // must delete pair style instance if in use if (lmp->force->pair_style) { if (utils::strmatch(lmp->force->pair_style,"^hybrid")) { if (lmp->force->pair_match(name,1,1) != nullptr) lmp->force->create_pair("none",0); } else { if (strcmp(lmp->force->pair_style,name) == 0) lmp->force->create_pair("none",0); } } } // if reference count is down to zero, close DSO handle. -- dso_refcounter[handle]; if (dso_refcounter[handle] == 0) { #ifndef WIN32 dlclose(handle); #endif } } }