dynamo.c 4.2 KB

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