/**************************************************************************** ** ** This file is part of GAP, a system for computational discrete algebra. ** ** Copyright of GAP belongs to its developers, whose names are too numerous ** to list here. Please refer to the COPYRIGHT file for details. ** ** SPDX-License-Identifier: GPL-2.0-or-later ** ** This file implements APIs for GAP modules, including builtin modules, ** or static and dynamic modules used by packages and end users to provide ** kernel extensions.
*/
/**************************************************************************** ** *F FuncGAP_CRC( <self>, <name> ) . . . . . . . create a crc value for a file
*/ static Obj FuncGAP_CRC(Obj self, Obj filename)
{
RequireStringRep(SELF_NAME, filename); return ObjInt_Int(SyGAPCRC(CONST_CSTR_STRING(filename)));
}
/**************************************************************************** ** *F ActivateModule( <info> )
*/ Int ActivateModule(StructInitInfo * info)
{ Int res = 0;
RegisterModuleState(info);
if (info->initKernel) {
res = info->initKernel(info);
}
int flag = 0; #ifdef GAP_ENABLE_SAVELOAD
flag = SyRestoring != 0; #endif if (!flag) {
UpdateCopyFopyInfo();
if (info->initLibrary) { // Start a new executor to run the outer function of the module in // global context
Bag oldLvars = SWITCH_TO_BOTTOM_LVARS();
res = res || info->initLibrary(info);
SWITCH_TO_OLD_LVARS(oldLvars);
}
}
if (res) {
Pr("#W init functions returned non-zero exit code\n", 0, 0);
}
if (info->initModuleState)
res = res || (info->initModuleState)();
return res;
}
/**************************************************************************** ** *F LookupStaticModule(<name>)
*/
StructInitInfo * LookupStaticModule(constchar * name)
{ for (int k = 0; CompInitFuncs[k]; k++) {
StructInitInfo * info = (*(CompInitFuncs[k]))(); if (info && streq(name, info->name)) { return info;
}
} return 0;
}
/**************************************************************************** ** *F SyLoadModule( <name>, <func> ) . . . . . . . . . load a compiled module ** ** This function attempts to load a compiled module <name>. ** If successful, it returns 0, and sets <func> to a pointer to the init ** function of the module. In case of an error, <func> is set to 0, and the ** return value is a pointer to a string with more information.
*/ #ifdef HAVE_DLOPEN staticconstchar * SyLoadModule(constChar * name, InitInfoFunc * func)
{ void * handle = dlopen(name, RTLD_LAZY | RTLD_LOCAL); if (handle == 0) {
*func = 0; return dlerror();
}
*func = (InitInfoFunc)dlsym(handle, "Init__Dynamic"); if (*func == 0) return"symbol 'Init__Dynamic' not found";
return 0;
} #endif
/**************************************************************************** ** *F FuncIS_LOADABLE_DYN( <self>, <name> ) . test if a dyn. module is loadable
*/ static Obj FuncIS_LOADABLE_DYN(Obj self, Obj filename)
{
RequireStringRep(SELF_NAME, filename);
#if !defined(HAVE_DLOPEN) returnFalse; #else
InitInfoFunc init;
// try to load the module
SyLoadModule(CONST_CSTR_STRING(filename), &init); if (init == 0) returnFalse;
// get the description structure
StructInitInfo * info = (*init)(); if (info == 0) returnFalse;
// info->type should not be larger than kernel version if (info->type / 10 > GAP_KERNEL_API_VERSION) returnFalse;
// info->type should not have an older major version if (info->type / 10000 < GAP_KERNEL_MAJOR_VERSION) returnFalse;
// info->type % 10 should be 0, 1 or 2, for the 3 types of module if (info->type % 10 > 2) returnFalse;
#if !defined(HAVE_DLOPEN) // no dynamic library support if (SyDebugLoading) {
Pr("#I LOAD_DYN: no support for dynamical loading\n", 0, 0);
} returnFalse; #else
InitInfoFunc init;
// try to read the module constchar * res = SyLoadModule(CONST_CSTR_STRING(filename), &init); if (res)
ErrorQuit("LOAD_DYN: failed to load kernel module %g, %s",
(Int)filename, (Int)res);
// get the description structure
StructInitInfo * info = (*init)(); if (info == 0)
ErrorQuit("LOAD_DYN: init function of kernel module %g failed",
(Int)filename, 0);
// info->type should not be larger than kernel version if (info->type / 10 > GAP_KERNEL_API_VERSION)
ErrorMayQuit("LOAD_DYN: kernel module %g built for newer " "version %d of GAP",
(Int)filename, info->type / 10);
// info->type should not have an older major version if (info->type / 10000 < GAP_KERNEL_MAJOR_VERSION)
ErrorMayQuit("LOAD_DYN: kernel module %g built for older " "version of GAP",
(Int)filename, 0);
// info->type % 10 should be 0, 1 or 2, for the 3 types of module if (info->type % 10 > 2)
ErrorMayQuit("LOAD_DYN: Invalid kernel module '%g'", (Int)filename,
0);
// try to find the module
info = LookupStaticModule(CONST_CSTR_STRING(filename)); if (info == 0) { if (SyDebugLoading) {
Pr("#I LOAD_STAT: no module named '%g' found\n", (Int)filename,
0);
} returnFalse;
}
// count the number of install modules for (k = 0, im = 0; CompInitFuncs[k]; k++) {
info = (*(CompInitFuncs[k]))(); if (info == 0) { continue;
}
im++;
}
// make a list of modules with crc values
modules = NEW_PLIST(T_PLIST, 2 * im);
for (k = 0; CompInitFuncs[k]; k++) {
info = (*(CompInitFuncs[k]))(); if (info == 0) { continue;
}
name = MakeImmString(info->name);
PushPlist(modules, name);
// compute the crc value
PushPlist(modules, ObjInt_Int(info->crc));
}
return modules;
}
/**************************************************************************** ** *F FuncLoadedModules( <self> ) . . . . . . . . . . . list all loaded modules
*/ static Obj FuncLoadedModules(Obj self)
{ Int i;
StructInitInfo * m;
Obj str;
Obj list;
// create a list
list = NEW_PLIST(T_PLIST, NrModules * 3);
SET_LEN_PLIST(list, NrModules * 3); for (i = 0; i < NrModules; i++) {
m = Modules[i].info; if (IS_MODULE_BUILTIN(m->type)) {
SET_ELM_PLIST(list, 3 * i + 1, ObjsChar[(Int)'b']);
CHANGED_BAG(list);
str = MakeImmString(m->name);
SET_ELM_PLIST(list, 3 * i + 2, str);
SET_ELM_PLIST(list, 3 * i + 3, INTOBJ_INT(m->version));
} elseif (IS_MODULE_DYNAMIC(m->type)) {
SET_ELM_PLIST(list, 3 * i + 1, ObjsChar[(Int)'d']);
CHANGED_BAG(list);
str = MakeImmString(m->name);
SET_ELM_PLIST(list, 3 * i + 2, str);
CHANGED_BAG(list);
str = MakeImmString(Modules[i].filename);
SET_ELM_PLIST(list, 3 * i + 3, str);
} elseif (IS_MODULE_STATIC(m->type)) {
SET_ELM_PLIST(list, 3 * i + 1, ObjsChar[(Int)'s']);
CHANGED_BAG(list);
str = MakeImmString(m->name);
SET_ELM_PLIST(list, 3 * i + 2, str);
CHANGED_BAG(list);
str = MakeImmString(Modules[i].filename);
SET_ELM_PLIST(list, 3 * i + 3, str);
}
} return list;
}
staticvoid SetupFuncInfo(Obj func, constChar * cookie)
{ // The string <cookie> usually has the form "PATH/TO/FILE.c:FUNCNAME". // We check if that is the case, and if so, split it into the parts before // and after the colon. In addition, the file path is cut to only contain // the last two '/'-separated components. constChar * pos = strchr(cookie, ':'); if (pos) {
Obj location = MakeImmString(pos + 1);
SyInitializing = 0; for (i = 0; i < NrImportedGVars; i++) { if (ImportedGVars[i].address == 0) {
val = ValAutoGVar(GVarName(ImportedGVars[i].name)); if (val == 0) {
errs++; if (!SyQuiet) {
Pr("#W global variable '%s' has not been defined\n",
(Int)ImportedFuncs[i].name, 0);
}
}
} elseif (*ImportedGVars[i].address == 0) {
errs++; if (!SyQuiet) {
Pr("#W global variable '%s' has not been defined\n",
(Int)ImportedGVars[i].name, 0);
}
} else {
MakeReadOnlyGVar(GVarName(ImportedGVars[i].name));
}
}
for (i = 0; i < NrImportedFuncs; i++) { if (ImportedFuncs[i].address == 0) {
val = ValAutoGVar(GVarName(ImportedFuncs[i].name)); if (val == 0 || !IS_FUNC(val)) {
errs++; if (!SyQuiet) {
Pr("#W global function '%s' has not been defined\n",
(Int)ImportedFuncs[i].name, 0);
}
}
} elseif (*ImportedFuncs[i].address == ErrorMustEvalToFuncFunc ||
*ImportedFuncs[i].address == ErrorMustHaveAssObjFunc) {
errs++; if (!SyQuiet) {
Pr("#W global function '%s' has not been defined\n",
(Int)ImportedFuncs[i].name, 0);
}
} else {
MakeReadOnlyGVar(GVarName(ImportedFuncs[i].name));
}
}
return errs == 0 ? True : False;
}
/**************************************************************************** ** *F RecordLoadedModule( <module> ) . . . . . . . . store module in <Modules>
*/
void RecordLoadedModule(StructInitInfo * info, Int isGapRootRelative, constChar * filename)
{
UInt len; if (NrModules == MAX_MODULES) {
Panic("no room to record module");
}
len = strlen(filename); if (NextLoadedModuleFilename + len + 1 >
LoadedModuleFilenames + MAX_MODULE_FILENAMES) {
Panic("no room for module filename");
}
*NextLoadedModuleFilename = '\0';
memcpy(NextLoadedModuleFilename, filename, len + 1);
Modules[NrModules].info = info;
Modules[NrModules].filename = NextLoadedModuleFilename;
NextLoadedModuleFilename += len + 1;
Modules[NrModules].isGapRootRelative = isGapRootRelative;
NrModules++;
}
#ifdef GAP_ENABLE_SAVELOAD
void SaveModules(void)
{
SaveUInt(NrModules - NrBuiltinModules); for (UInt i = NrBuiltinModules; i < NrModules; i++) {
SaveUInt(Modules[i].info->type);
SaveUInt(Modules[i].isGapRootRelative);
SaveCStr(Modules[i].filename);
}
}
void LoadModules(void)
{ Char buf[256];
UInt nMods = LoadUInt(); for (UInt i = 0; i < nMods; i++) {
UInt type = LoadUInt();
UInt isGapRootRelative = LoadUInt();
LoadCStr(buf, 256); if (isGapRootRelative)
READ_GAP_ROOT(buf); else {
StructInitInfo * info = NULL; // Search for user module static case first if (IS_MODULE_STATIC(type)) {
info = LookupStaticModule(buf); if (info == 0) {
Panic("Static module %s not found in loading kernel",
buf);
}
} else { // and dynamic case
InitInfoFunc init;
#ifdef HAVE_DLOPEN constchar * res = SyLoadModule(buf, &init); if (init == 0) {
Panic("failed to load dynamic module %s, %s\n", buf, res);
}
info = (*init)(); if (info == 0) {
Panic("failed to init dynamic module %s\n", buf);
} #else
Panic("workspace require dynamic module %s, but dynamic " "loading not supported",
buf); #endif
}
void ModulesInitKernel(void)
{ for (UInt i = 0; i < NrBuiltinModules; i++) {
StructInitInfo * info = Modules[i].info; if (info->initKernel) { if (SyDebugLoading) {
fputs("#I InitKernel(builtin ", stderr);
fputs(info->name, stderr);
fputs(")\n", stderr);
} Int ret = info->initKernel(info); if (ret) {
Panic("InitKernel(builtin %s) returned non-zero value", info->name);
}
}
}
}
void ModulesInitLibrary(void)
{ for (UInt i = 0; i < NrBuiltinModules; i++) {
StructInitInfo * info = Modules[i].info; if (info->initLibrary) { if (SyDebugLoading) {
fputs("#I InitLibrary(builtin ", stderr);
fputs(info->name, stderr);
fputs(")\n", stderr);
} Int ret = info->initLibrary(info); if (ret) {
Panic("InitLibrary(builtin %s) returned non-zero value", info->name);
}
}
}
}
void ModulesCheckInit(void)
{ for (UInt i = 0; i < NrModules; i++) {
StructInitInfo * info = Modules[i].info; if (info->checkInit) { if (SyDebugLoading) {
fputs("#I CheckInit(builtin ", stderr);
fputs(info->name, stderr);
fputs(")\n", stderr);
} Int ret = info->checkInit(info); if (ret) {
Panic("CheckInit(builtin %s) returned non-zero value", info->name);
}
}
}
}
void ModulesInitModuleState(void)
{ for (UInt i = 0; i < NrModules; i++) {
StructInitInfo * info = Modules[i].info; if (info->initModuleState) { if (SyDebugLoading) {
fputs("#I InitModuleState(", stderr);
fputs(info->name, stderr);
fputs(")\n", stderr);
} Int ret = info->initModuleState(); if (ret) {
Panic("InitModuleState(builtin %s) returned non-zero value", info->name);
}
}
}
}
void ModulesDestroyModuleState(void)
{ for (UInt i = 0; i < NrModules; i++) {
StructInitInfo * info = Modules[i].info; if (info->destroyModuleState) { if (SyDebugLoading) {
fputs("#I DestroyModuleState(", stderr);
fputs(info->name, stderr);
fputs(")\n", stderr);
} Int ret = info->destroyModuleState(); if (ret) {
Panic("DestroyModuleState(builtin %s) returned non-zero value", info->name);
}
}
}
}
#ifdef GAP_ENABLE_SAVELOAD
Int ModulesPreSave(void)
{ for (UInt i = 0; i < NrModules; i++) {
StructInitInfo * info = Modules[i].info; if (info->preSave != NULL && info->preSave(info)) {
Pr("Failed to save workspace -- problem reported in %s\n",
(Int)info->name, 0); // roll back all save preparations while (i--) {
info = Modules[i].info;
info->postSave(info);
} return 1;
}
} return 0;
}
void ModulesPostSave(void)
{ for (UInt i = 0; i < NrModules; i++) {
StructInitInfo * info = Modules[i].info; if (info->postSave != NULL)
info->postSave(info);
}
}
void ModulesPostRestore(void)
{ for (UInt i = 0; i < NrModules; i++) {
StructInitInfo * info = Modules[i].info; if (info->postRestore) { if (SyDebugLoading) {
fputs("#I PostRestore(builtin ", stderr);
fputs(info->name, stderr);
fputs(")\n", stderr);
} Int ret = info->postRestore(info); if (ret) {
Panic("PostRestore(builtin %s) returned non-zero value", info->name);
}
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.