Skip to content

Commit

Permalink
WIP LoadKernelExtension, IsKernelExtensionAvailable
Browse files Browse the repository at this point in the history
  • Loading branch information
fingolfin committed May 19, 2021
1 parent cb76422 commit 5fff8c2
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 44 deletions.
54 changes: 54 additions & 0 deletions lib/files.gd
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,60 @@ BIND_GLOBAL( "LoadStaticModule", function( filename )
end );


#############################################################################
##
#F IsKernelExtensionAvailable( <pkgname> [, <modname> ] )
##
BIND_GLOBAL( "IsKernelExtensionAvailable", function( pkgname, modname... )
local fname;

if Length(modname) = 0 then
modname := pkgname;
elif Length(modname) = 1 then
modname := modname[1];
else
Error( "usage: IsKernelExtensionAvailable( <pkgname> [, <modname> ] )" );
fi;

if modname in SHOW_STAT() then
return true;
fi;
fname := Filename(DirectoriesPackagePrograms(pkgname), Concatenation(modname, ".so"));
if fname <> fail then
return IS_LOADABLE_DYN(fname);
fi;
return false;
end );


#############################################################################
##
#F LoadKernelExtension( <pkgname> [, <modname> ] )
##
BIND_GLOBAL( "LoadKernelExtension", function( pkgname, modname... )
local fname;

if Length(modname) = 0 then
modname := pkgname;
elif Length(modname) = 1 then
modname := modname[1];
else
Error( "usage: LoadKernelExtension( <pkgname> [, <modname> ] )" );
fi;

if modname in SHOW_STAT() then
LoadStaticModule(modname);
return true;
fi;
fname := Filename(DirectoriesPackagePrograms(pkgname), Concatenation(modname, ".so"));
if fname <> fail then
LoadDynamicModule(fname);
return true;
fi;
return false;
end );


#############################################################################
##
#F Edit( <filename> ) . . . . . . . . . . . . . . . . . edit and read file
Expand Down
12 changes: 12 additions & 0 deletions lib/package.gi
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,18 @@ InstallGlobalFunction( DirectoriesPackagePrograms, function( name )
# This package is not known.
return [];
fi;
# FIXME: inject another secondary path??? to allow "out of tree builds"
# for packages, and/or allow GAP itself to store binaries for the package
# so that the precise combination of GAP and package are matched...
# That is, take the precise GAP version (possibly including the git commit
# it was compiled from), plus the package version (and possibly also the locations of both?)
# and combine them into a unique ID (e.g. via a hash), then use that to
# store .so binaries


# also add a new mechanism to integrate kernel extensions into a package:
# let the package declare in its PackageInfo.g that it has a kernel extension;
# how to build it; what's its name; then GAP can take care of that dynamically
return [ Directory( Concatenation( installationpath, "/bin/",
GAPInfo.Architecture, "/" ) ) ];
end );
Expand Down
89 changes: 59 additions & 30 deletions src/modules.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,32 +203,66 @@ StructInitInfo * LookupStaticModule(const char * name)
** 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 indicates which error occurred.
** return value is a pointer to a string with more information.
*/
#ifdef HAVE_DLOPEN
static Int SyLoadModule(const Char * name, InitInfoFunc * func)
static const char * SyLoadModule(const Char * name, InitInfoFunc * func)
{
void * init;
void * handle;

*func = 0;

handle = dlopen( name, RTLD_LAZY | RTLD_LOCAL);
if ( handle == 0 ) {
Pr("#W dlopen() error: %s\n", (long) dlerror(), 0);
return 1;
void * handle = dlopen(name, RTLD_LAZY | RTLD_LOCAL);
if (handle == 0) {
*func = 0;
return dlerror();
}

init = dlsym( handle, "Init__Dynamic" );
if ( init == 0 )
return 3;
*func = (InitInfoFunc)dlsym(handle, "Init__Dynamic");
if (*func == 0)
return "symbol 'Init__Dynamic' not found";

*func = (InitInfoFunc) init;
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)
return False;
#else

InitInfoFunc init;

// try to load the module
SyLoadModule(CONST_CSTR_STRING(filename), &init);
if (init == 0)
return False;

// get the description structure
StructInitInfo * info = (*init)();
if (info == 0)
return False;

// info->type should not be larger than kernel version
if (info->type / 10 > GAP_KERNEL_API_VERSION)
return False;

// info->type should not have an older major version
if (info->type / 10000 < GAP_KERNEL_MAJOR_VERSION)
return False;

// info->type % 10 should be 0, 1 or 2, for the 3 types of module
if (info->type % 10 > 2)
return False;

return True;
#endif
}


/****************************************************************************
**
Expand All @@ -248,14 +282,12 @@ static Obj FuncLOAD_DYN(Obj self, Obj filename)

InitInfoFunc init;

/* try to read the module */
Int res = SyLoadModule(CONST_CSTR_STRING(filename), &init);
if (res == 1)
ErrorQuit("module '%g' not found", (Int)filename, 0);
else if (res == 3)
ErrorQuit("symbol 'Init_Dynamic' not found", 0, 0);
// try to read the module
const char * res = SyLoadModule(CONST_CSTR_STRING(filename), &init);
if (res)
ErrorQuit("failed to load dynamic module %g, %s", (Int)filename, (Int)res);

/* get the description structure */
// get the description structure
StructInitInfo * info = (*init)();
if (info == 0)
ErrorQuit("call to init function failed", 0, 0);
Expand Down Expand Up @@ -855,17 +887,13 @@ void LoadModules(void)
InitInfoFunc init;

#ifdef HAVE_DLOPEN
int res = SyLoadModule(buf, &init);
if (res != 0) {
Panic("Failed to load needed dynamic module %s, error "
"code %d\n",
buf, res);
const char * 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 needed dynamic module %s, error "
"code %d\n",
buf, res);
Panic("failed to init dynamic module %s\n", buf);
}
#else
Panic("workspace require dynamic module %s, but dynamic "
Expand Down Expand Up @@ -1051,6 +1079,7 @@ void ModulesPostRestore(void)
*/
static StructGVarFunc GVarFuncs[] = {
GVAR_FUNC_1ARGS(GAP_CRC, filename),
GVAR_FUNC_1ARGS(IS_LOADABLE_DYN, filename),
GVAR_FUNC_1ARGS(LOAD_DYN, filename),
GVAR_FUNC_1ARGS(LOAD_STAT, filename),
GVAR_FUNC_0ARGS(SHOW_STAT),
Expand Down
15 changes: 1 addition & 14 deletions tst/testinstall/kernel/gap.tst
Original file line number Diff line number Diff line change
Expand Up @@ -130,19 +130,6 @@ Error, GAP_CRC: <filename> must be a string (not the value 'fail')
gap> GAP_CRC("foobar");
0

#
gap> LOAD_DYN(fail);
Error, LOAD_DYN: <filename> must be a string (not the value 'fail')

#
gap> LOAD_STAT(fail);
Error, LOAD_STAT: <filename> must be a string (not the value 'fail')
gap> LOAD_STAT("foobar");
false

#
gap> LoadedModules();;

#
gap> GASMAN();
Error, usage: GASMAN( "display"|"displayshort"|"clear"|"collect"|"message"|"pa\
Expand Down Expand Up @@ -186,7 +173,7 @@ gap> Sleep(0);
gap> Sleep(1);

#
gap> MicroSleep(fail);
gap> MicroSleep(fail);
Error, MicroSleep: <msecs> must be a small integer (not the value 'fail')
gap> MicroSleep(0);
gap> MicroSleep(1);
Expand Down
24 changes: 24 additions & 0 deletions tst/testinstall/kernel/modules.tst
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#
# Tests for functions defined in src/modules.c
#
gap> START_TEST("kernel/modules.tst");

#
gap> IS_LOADABLE_DYN(fail);
Error, IS_LOADABLE_DYN: <filename> must be a string (not the value 'fail')

#
gap> LOAD_DYN(fail);
Error, LOAD_DYN: <filename> must be a string (not the value 'fail')

#
gap> LOAD_STAT(fail);
Error, LOAD_STAT: <filename> must be a string (not the value 'fail')
gap> LOAD_STAT("foobar");
false

#
gap> LoadedModules();;

#
gap> STOP_TEST("kernel/modules.tst", 1);

0 comments on commit 5fff8c2

Please sign in to comment.