Skip to content

Instantly share code, notes, and snippets.

@dcdillon
Created December 22, 2016 03:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dcdillon/814e769adbf53ff43961f106008b3312 to your computer and use it in GitHub Desktop.
Save dcdillon/814e769adbf53ff43961f106008b3312 to your computer and use it in GitHub Desktop.
Index: src/main/Rdynload.c
===================================================================
--- src/main/Rdynload.c (revision 71827)
+++ src/main/Rdynload.c (working copy)
@@ -134,9 +134,19 @@
#include <R_ext/Rdynload.h>
-static DllInfo LoadedDLL[MAX_NUM_DLLS];
+struct _DllInfoNode
+{
+ DllInfo info;
+ struct _DllInfoNode *prev;
+ struct _DllInfoNode *next;
+};
-static int addDLL(char *dpath, char *name, HINSTANCE handle);
+typedef struct _DllInfoNode DllInfoNode;
+
+static DllInfoNode *LoadedDLL = NULL;
+
+static DllInfo *addDLL(char *dpath, char *name, HINSTANCE handle,
+ DllInfoNode *node);
static SEXP Rf_MakeDLLInfo(DllInfo *info);
static SEXP createRSymbolObject(SEXP sname, DL_FUNC f,
@@ -156,8 +166,12 @@
InitDynload()
{
DllInfo *dll;
- int which = addDLL(strdup("base"), "base", NULL);
- dll = &LoadedDLL[which];
+ DllInfoNode *node = (DllInfoNode *)malloc(sizeof(DllInfoNode));
+ if(!node)
+ error("allocation failure in InitDynload");
+ node->prev = NULL;
+ node->next = NULL;
+ dll = addDLL(strdup("base"), "base", NULL, node);
R_init_base(dll);
InitFunctionHashing();
}
@@ -168,8 +182,13 @@
{
DllInfo *dll = R_getDllInfo("(embedding)");
if (dll == NULL) {
- int which = addDLL(strdup("(embedding)"), "(embedding)", NULL);
- dll = &LoadedDLL[which];
+ DllInfoNode *node = (DllInfoNode *)malloc(sizeof(DllInfoNode));
+ if(!node)
+ error("allocation failure in R_getEmbeddingDllInfo");
+ node->prev = NULL;
+ node->next = NULL;
+ dll = addDLL(strdup("(embedding)"), "(embedding)", NULL, node);
+
/* make sure we don't attempt dynamic lookup */
R_useDynamicSymbols(dll, FALSE);
}
@@ -222,9 +241,26 @@
DllInfo *
R_getDllInfo(const char *path)
{
- int i;
- for(i = 0; i < CountDLL; i++) {
- if(strcmp(LoadedDLL[i].path, path) == 0) return(&LoadedDLL[i]);
+ DllInfoNode *current = LoadedDLL;
+
+ while (current != NULL) {
+ if(strcmp(current->info.path, path) == 0) {
+#ifdef USE_DLL_MRU
+ /*
+ This will promote the most recently accessed dll to the front
+ of the list making subsequent lookups more efficient for the
+ Most Recently Used dll.
+ */
+ if (current->prev) current->prev->next = current->next;
+ if (current->next) current->next->prev = current->prev;
+
+ current->next = LoadedDLL;
+ if (LoadedDLL) LoadedDLL->prev = current;
+ LoadedDLL = current;
+#endif
+ return(&current->info);
+ }
+ current = current->next;
}
return (DllInfo*) NULL;
}
@@ -453,39 +489,37 @@
static int DeleteDLL(const char *path)
{
- int i, loc;
+ DllInfoNode *current = LoadedDLL;
- for (i = 0; i < CountDLL; i++) {
- if (!strcmp(path, LoadedDLL[i].path)) {
- loc = i;
+ while (current != NULL) {
+ if (!strcmp(path, current->info.path)) {
goto found;
}
+ current = current->next;
}
return 0;
found:
#ifdef CACHE_DLL_SYM
if(R_osDynSymbol->deleteCachedSymbols)
- R_osDynSymbol->deleteCachedSymbols(&LoadedDLL[loc]);
+ R_osDynSymbol->deleteCachedSymbols(current->info);
#endif
- R_callDLLUnload(&LoadedDLL[loc]);
- R_osDynSymbol->closeLibrary(LoadedDLL[loc].handle);
- Rf_freeDllInfo(LoadedDLL+loc);
- /* FIXME: why not use memcpy here? */
- for(i = loc + 1 ; i < CountDLL ; i++) {
- LoadedDLL[i - 1].path = LoadedDLL[i].path;
- LoadedDLL[i - 1].name = LoadedDLL[i].name;
- LoadedDLL[i - 1].handle = LoadedDLL[i].handle;
- LoadedDLL[i - 1].useDynamicLookup = LoadedDLL[i].useDynamicLookup;
- LoadedDLL[i - 1].numCSymbols = LoadedDLL[i].numCSymbols;
- LoadedDLL[i - 1].numCallSymbols = LoadedDLL[i].numCallSymbols;
- LoadedDLL[i - 1].numFortranSymbols = LoadedDLL[i].numFortranSymbols;
- LoadedDLL[i - 1].numExternalSymbols = LoadedDLL[i].numExternalSymbols;
- LoadedDLL[i - 1].CSymbols = LoadedDLL[i].CSymbols;
- LoadedDLL[i - 1].CallSymbols = LoadedDLL[i].CallSymbols;
- LoadedDLL[i - 1].FortranSymbols = LoadedDLL[i].FortranSymbols;
- LoadedDLL[i - 1].ExternalSymbols = LoadedDLL[i].ExternalSymbols;
- LoadedDLL[i - 1].forceSymbols = LoadedDLL[i].forceSymbols;
+ R_callDLLUnload(&current->info);
+ R_osDynSymbol->closeLibrary(current->info.handle);
+ Rf_freeDllInfo(&current->info);
+
+ if (current->prev) {
+ current->prev->next = current->next;
}
+
+ if (current->next) {
+ current->next->prev = current->prev;
+ }
+
+ if (current == LoadedDLL) {
+ LoadedDLL = current->next;
+ }
+
+ free(current);
CountDLL--;
return 1;
}
@@ -529,10 +563,6 @@
DllInfo *info = NULL;
DeleteDLL(path);
- if(CountDLL == MAX_NUM_DLLS) {
- strcpy(DLLerror, _("`maximal number of DLLs reached..."));
- return NULL;
- }
handle = R_osDynSymbol->loadLibrary(path, asLocal, now, DLLsearchpath);
@@ -578,7 +608,15 @@
char *dpath, DLLname[PATH_MAX], *p;
DllInfo *info;
- info = &LoadedDLL[CountDLL];
+ DllInfoNode *node = (DllInfoNode *)malloc(sizeof(DllInfoNode));
+ if(!node) {
+ strcpy(DLLerror, _("allocation failure in R_RegisterDLL"));
+ return NULL;
+ }
+ node->prev = NULL;
+ node->next = NULL;
+
+ info = &node->info;
/* default is to use old-style dynamic lookup. The object's
initialization routine can limit access by setting this to FALSE.
*/
@@ -589,7 +627,8 @@
if(dpath == NULL) {
strcpy(DLLerror, _("could not allocate space for 'path'"));
R_osDynSymbol->closeLibrary(handle);
- return 0;
+ free(node);
+ return NULL;
}
strcpy(dpath, path);
@@ -609,15 +648,14 @@
if(p > DLLname && strcmp(p, SHLIB_EXT) == 0) *p = '\0';
#endif
- addDLL(dpath, DLLname, handle);
+ addDLL(dpath, DLLname, handle, node);
return(info);
}
-static int
-addDLL(char *dpath, char *DLLname, HINSTANCE handle)
+static DllInfo *
+addDLL(char *dpath, char *DLLname, HINSTANCE handle, DllInfoNode *node)
{
- int ans = CountDLL;
char *name = (char *) malloc(strlen(DLLname)+1);
if(name == NULL) {
strcpy(DLLerror, _("could not allocate space for 'name'"));
@@ -624,25 +662,32 @@
if(handle)
R_osDynSymbol->closeLibrary(handle);
free(dpath);
- return 0;
+ free(node);
+ return NULL;
}
strcpy(name, DLLname);
- LoadedDLL[CountDLL].path = dpath;
- LoadedDLL[CountDLL].name = name;
- LoadedDLL[CountDLL].handle = handle;
+ node->info.path = dpath;
+ node->info.name = name;
+ node->info.handle = handle;
- LoadedDLL[CountDLL].numCSymbols = 0;
- LoadedDLL[CountDLL].numCallSymbols = 0;
- LoadedDLL[CountDLL].numFortranSymbols = 0;
- LoadedDLL[CountDLL].numExternalSymbols = 0;
- LoadedDLL[CountDLL].CSymbols = NULL;
- LoadedDLL[CountDLL].CallSymbols = NULL;
- LoadedDLL[CountDLL].FortranSymbols = NULL;
- LoadedDLL[CountDLL].ExternalSymbols = NULL;
+ node->info.numCSymbols = 0;
+ node->info.numCallSymbols = 0;
+ node->info.numFortranSymbols = 0;
+ node->info.numExternalSymbols = 0;
+ node->info.CSymbols = NULL;
+ node->info.CallSymbols = NULL;
+ node->info.FortranSymbols = NULL;
+ node->info.ExternalSymbols = NULL;
+
+ node->prev = NULL;
+ node->next = LoadedDLL;
+
+ if (node->next) node->next->prev = node;
+
CountDLL++;
-
- return(ans);
+ LoadedDLL = node;
+ return(&node->info);
}
static Rf_DotCSymbol *
@@ -821,19 +866,29 @@
/* function pointers _are_ the same size and _can_ */
/* be cast without loss of information. */
- for (i = CountDLL - 1; i >= 0; i--) {
+ DllInfoNode *current = LoadedDLL;
+
+ while (current != NULL) {
doit = all;
- if(!doit && !strcmp(pkg, LoadedDLL[i].name)) doit = 2;
- if(doit && LoadedDLL[i].forceSymbols) doit = 0;
+ if(!doit && !strcmp(pkg, current->info.name)) doit = 2;
+ if(doit && current->info.forceSymbols) doit = 0;
if(doit) {
- fcnptr = R_dlsym(&LoadedDLL[i], name, symbol); /* R_osDynSymbol->dlsym */
+ fcnptr = R_dlsym(&current->info, name, symbol); /* R_osDynSymbol->dlsym */
if (fcnptr != (DL_FUNC) NULL) {
if(symbol)
- symbol->dll = LoadedDLL+i;
+#ifdef USE_DLL_MRU
+ if (current->prev) current->prev->next = current->next;
+ if (current->next) current->next->prev = current->prev;
+
+ current->next = LoadedDLL;
+ if (LoadedDLL) LoadedDLL->prev = current;
+ LoadedDLL = current;
+#endif
+ symbol->dll = &current->info;
#ifdef CACHE_DLL_SYM
if(strlen(pkg) <= 20 && strlen(name) <= 40 && nCPFun < MAX_CACHE
&& (!symbol || !symbol->symbol.c)) {
- strcpy(CPFun[nCPFun].pkg, LoadedDLL[i].name);
+ strcpy(CPFun[nCPFun].pkg, current->info.name);
strcpy(CPFun[nCPFun].name, name);
CPFun[nCPFun++].func = fcnptr;
}
@@ -842,6 +897,8 @@
}
}
if(doit > 1) return (DL_FUNC) NULL; /* Only look in the first-matching DLL */
+
+ current = current->next;
}
return (DL_FUNC) NULL;
@@ -1118,11 +1175,19 @@
{
int i;
SEXP ans;
-
+ DllInfoNode *current;
+
again:
+ current = LoadedDLL;
+
PROTECT(ans = allocVector(VECSXP, CountDLL));
- for(i = 0; i < CountDLL; i++) {
- SET_VECTOR_ELT(ans, i, Rf_MakeDLLInfo(&(LoadedDLL[i])));
+
+ i = 0;
+
+ while (current && i < CountDLL) {
+ SET_VECTOR_ELT(ans, i, Rf_MakeDLLInfo(&(current->info)));
+ current = current->next;
+ i++;
}
setAttrib(ans, R_ClassSymbol, mkString("DLLInfoList"));
UNPROTECT(1);
@@ -1132,6 +1197,7 @@
CountDLL can be reduced during this loop. A simple work-around
is to just try again until CountDLL at the end is the same as
it was at the beginning. LT */
+
if (CountDLL != LENGTH(ans))
goto again;
@@ -1335,13 +1401,20 @@
do_getDllTable(SEXP call, SEXP op, SEXP args, SEXP env)
{
SEXP ans, nm;
-
+ int i;
checkArity(op, args);
again:
PROTECT(ans = allocVector(VECSXP, CountDLL));
- for(int i = 0; i < CountDLL; i++)
- SET_VECTOR_ELT(ans, i, Rf_MakeDLLInfo(&(LoadedDLL[i])));
+
+ DllInfoNode *current = LoadedDLL;
+
+ i = 0;
+ while (current && i < CountDLL) {
+ SET_VECTOR_ELT(ans, i, Rf_MakeDLLInfo(&(current->info)));
+ current = current->next;
+ i++;
+ }
setAttrib(ans, R_ClassSymbol, mkString("DLLInfoList"));
UNPROTECT(1);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment