1 /****************************************************************************
2 **
3 ** This file is part of GAP, a system for computational discrete algebra.
4 **
5 ** Copyright of GAP belongs to its developers, whose names are too numerous
6 ** to list here. Please refer to the COPYRIGHT file for details.
7 **
8 ** SPDX-License-Identifier: GPL-2.0-or-later
9 **
10 ** This file implements APIs for GAP modules, including builtin modules,
11 ** or static and dynamic modules used by packages and end users to provide
12 ** kernel extensions.
13 */
14
15 #include "modules.h"
16
17 #include "ariths.h"
18 #include "bool.h"
19 #include "code.h"
20 #include "compstat.h"
21 #include "error.h"
22 #include "funcs.h"
23 #include "gap.h"
24 #include "gapstate.h"
25 #include "gvars.h"
26 #include "integer.h"
27 #include "intobj.h"
28 #include "io.h"
29 #include "lists.h"
30 #include "modules_builtin.h"
31 #include "opers.h"
32 #include "plist.h"
33 #include "saveload.h"
34 #include "streams.h"
35 #include "stringobj.h"
36 #include "sysfiles.h"
37 #include "sysopt.h"
38
39 #ifdef HAVE_DLOPEN
40 #include <dlfcn.h>
41 #endif
42
43
44 /****************************************************************************
45 **
46 *F Modules . . . . . . . . . . . . . . . . . . . . . . . . . list of modules
47 */
48 #ifndef MAX_MODULES
49 #define MAX_MODULES 1000
50 #endif
51
52
53 #ifndef MAX_MODULE_FILENAMES
54 #define MAX_MODULE_FILENAMES (MAX_MODULES * 50)
55 #endif
56
57 static Char LoadedModuleFilenames[MAX_MODULE_FILENAMES];
58 static Char * NextLoadedModuleFilename = LoadedModuleFilenames;
59
60 typedef struct {
61
62 // pointer to the actual StructInitInfo
63 StructInitInfo * info;
64
65 // filename relative to GAP_ROOT or absolute
66 Char * filename;
67
68 // true if the filename is GAP_ROOT relative
69 Int isGapRootRelative;
70
71 } StructInitInfoExt;
72
73
74 static StructInitInfoExt Modules[MAX_MODULES];
75 static UInt NrModules;
76 static UInt NrBuiltinModules;
77
78
79 typedef struct {
80 const Char * name;
81 Obj * address;
82 } StructImportedGVars;
83
84 #ifndef MAX_IMPORTED_GVARS
85 #define MAX_IMPORTED_GVARS 1024
86 #endif
87
88 static StructImportedGVars ImportedGVars[MAX_IMPORTED_GVARS];
89 static Int NrImportedGVars;
90
91 static StructImportedGVars ImportedFuncs[MAX_IMPORTED_GVARS];
92 static Int NrImportedFuncs;
93
94 static Int StateNextFreeOffset = 0; // Start of next free memory area (as offset into GAPState.StateSlots)
95
RegisterModuleState(StructInitInfo * info)96 static void RegisterModuleState(StructInitInfo * info)
97 {
98 UInt size = info->moduleStateSize;
99 if (size == 0)
100 return;
101
102 // using moduleStateSize without moduleStateOffsetPtr makes no sense
103 GAP_ASSERT(info->moduleStateOffsetPtr);
104
105 // check that we have enough free space
106 assert((STATE_SLOTS_SIZE - StateNextFreeOffset) >= size);
107
108 // record start offset of this module's state
109 *info->moduleStateOffsetPtr = StateNextFreeOffset;
110
111 // ... and 'allocate' the requested amount of storage
112 StateNextFreeOffset += size;
113 StateNextFreeOffset = (StateNextFreeOffset + sizeof(Obj)-1) & ~(sizeof(Obj)-1);
114 }
115
116
117 /*************************************************************************
118 **
119 *F * * * * * * * * * functions for dynamical/static modules * * * * * * * * *
120 */
121
122
123 /****************************************************************************
124 **
125 *F FuncGAP_CRC( <self>, <name> ) . . . . . . . create a crc value for a file
126 */
FuncGAP_CRC(Obj self,Obj filename)127 static Obj FuncGAP_CRC(Obj self, Obj filename)
128 {
129 /* check the argument */
130 RequireStringRep("GAP_CRC", filename);
131
132 /* compute the crc value */
133 return ObjInt_Int(SyGAPCRC(CONST_CSTR_STRING(filename)));
134 }
135
136
137 /****************************************************************************
138 **
139 *F ActivateModule( <info> )
140 */
ActivateModule(StructInitInfo * info)141 void ActivateModule(StructInitInfo * info)
142 {
143 Int res = 0;
144
145 RegisterModuleState(info);
146
147 if (info->initKernel) {
148 res = info->initKernel(info);
149 }
150
151 if (!SyRestoring) {
152 UpdateCopyFopyInfo();
153
154 if (info->initLibrary) {
155 // Start a new executor to run the outer function of the module in
156 // global context
157 ExecBegin(STATE(BottomLVars));
158 res = res || info->initLibrary(info);
159 ExecEnd(res);
160 }
161 }
162
163 if (res) {
164 Pr("#W init functions returned non-zero exit code\n", 0L, 0L);
165 }
166
167 if (info->initModuleState)
168 res = res || (info->initModuleState)();
169 }
170
171
172 /****************************************************************************
173 **
174 *F SyLoadModule( <name>, <func> ) . . . . . . . . . load a compiled module
175 **
176 ** This function attempts to load a compiled module <name>.
177 ** If successful, it returns 0, and sets <func> to a pointer to the init
178 ** function of the module. In case of an error, <func> is set to 0, and the
179 ** return value indicates which error occurred.
180 */
181 #ifdef HAVE_DLOPEN
SyLoadModule(const Char * name,InitInfoFunc * func)182 static Int SyLoadModule(const Char * name, InitInfoFunc * func)
183 {
184 void * init;
185 void * handle;
186
187 *func = 0;
188
189 handle = dlopen( name, RTLD_LAZY | RTLD_GLOBAL);
190 if ( handle == 0 ) {
191 Pr("#W dlopen() error: %s\n", (long) dlerror(), 0L);
192 return 1;
193 }
194
195 init = dlsym( handle, "Init__Dynamic" );
196 if ( init == 0 )
197 return 3;
198
199 *func = (InitInfoFunc) init;
200 return 0;
201 }
202 #endif
203
204
205
206 /****************************************************************************
207 **
208 *F FuncLOAD_DYN( <self>, <name>, <crc> ) . . . try to load a dynamic module
209 */
FuncLOAD_DYN(Obj self,Obj filename,Obj crc)210 static Obj FuncLOAD_DYN(Obj self, Obj filename, Obj crc)
211 {
212 StructInitInfo * info;
213 Obj crc1;
214 Int res;
215 InitInfoFunc init;
216
217 /* check the argument */
218 RequireStringRep("LOAD_DYN", filename);
219 if (!IS_INTOBJ(crc) && crc != False) {
220 ErrorMayQuit(
221 "LOAD_DYN: <crc> must be a small integer or 'false' (not a %s)",
222 (Int)TNAM_OBJ(crc), 0);
223 }
224
225 /* try to read the module */
226 #ifdef HAVE_DLOPEN
227 res = SyLoadModule(CONST_CSTR_STRING(filename), &init);
228 if (res == 1)
229 ErrorQuit("module '%g' not found", (Int)filename, 0L);
230 else if (res == 3)
231 ErrorQuit("symbol 'Init_Dynamic' not found", 0L, 0L);
232 #else
233 /* no dynamic library support */
234 if (SyDebugLoading) {
235 Pr("#I LOAD_DYN: no support for dynamical loading\n", 0L, 0L);
236 }
237 return False;
238 #endif
239
240 /* get the description structure */
241 info = (*init)();
242 if (info == 0)
243 ErrorQuit("call to init function failed", 0L, 0L);
244
245 // info->type should not be larger than kernel version
246 if (info->type / 10 > GAP_KERNEL_API_VERSION)
247 ErrorMayQuit("LOAD_DYN: kernel module built for newer "
248 "version of GAP",
249 0L, 0L);
250
251 // info->type should not have an older major version
252 if (info->type / 10000 < GAP_KERNEL_MAJOR_VERSION)
253 ErrorMayQuit("LOAD_DYN: kernel module built for older "
254 "version of GAP",
255 0L, 0L);
256
257 // info->type % 10 should be 0, 1 or 2, for the 3 types of module
258 if (info->type % 10 > 2)
259 ErrorMayQuit("LOAD_DYN: Invalid kernel module", 0L, 0L);
260
261 /* check the crc value */
262 if (crc != False) {
263 crc1 = ObjInt_Int(info->crc);
264 if (!EQ(crc, crc1)) {
265 if (SyDebugLoading) {
266 Pr("#I LOAD_DYN: crc values do not match, gap ", 0L, 0L);
267 PrintInt(crc);
268 Pr(", dyn ", 0L, 0L);
269 PrintInt(crc1);
270 Pr("\n", 0L, 0L);
271 }
272 return False;
273 }
274 }
275
276 ActivateModule(info);
277 RecordLoadedModule(info, 0, CONST_CSTR_STRING(filename));
278
279 return True;
280 }
281
282
283 /****************************************************************************
284 **
285 *F FuncLOAD_STAT( <self>, <name>, <crc> ) . . . . try to load static module
286 */
FuncLOAD_STAT(Obj self,Obj filename,Obj crc)287 static Obj FuncLOAD_STAT(Obj self, Obj filename, Obj crc)
288 {
289 StructInitInfo * info = 0;
290 Obj crc1;
291 Int k;
292
293 /* check the argument */
294 RequireStringRep("LOAD_STAT", filename);
295 if (!IS_INTOBJ(crc) && crc != False) {
296 ErrorMayQuit(
297 "LOAD_STAT: <crc> must be a small integer or 'false' (not a %s)",
298 (Int)TNAM_OBJ(crc), 0);
299 }
300
301 /* try to find the module */
302 for (k = 0; CompInitFuncs[k]; k++) {
303 info = (*(CompInitFuncs[k]))();
304 if (info && !strcmp(CONST_CSTR_STRING(filename), info->name)) {
305 break;
306 }
307 }
308 if (CompInitFuncs[k] == 0) {
309 if (SyDebugLoading) {
310 Pr("#I LOAD_STAT: no module named '%g' found\n", (Int)filename,
311 0L);
312 }
313 return False;
314 }
315
316 /* check the crc value */
317 if (crc != False) {
318 crc1 = ObjInt_Int(info->crc);
319 if (!EQ(crc, crc1)) {
320 if (SyDebugLoading) {
321 Pr("#I LOAD_STAT: crc values do not match, gap ", 0L, 0L);
322 PrintInt(crc);
323 Pr(", stat ", 0L, 0L);
324 PrintInt(crc1);
325 Pr("\n", 0L, 0L);
326 }
327 return False;
328 }
329 }
330
331 ActivateModule(info);
332 RecordLoadedModule(info, 0, CONST_CSTR_STRING(filename));
333
334 return True;
335 }
336
337
338 /****************************************************************************
339 **
340 *F FuncSHOW_STAT() . . . . . . . . . . . . . . . . . . . show static modules
341 */
FuncSHOW_STAT(Obj self)342 static Obj FuncSHOW_STAT(Obj self)
343 {
344 Obj modules;
345 Obj name;
346 StructInitInfo * info;
347 Int k;
348 Int im;
349
350 /* count the number of install modules */
351 for (k = 0, im = 0; CompInitFuncs[k]; k++) {
352 info = (*(CompInitFuncs[k]))();
353 if (info == 0) {
354 continue;
355 }
356 im++;
357 }
358
359 /* make a list of modules with crc values */
360 modules = NEW_PLIST(T_PLIST, 2 * im);
361
362 for (k = 0; CompInitFuncs[k]; k++) {
363 info = (*(CompInitFuncs[k]))();
364 if (info == 0) {
365 continue;
366 }
367 name = MakeImmString(info->name);
368
369 PushPlist(modules, name);
370
371 /* compute the crc value */
372 PushPlist(modules, ObjInt_Int(info->crc));
373 }
374
375 return modules;
376 }
377
378
379 /****************************************************************************
380 **
381 *F FuncLoadedModules( <self> ) . . . . . . . . . . . list all loaded modules
382 */
FuncLoadedModules(Obj self)383 static Obj FuncLoadedModules(Obj self)
384 {
385 Int i;
386 StructInitInfo * m;
387 Obj str;
388 Obj list;
389
390 /* create a list */
391 list = NEW_PLIST(T_PLIST, NrModules * 3);
392 SET_LEN_PLIST(list, NrModules * 3);
393 for (i = 0; i < NrModules; i++) {
394 m = Modules[i].info;
395 if (IS_MODULE_BUILTIN(m->type)) {
396 SET_ELM_PLIST(list, 3 * i + 1, ObjsChar[(Int)'b']);
397 CHANGED_BAG(list);
398 str = MakeImmString(m->name);
399 SET_ELM_PLIST(list, 3 * i + 2, str);
400 SET_ELM_PLIST(list, 3 * i + 3, INTOBJ_INT(m->version));
401 }
402 else if (IS_MODULE_DYNAMIC(m->type)) {
403 SET_ELM_PLIST(list, 3 * i + 1, ObjsChar[(Int)'d']);
404 CHANGED_BAG(list);
405 str = MakeImmString(m->name);
406 SET_ELM_PLIST(list, 3 * i + 2, str);
407 CHANGED_BAG(list);
408 str = MakeImmString(Modules[i].filename);
409 SET_ELM_PLIST(list, 3 * i + 3, str);
410 }
411 else if (IS_MODULE_STATIC(m->type)) {
412 SET_ELM_PLIST(list, 3 * i + 1, ObjsChar[(Int)'s']);
413 CHANGED_BAG(list);
414 str = MakeImmString(m->name);
415 SET_ELM_PLIST(list, 3 * i + 2, str);
416 CHANGED_BAG(list);
417 str = MakeImmString(Modules[i].filename);
418 SET_ELM_PLIST(list, 3 * i + 3, str);
419 }
420 }
421 return list;
422 }
423
424
425 /****************************************************************************
426 **
427 *F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
428 */
429
430
431 /****************************************************************************
432 **
433 *F InitBagNamesFromTable( <table> ) . . . . . . . . . initialise bag names
434 */
InitBagNamesFromTable(const StructBagNames * tab)435 void InitBagNamesFromTable(const StructBagNames * tab)
436 {
437 Int i;
438
439 for (i = 0; tab[i].tnum != -1; i++) {
440 SET_TNAM_TNUM(tab[i].tnum, tab[i].name);
441 }
442 }
443
444
445 /****************************************************************************
446 **
447 *F InitClearFiltsTNumsFromTable( <tab> ) . . . initialise clear filts tnums
448 */
InitClearFiltsTNumsFromTable(const Int * tab)449 void InitClearFiltsTNumsFromTable(const Int * tab)
450 {
451 Int i;
452
453 for (i = 0; tab[i] != -1; i += 2) {
454 ClearFiltsTNums[tab[i]] = tab[i + 1];
455 ClearFiltsTNums[tab[i] | IMMUTABLE] = tab[i + 1] | IMMUTABLE;
456 }
457 }
458
459
460 /****************************************************************************
461 **
462 *F InitHasFiltListTNumsFromTable( <tab> ) . . initialise tester filts tnums
463 */
InitHasFiltListTNumsFromTable(const Int * tab)464 void InitHasFiltListTNumsFromTable(const Int * tab)
465 {
466 Int i;
467
468 for (i = 0; tab[i] != -1; i += 3) {
469 HasFiltListTNums[tab[i]][tab[i + 1]] = tab[i + 2];
470 HasFiltListTNums[tab[i] | IMMUTABLE][tab[i + 1]] = tab[i + 2];
471 }
472 }
473
474
475 /****************************************************************************
476 **
477 *F InitSetFiltListTNumsFromTable( <tab> ) . . initialise setter filts tnums
478 */
InitSetFiltListTNumsFromTable(const Int * tab)479 void InitSetFiltListTNumsFromTable(const Int * tab)
480 {
481 Int i;
482
483 for (i = 0; tab[i] != -1; i += 3) {
484 SetFiltListTNums[tab[i]][tab[i + 1]] = tab[i + 2];
485 SetFiltListTNums[tab[i] | IMMUTABLE][tab[i + 1]] =
486 tab[i + 2] | IMMUTABLE;
487 }
488 }
489
490
491 /****************************************************************************
492 **
493 *F InitResetFiltListTNumsFromTable( <tab> ) initialise unsetter filts tnums
494 */
InitResetFiltListTNumsFromTable(const Int * tab)495 void InitResetFiltListTNumsFromTable(const Int * tab)
496 {
497 Int i;
498
499 for (i = 0; tab[i] != -1; i += 3) {
500 ResetFiltListTNums[tab[i]][tab[i + 1]] = tab[i + 2];
501 ResetFiltListTNums[tab[i] | IMMUTABLE][tab[i + 1]] =
502 tab[i + 2] | IMMUTABLE;
503 }
504 }
505
ValidatedArgList(const char * name,int nargs,const char * argStr)506 static Obj ValidatedArgList(const char * name, int nargs, const char * argStr)
507 {
508 Obj args = ArgStringToList(argStr);
509 int len = LEN_PLIST(args);
510 if (nargs >= 0 && len != nargs)
511 fprintf(stderr,
512 "#W %s takes %d arguments, but argument string is '%s'"
513 " which implies %d arguments\n",
514 name, nargs, argStr, len);
515 return args;
516 }
517
518 /****************************************************************************
519 **
520 *F InitGVarFiltsFromTable( <tab> ) . . . . . . . . . . . . . . . new filters
521 */
InitGVarFiltsFromTable(const StructGVarFilt * tab)522 void InitGVarFiltsFromTable(const StructGVarFilt * tab)
523 {
524 Int i;
525
526 for (i = 0; tab[i].name != 0; i++) {
527 UInt gvar = GVarName(tab[i].name);
528 Obj name = NameGVar(gvar);
529 Obj args = ValidatedArgList(tab[i].name, 1, tab[i].argument);
530 AssReadOnlyGVar(gvar, NewFilter(name, args, tab[i].handler));
531 }
532 }
533
534
535 /****************************************************************************
536 **
537 *F InitGVarAttrsFromTable( <tab> ) . . . . . . . . . . . . . new attributes
538 */
InitGVarAttrsFromTable(const StructGVarAttr * tab)539 void InitGVarAttrsFromTable(const StructGVarAttr * tab)
540 {
541 Int i;
542
543 for (i = 0; tab[i].name != 0; i++) {
544 UInt gvar = GVarName(tab[i].name);
545 Obj name = NameGVar(gvar);
546 Obj args = ValidatedArgList(tab[i].name, 1, tab[i].argument);
547 AssReadOnlyGVar(gvar, NewAttribute(name, args, tab[i].handler));
548 }
549 }
550
551 /****************************************************************************
552 **
553 *F InitGVarPropsFromTable( <tab> ) . . . . . . . . . . . . . new properties
554 */
InitGVarPropsFromTable(const StructGVarProp * tab)555 void InitGVarPropsFromTable(const StructGVarProp * tab)
556 {
557 Int i;
558
559 for (i = 0; tab[i].name != 0; i++) {
560 UInt gvar = GVarName(tab[i].name);
561 Obj name = NameGVar(gvar);
562 Obj args = ValidatedArgList(tab[i].name, 1, tab[i].argument);
563 AssReadOnlyGVar(gvar, NewProperty(name, args, tab[i].handler));
564 }
565 }
566
567
568 /****************************************************************************
569 **
570 *F InitGVarOpersFromTable( <tab> ) . . . . . . . . . . . . . new operations
571 */
InitGVarOpersFromTable(const StructGVarOper * tab)572 void InitGVarOpersFromTable(const StructGVarOper * tab)
573 {
574 Int i;
575
576 for (i = 0; tab[i].name != 0; i++) {
577 UInt gvar = GVarName(tab[i].name);
578 Obj name = NameGVar(gvar);
579 Obj args = ValidatedArgList(tab[i].name, tab[i].nargs, tab[i].args);
580 AssReadOnlyGVar(
581 gvar, NewOperation(name, tab[i].nargs, args, tab[i].handler));
582 }
583 }
584
SetupFuncInfo(Obj func,const Char * cookie)585 static void SetupFuncInfo(Obj func, const Char * cookie)
586 {
587 // The string <cookie> usually has the form "PATH/TO/FILE.c:FUNCNAME".
588 // We check if that is the case, and if so, split it into the parts before
589 // and after the colon. In addition, the file path is cut to only contain
590 // the last two '/'-separated components.
591 const Char * pos = strchr(cookie, ':');
592 if (pos) {
593 Obj location = MakeImmString(pos + 1);
594
595 Obj filename;
596 char buffer[512];
597 Int len = 511 < (pos - cookie) ? 511 : pos - cookie;
598 memcpy(buffer, cookie, len);
599 buffer[len] = 0;
600
601 Char * start = strrchr(buffer, '/');
602 if (start) {
603 while (start > buffer && *(start - 1) != '/')
604 start--;
605 }
606 else
607 start = buffer;
608 filename = MakeImmString(start);
609
610 Obj body_bag = NewFunctionBody();
611 SET_FILENAME_BODY(body_bag, filename);
612 SET_LOCATION_BODY(body_bag, location);
613 SET_BODY_FUNC(func, body_bag);
614 CHANGED_BAG(body_bag);
615 CHANGED_BAG(func);
616 }
617 }
618
619 /****************************************************************************
620 **
621 *F InitGVarFuncsFromTable( <tab> ) . . . . . . . . . . . . . . new functions
622 */
InitGVarFuncsFromTable(const StructGVarFunc * tab)623 void InitGVarFuncsFromTable(const StructGVarFunc * tab)
624 {
625 Int i;
626
627 for (i = 0; tab[i].name != 0; i++) {
628 UInt gvar = GVarName(tab[i].name);
629 Obj name = NameGVar(gvar);
630 Obj args = ValidatedArgList(tab[i].name, tab[i].nargs, tab[i].args);
631 Obj func = NewFunction(name, tab[i].nargs, args, tab[i].handler);
632 SetupFuncInfo(func, tab[i].cookie);
633 AssReadOnlyGVar(gvar, func);
634 }
635 }
636
637
638 /****************************************************************************
639 **
640 *F InitHdlrFiltsFromTable( <tab> ) . . . . . . . . . . . . . . . new filters
641 */
InitHdlrFiltsFromTable(const StructGVarFilt * tab)642 void InitHdlrFiltsFromTable(const StructGVarFilt * tab)
643 {
644 Int i;
645
646 for (i = 0; tab[i].name != 0; i++) {
647 InitHandlerFunc(tab[i].handler, tab[i].cookie);
648 InitFopyGVar(tab[i].name, tab[i].filter);
649 }
650 }
651
652
653 /****************************************************************************
654 **
655 *F InitHdlrAttrsFromTable( <tab> ) . . . . . . . . . . . . . new attributes
656 */
InitHdlrAttrsFromTable(const StructGVarAttr * tab)657 void InitHdlrAttrsFromTable(const StructGVarAttr * tab)
658 {
659 Int i;
660
661 for (i = 0; tab[i].name != 0; i++) {
662 InitHandlerFunc(tab[i].handler, tab[i].cookie);
663 InitFopyGVar(tab[i].name, tab[i].attribute);
664 }
665 }
666
667
668 /****************************************************************************
669 **
670 *F InitHdlrPropsFromTable( <tab> ) . . . . . . . . . . . . . new properties
671 */
InitHdlrPropsFromTable(const StructGVarProp * tab)672 void InitHdlrPropsFromTable(const StructGVarProp * tab)
673 {
674 Int i;
675
676 for (i = 0; tab[i].name != 0; i++) {
677 InitHandlerFunc(tab[i].handler, tab[i].cookie);
678 InitFopyGVar(tab[i].name, tab[i].property);
679 }
680 }
681
682
683 /****************************************************************************
684 **
685 *F InitHdlrOpersFromTable( <tab> ) . . . . . . . . . . . . . new operations
686 */
InitHdlrOpersFromTable(const StructGVarOper * tab)687 void InitHdlrOpersFromTable(const StructGVarOper * tab)
688 {
689 Int i;
690
691 for (i = 0; tab[i].name != 0; i++) {
692 InitHandlerFunc(tab[i].handler, tab[i].cookie);
693 InitFopyGVar(tab[i].name, tab[i].operation);
694 }
695 }
696
697
698 /****************************************************************************
699 **
700 *F InitHdlrFuncsFromTable( <tab> ) . . . . . . . . . . . . . . new functions
701 */
InitHdlrFuncsFromTable(const StructGVarFunc * tab)702 void InitHdlrFuncsFromTable(const StructGVarFunc * tab)
703 {
704 Int i;
705
706 for (i = 0; tab[i].name != 0; i++) {
707 InitHandlerFunc(tab[i].handler, tab[i].cookie);
708 }
709 }
710
711
712 /****************************************************************************
713 **
714 *F ImportGVarFromLibrary( <name>, <address> ) . . . import global variable
715 */
716
717
ImportGVarFromLibrary(const Char * name,Obj * address)718 void ImportGVarFromLibrary(const Char * name, Obj * address)
719 {
720 if (NrImportedGVars == 1024) {
721 Pr("#W warning: too many imported GVars\n", 0L, 0L);
722 }
723 else {
724 ImportedGVars[NrImportedGVars].name = name;
725 ImportedGVars[NrImportedGVars].address = address;
726 NrImportedGVars++;
727 }
728 if (address != 0) {
729 InitCopyGVar(name, address);
730 }
731 }
732
733
734 /****************************************************************************
735 **
736 *F ImportFuncFromLibrary( <name>, <address> ) . . . import global function
737 */
738
739
ImportFuncFromLibrary(const Char * name,Obj * address)740 void ImportFuncFromLibrary(const Char * name, Obj * address)
741 {
742 if (NrImportedFuncs == 1024) {
743 Pr("#W warning: too many imported Funcs\n", 0L, 0L);
744 }
745 else {
746 ImportedFuncs[NrImportedFuncs].name = name;
747 ImportedFuncs[NrImportedFuncs].address = address;
748 NrImportedFuncs++;
749 }
750 if (address != 0) {
751 InitFopyGVar(name, address);
752 }
753 }
754
755
756 /****************************************************************************
757 **
758 *F FuncExportToKernelFinished( <self> ) . . . . . . . . . . check functions
759 */
FuncExportToKernelFinished(Obj self)760 static Obj FuncExportToKernelFinished(Obj self)
761 {
762 UInt i;
763 Int errs = 0;
764 Obj val;
765
766 SyInitializing = 0;
767 for (i = 0; i < NrImportedGVars; i++) {
768 if (ImportedGVars[i].address == 0) {
769 val = ValAutoGVar(GVarName(ImportedGVars[i].name));
770 if (val == 0) {
771 errs++;
772 if (!SyQuiet) {
773 Pr("#W global variable '%s' has not been defined\n",
774 (Int)ImportedFuncs[i].name, 0L);
775 }
776 }
777 }
778 else if (*ImportedGVars[i].address == 0) {
779 errs++;
780 if (!SyQuiet) {
781 Pr("#W global variable '%s' has not been defined\n",
782 (Int)ImportedGVars[i].name, 0L);
783 }
784 }
785 else {
786 MakeReadOnlyGVar(GVarName(ImportedGVars[i].name));
787 }
788 }
789
790 for (i = 0; i < NrImportedFuncs; i++) {
791 if (ImportedFuncs[i].address == 0) {
792 val = ValAutoGVar(GVarName(ImportedFuncs[i].name));
793 if (val == 0 || !IS_FUNC(val)) {
794 errs++;
795 if (!SyQuiet) {
796 Pr("#W global function '%s' has not been defined\n",
797 (Int)ImportedFuncs[i].name, 0L);
798 }
799 }
800 }
801 else if (*ImportedFuncs[i].address == ErrorMustEvalToFuncFunc ||
802 *ImportedFuncs[i].address == ErrorMustHaveAssObjFunc) {
803 errs++;
804 if (!SyQuiet) {
805 Pr("#W global function '%s' has not been defined\n",
806 (Int)ImportedFuncs[i].name, 0L);
807 }
808 }
809 else {
810 MakeReadOnlyGVar(GVarName(ImportedFuncs[i].name));
811 }
812 }
813
814 return errs == 0 ? True : False;
815 }
816
817
818 /****************************************************************************
819 **
820 *F RecordLoadedModule( <module> ) . . . . . . . . store module in <Modules>
821 */
822
RecordLoadedModule(StructInitInfo * info,Int isGapRootRelative,const Char * filename)823 void RecordLoadedModule(StructInitInfo * info,
824 Int isGapRootRelative,
825 const Char * filename)
826 {
827 UInt len;
828 if (NrModules == MAX_MODULES) {
829 Panic("no room to record module");
830 }
831 len = strlen(filename);
832 if (NextLoadedModuleFilename + len + 1 >
833 LoadedModuleFilenames + MAX_MODULE_FILENAMES) {
834 Panic("no room for module filename");
835 }
836 *NextLoadedModuleFilename = '\0';
837 memcpy(NextLoadedModuleFilename, filename, len + 1);
838 Modules[NrModules].info = info;
839 Modules[NrModules].filename = NextLoadedModuleFilename;
840 NextLoadedModuleFilename += len + 1;
841 Modules[NrModules].isGapRootRelative = isGapRootRelative;
842 NrModules++;
843 }
844
845
SaveModules(void)846 void SaveModules(void)
847 {
848 SaveUInt(NrModules - NrBuiltinModules);
849 for (UInt i = NrBuiltinModules; i < NrModules; i++) {
850 SaveUInt(Modules[i].info->type);
851 SaveUInt(Modules[i].isGapRootRelative);
852 SaveCStr(Modules[i].filename);
853 }
854 }
855
LoadModules(void)856 void LoadModules(void)
857 {
858 Char buf[256];
859 UInt nMods = LoadUInt();
860 for (UInt i = 0; i < nMods; i++) {
861 UInt type = LoadUInt();
862 UInt isGapRootRelative = LoadUInt();
863 LoadCStr(buf, 256);
864 if (isGapRootRelative)
865 READ_GAP_ROOT(buf);
866 else {
867 StructInitInfo * info = NULL;
868 /* Search for user module static case first */
869 if (IS_MODULE_STATIC(type)) {
870 UInt k;
871 for (k = 0; CompInitFuncs[k]; k++) {
872 info = (*(CompInitFuncs[k]))();
873 if (info == 0) {
874 continue;
875 }
876 if (!strcmp(buf, info->name)) {
877 break;
878 }
879 }
880 if (CompInitFuncs[k] == 0) {
881 Pr("Static module %s not found in loading kernel\n",
882 (Int)buf, 0L);
883 SyExit(1);
884 }
885 }
886 else {
887 /* and dynamic case */
888 InitInfoFunc init;
889
890 #ifdef HAVE_DLOPEN
891 int res = SyLoadModule(buf, &init);
892 if (res != 0) {
893 Panic("Failed to load needed dynamic module %s, error "
894 "code %d\n",
895 buf, res);
896 }
897 info = (*init)();
898 if (info == 0) {
899 Panic("Failed to init needed dynamic module %s, error "
900 "code %d\n",
901 buf, res);
902 }
903 #else
904 Panic("workspace require dynamic module %s, but dynamic "
905 "loading not supported",
906 buf);
907 #endif
908 }
909
910 ActivateModule(info);
911 RecordLoadedModule(info, 0, buf);
912 }
913 }
914 }
915
ModulesSetup(void)916 void ModulesSetup(void)
917 {
918 NrImportedGVars = 0;
919 NrImportedFuncs = 0;
920 NrModules = 0;
921 for (UInt i = 0; InitFuncsBuiltinModules[i]; i++) {
922 if (NrModules == MAX_MODULES) {
923 Panic("too many builtin modules");
924 }
925 StructInitInfo * info = InitFuncsBuiltinModules[i]();
926 Modules[NrModules++].info = info;
927 if (SyDebugLoading) {
928 fputs("#I InitInfo(builtin ", stderr);
929 fputs(info->name, stderr);
930 fputs(")\n", stderr);
931 }
932
933 RegisterModuleState(info);
934 }
935 NrBuiltinModules = NrModules;
936 }
937
ModulesInitKernel(void)938 void ModulesInitKernel(void)
939 {
940 for (UInt i = 0; i < NrBuiltinModules; i++) {
941 StructInitInfo * info = Modules[i].info;
942 if (info->initKernel) {
943 if (SyDebugLoading) {
944 fputs("#I InitKernel(builtin ", stderr);
945 fputs(info->name, stderr);
946 fputs(")\n", stderr);
947 }
948 Int ret = info->initKernel(info);
949 if (ret) {
950 Panic("InitKernel(builtin %s) returned non-zero value", info->name);
951 }
952 }
953 }
954 }
955
ModulesInitLibrary(void)956 void ModulesInitLibrary(void)
957 {
958 for (UInt i = 0; i < NrBuiltinModules; i++) {
959 StructInitInfo * info = Modules[i].info;
960 if (info->initLibrary) {
961 if (SyDebugLoading) {
962 fputs("#I InitLibrary(builtin ", stderr);
963 fputs(info->name, stderr);
964 fputs(")\n", stderr);
965 }
966 Int ret = info->initLibrary(info);
967 if (ret) {
968 Panic("InitLibrary(builtin %s) returned non-zero value", info->name);
969 }
970 }
971 }
972 }
973
ModulesCheckInit(void)974 void ModulesCheckInit(void)
975 {
976 for (UInt i = 0; i < NrModules; i++) {
977 StructInitInfo * info = Modules[i].info;
978 if (info->checkInit) {
979 if (SyDebugLoading) {
980 fputs("#I CheckInit(builtin ", stderr);
981 fputs(info->name, stderr);
982 fputs(")\n", stderr);
983 }
984 Int ret = info->checkInit(info);
985 if (ret) {
986 Panic("CheckInit(builtin %s) returned non-zero value", info->name);
987 }
988 }
989 }
990 }
991
ModulesInitModuleState(void)992 void ModulesInitModuleState(void)
993 {
994 for (UInt i = 0; i < NrModules; i++) {
995 StructInitInfo * info = Modules[i].info;
996 if (info->initModuleState) {
997 if (SyDebugLoading) {
998 fputs("#I InitModuleState(", stderr);
999 fputs(info->name, stderr);
1000 fputs(")\n", stderr);
1001 }
1002 Int ret = info->initModuleState();
1003 if (ret) {
1004 Panic("InitModuleState(builtin %s) returned non-zero value", info->name);
1005 }
1006 }
1007 }
1008 }
1009
ModulesDestroyModuleState(void)1010 void ModulesDestroyModuleState(void)
1011 {
1012 for (UInt i = 0; i < NrModules; i++) {
1013 StructInitInfo * info = Modules[i].info;
1014 if (info->destroyModuleState) {
1015 if (SyDebugLoading) {
1016 fputs("#I DestroyModuleState(", stderr);
1017 fputs(info->name, stderr);
1018 fputs(")\n", stderr);
1019 }
1020 Int ret = info->destroyModuleState();
1021 if (ret) {
1022 Panic("DestroyModuleState(builtin %s) returned non-zero value", info->name);
1023 }
1024 }
1025 }
1026 }
1027
1028
ModulesPreSave(void)1029 Int ModulesPreSave(void)
1030 {
1031 for (UInt i = 0; i < NrModules; i++) {
1032 StructInitInfo * info = Modules[i].info;
1033 if (info->preSave != NULL && info->preSave(info)) {
1034 Pr("Failed to save workspace -- problem reported in %s\n",
1035 (Int)info->name, 0L);
1036 // roll back all save preparations
1037 while (i--) {
1038 info = Modules[i].info;
1039 info->postSave(info);
1040 }
1041 return 1;
1042 }
1043 }
1044 return 0;
1045 }
1046
ModulesPostSave(void)1047 void ModulesPostSave(void)
1048 {
1049 for (UInt i = 0; i < NrModules; i++) {
1050 StructInitInfo * info = Modules[i].info;
1051 if (info->postSave != NULL)
1052 info->postSave(info);
1053 }
1054 }
1055
ModulesPostRestore(void)1056 void ModulesPostRestore(void)
1057 {
1058 for (UInt i = 0; i < NrModules; i++) {
1059 StructInitInfo * info = Modules[i].info;
1060 if (info->postRestore) {
1061 if (SyDebugLoading) {
1062 fputs("#I PostRestore(builtin ", stderr);
1063 fputs(info->name, stderr);
1064 fputs(")\n", stderr);
1065 }
1066 Int ret = info->postRestore(info);
1067 if (ret) {
1068 Panic("PostRestore(builtin %s) returned non-zero value", info->name);
1069 }
1070 }
1071 }
1072 }
1073
1074
1075 /****************************************************************************
1076 **
1077 *V GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
1078 */
1079 static StructGVarFunc GVarFuncs[] = {
1080 GVAR_FUNC(GAP_CRC, 1, "filename"),
1081 GVAR_FUNC(LOAD_DYN, 2, "filename, crc"),
1082 GVAR_FUNC(LOAD_STAT, 2, "filename, crc"),
1083 GVAR_FUNC(SHOW_STAT, 0, ""),
1084 GVAR_FUNC(LoadedModules, 0, ""),
1085 GVAR_FUNC(ExportToKernelFinished, 0, ""),
1086 { 0, 0, 0, 0, 0 }
1087 };
1088
1089
1090 /****************************************************************************
1091 **
1092 *F InitKernel( <module> ) . . . . . . . . initialise kernel data structures
1093 */
InitKernel(StructInitInfo * module)1094 static Int InitKernel(StructInitInfo * module)
1095 {
1096 // init filters and functions
1097 InitHdlrFuncsFromTable(GVarFuncs);
1098
1099 // return success
1100 return 0;
1101 }
1102
1103
1104 /****************************************************************************
1105 **
1106 *F InitLibrary( <module> ) . . . . . . . initialise library data structures
1107 */
InitLibrary(StructInitInfo * module)1108 static Int InitLibrary(StructInitInfo * module)
1109 {
1110 // init filters and functions
1111 InitGVarFuncsFromTable(GVarFuncs);
1112
1113 // return success
1114 return 0;
1115 }
1116
1117
1118 /****************************************************************************
1119 **
1120 *F InitInfoModules() . . . . . . . . . . . . . . . . table of init functions
1121 */
1122 static StructInitInfo module = {
1123 // init struct using C99 designated initializers; for a full list of
1124 // fields, please refer to the definition of StructInitInfo
1125 .type = MODULE_BUILTIN,
1126 .name = "modules",
1127 .initKernel = InitKernel,
1128 .initLibrary = InitLibrary,
1129 };
1130
InitInfoModules(void)1131 StructInitInfo * InitInfoModules(void)
1132 {
1133 return &module;
1134 }
1135