dynamo.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /* No Copyright. */
  2. /*
  3. * Lookup external names in the running scheme virtual machine and, on
  4. * machines which support it, do dynamic loading.
  5. */
  6. #include <stdlib.h>
  7. #include <unistd.h>
  8. #include <string.h>
  9. #include "sysdep.h"
  10. #include "scheme48.h"
  11. #include "c-mods.h"
  12. #if defined(HAVE_DLOPEN)
  13. #include <dlfcn.h>
  14. #else
  15. #include "fake/dlfcn.h"
  16. #endif
  17. #if defined(RTLD_NOW)
  18. #define DLOPEN_MODE RTLD_NOW
  19. #elif defined(RTLD_LAZY)
  20. #define DLOPEN_MODE (RTLD_LAZY)
  21. #else
  22. #define DLOPEN_MODE (1)
  23. #endif
  24. /*
  25. * Linked list of dynamically loaded libraries.
  26. */
  27. static struct dlob {
  28. struct dlob *next;
  29. char *name;
  30. void *handle;
  31. } *dlobs;
  32. static s48_value s48_external_lookup(s48_value svname, s48_value svlocp),
  33. s48_old_external_call(s48_value svproc, s48_value svargv),
  34. s48_dynamic_load(s48_value filename);
  35. static long lookup_external_name(char *name, long *locp);
  36. static psbool dynamic_load(char *name);
  37. /*
  38. * Install all exported functions in Scheme48.
  39. */
  40. void
  41. s48_init_external_lookup(void)
  42. {
  43. S48_EXPORT_FUNCTION(s48_external_lookup);
  44. S48_EXPORT_FUNCTION(s48_old_external_call);
  45. S48_EXPORT_FUNCTION(s48_dynamic_load);
  46. }
  47. /*
  48. * Glue between Scheme48 types and C types for external name lookup.
  49. * Look up svname (either in a dynamically loaded library, or in the
  50. * running executable).
  51. * On success we return PSTRUE, having set *(long *)svlocp to the location.
  52. * On failure, we return PSFALSE.
  53. */
  54. static s48_value
  55. s48_external_lookup(s48_value svname, s48_value svlocp)
  56. {
  57. char *name;
  58. long *locp,
  59. res;
  60. name = s48_extract_byte_vector(svname);
  61. locp = S48_EXTRACT_VALUE_POINTER(svlocp, long);
  62. res = lookup_external_name(name, locp);
  63. return (S48_ENTER_BOOLEAN(res));
  64. }
  65. /*
  66. * Glue between Scheme48 types and C types for external call.
  67. * svproc is a byte vector containing the procedure and svargs is a
  68. * vector of arguments.
  69. */
  70. static s48_value
  71. s48_old_external_call(s48_value svproc, s48_value svargv)
  72. {
  73. s48_value (*func)(long, long*);
  74. long *argv,
  75. argc;
  76. func = (s48_value (*)(long, long*))*S48_EXTRACT_VALUE_POINTER(svproc, long);
  77. argc = S48_VECTOR_LENGTH(svargv);
  78. argv = S48_ADDRESS_AFTER_HEADER(svargv, long);
  79. return (func(argc, argv));
  80. }
  81. /*
  82. * Lookup an external name (either in a dynamically loaded library, or
  83. * in the running executable).
  84. * On success we return PSTRUE, having set *(long *)locp to the location.
  85. * On failure, we return PSFALSE.
  86. */
  87. static long
  88. lookup_external_name(char *name, long *locp)
  89. {
  90. struct dlob *dp;
  91. void *res;
  92. static void *self;
  93. for (dp = dlobs; dp != NULL; dp = dp->next) {
  94. res = dlsym(dp->handle, name);
  95. if (dlerror() == NULL) {
  96. *locp = (long)res;
  97. return (PSTRUE);
  98. }
  99. }
  100. if (self == NULL) {
  101. self = dlopen((char *)NULL, DLOPEN_MODE);
  102. if (dlerror() != NULL)
  103. return (PSFALSE);
  104. }
  105. res = dlsym(self, name);
  106. if (dlerror() == NULL) {
  107. *locp = (long)res;
  108. return (PSTRUE);
  109. }
  110. return (PSFALSE);
  111. }
  112. /*
  113. * External to load a library.
  114. * Raises an exception if the file cannot be loaded, or loaded properly.
  115. * Note, if you load the same file a second time, afterwards you must
  116. * evaluate (lookup-all-externals) in package externals to update any
  117. * externals the pointed to the old version of the library.
  118. */
  119. s48_value
  120. s48_dynamic_load(s48_value filename)
  121. {
  122. S48_CHECK_STRING(filename);
  123. if (! dynamic_load(S48_UNSAFE_EXTRACT_BYTE_VECTOR(filename)))
  124. /* the cast below is to remove the const part of the type */
  125. s48_raise_string_os_error((char *)dlerror());
  126. return S48_UNSPECIFIC;
  127. }
  128. static psbool
  129. dynamic_load(char *name)
  130. {
  131. struct dlob **dpp,
  132. *dp;
  133. void *handle;
  134. for (dpp = &dlobs;; dpp = &dp->next) {
  135. dp = *dpp;
  136. if (dp == NULL) {
  137. handle = dlopen(name, DLOPEN_MODE);
  138. if (handle == NULL)
  139. return (PSFALSE);
  140. dp = (struct dlob *)malloc(sizeof(*dp) + strlen(name) + 1);
  141. if (dp == NULL) {
  142. dlclose(handle);
  143. return (PSFALSE);
  144. }
  145. dp->next = dlobs;
  146. dlobs = dp;
  147. dp->name = (char *)(dp + 1);
  148. strcpy(dp->name, name);
  149. dp->handle = handle;
  150. return (PSTRUE);
  151. } else if (strcmp(name, dp->name) == 0) {
  152. dlclose(dp->handle);
  153. dp->handle = dlopen(name, DLOPEN_MODE);
  154. if (dp->handle == NULL) {
  155. *dpp = dp->next;
  156. free((void *)dp);
  157. return (PSFALSE);
  158. }
  159. return (PSTRUE);
  160. }
  161. }
  162. }