Ifdef-ize the hopscotch hash stuff for non-x86.
[sbcl.git] / src / code / foreign-load.lisp
blobcacf1f9610342e5b7a7b57ace20a68fd855f38c0
1 ;;;; Loading shared object files
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 (in-package "SB!ALIEN")
14 ;;; Used to serialize modifications to *shared-objects*.
15 (defvar *shared-objects-lock*
16 (sb!thread:make-mutex :name "shared object list lock"))
18 (define-unsupported-fun load-foreign
19 "Unsupported as of SBCL 0.8.13. See LOAD-SHARED-OBJECT."
20 "~S is unsupported as of SBCL 0.8.13. See LOAD-SHARED-OBJECT."
21 (load-foreign))
23 (define-unsupported-fun load-1-foreign
24 "Unsupported as of SBCL 0.8.13. Please use LOAD-SHARED-OBJECT."
25 "~S is unsupported as of SBCL 0.8.13. Please use LOAD-SHARED-OBJECT."
26 (load-1-foreign))
28 (define-alien-variable undefined-alien-address unsigned)
29 (defvar *runtime-dlhandle*)
31 (defvar *shared-objects*)
33 (defstruct shared-object pathname namestring handle dont-save)
35 (defun load-shared-object (pathname &key dont-save)
36 "Load a shared library / dynamic shared object file / similar foreign
37 container specified by designated PATHNAME, such as a .so on an ELF platform.
39 Locating the shared object follows standard rules of the platform, consult the
40 manual page for dlopen(3) for details. Typically paths specified by
41 environment variables such as LD_LIBRARY_PATH are searched if the PATHNAME has
42 no directory, but on some systems (eg. Mac OS X) search may happen even if
43 PATHNAME is absolute. (On Windows LoadLibrary is used instead of dlopen(3).)
45 On non-Windows platforms calling LOAD-SHARED-OBJECT again with a PATHNAME
46 EQUAL to the designated pathname of a previous call will replace the old
47 definitions; if a symbol was previously referenced through the object and
48 is not present in the reloaded version an error will be signalled. Reloading
49 may not work as expected if user or library-code has called dlopen(3) on the
50 same shared object.
52 LOAD-SHARED-OBJECT interacts with SB-EXT:SAVE-LISP-AND-DIE:
54 1. If DONT-SAVE is true (default is NIL), the shared object will be dropped
55 when SAVE-LISP-AND-DIE is called -- otherwise shared objects are reloaded
56 automatically when a saved core starts up. Specifying DONT-SAVE can be useful
57 when the location of the shared object on startup is uncertain.
59 2. On most platforms references in compiled code to foreign symbols in shared
60 objects (such as those generated by DEFINE-ALIEN-ROUTINE) remain valid across
61 SAVE-LISP-AND-DIE. On those platforms where this is not supported, a WARNING
62 will be signalled when the core is saved -- this is orthogonal from DONT-SAVE."
63 (let ((pathname (pathname pathname)))
64 (sb!thread:with-mutex (*shared-objects-lock*)
65 (let* ((old (find pathname *shared-objects*
66 :key #'shared-object-pathname
67 :test #'equal))
68 (obj (or old (make-shared-object
69 :pathname pathname
70 :namestring (native-namestring
71 (translate-logical-pathname pathname)
72 :as-file t)))))
73 (setf (shared-object-dont-save obj) dont-save)
74 ;; FIXME: Why doesn's dlopen-or-lose on already loaded stuff work on
75 ;; Windows?
77 ;; Kovalenko 2010-11-24: It would work, but it does nothing
78 ;; useful on Windows: library reference count is increased
79 ;; after each LoadLibrary, making it harder to unload it, and
80 ;; that's all the effect. Also, equal pathnames on Windows
81 ;; always designate _exactly the same library image_; Unix
82 ;; tricks like deleting an open library and replacing it with
83 ;; another version just don't work here.
84 #!-win32
85 (dlopen-or-lose obj)
86 #!+win32
87 (unless old
88 (dlopen-or-lose obj))
89 (setf *shared-objects* (append (remove obj *shared-objects*)
90 (list obj)))
91 ;; FIXME: Why doesn't the linkage table work on Windows? (Or maybe it
92 ;; does and this can be just #!+linkage-table?) Note: remember to change
93 ;; FOREIGN-DEINIT as well then!
95 ;; Kovalenko 2010-11-24: I think so. Alien _data_ references
96 ;; are the only thing on win32 that is even slightly
97 ;; problematic. Handle function references in the same way as
98 ;; other linkage-table platforms is easy.
100 #!+linkage-table
101 (when (or old (undefined-foreign-symbols-p))
102 (update-linkage-table))))
103 pathname))
105 (defun unload-shared-object (pathname)
106 "Unloads the shared object loaded earlier using the designated PATHNAME with
107 LOAD-SHARED-OBJECT, to the degree supported on the platform.
109 Experimental."
110 (let ((pathname (pathname pathname)))
111 (sb!thread:with-mutex (*shared-objects-lock*)
112 (let ((old (find pathname *shared-objects*
113 :key #'shared-object-pathname
114 :test #'equal)))
115 (when old
116 #!-hpux (dlclose-or-lose old)
117 (setf *shared-objects* (remove old *shared-objects*))
118 #!+linkage-table
119 (update-linkage-table))))))
121 (defun try-reopen-shared-object (obj)
122 (declare (type shared-object obj))
123 (tagbody :dlopen
124 (restart-case
125 (dlopen-or-lose obj)
126 (continue ()
127 :report "Skip this shared object and continue."
128 ;; By returning NIL the shared object is dropped from the list.
129 (setf (shared-object-handle obj) nil)
130 (return-from try-reopen-shared-object nil))
131 (retry ()
132 :report "Retry loading this shared object."
133 (go :dlopen))
134 (change-pathname ()
135 :report "Specify a different pathname to load the shared object from."
136 (tagbody :query
137 (format *query-io* "~&Enter pathname (evaluated):~%")
138 (force-output *query-io*)
139 (let ((pathname (ignore-errors (pathname (read *query-io*)))))
140 (unless (pathnamep pathname)
141 (format *query-io* "~&Error: invalid pathname.~%")
142 (go :query))
143 (setf (shared-object-pathname obj) pathname)
144 (setf (shared-object-namestring obj)
145 (native-namestring (translate-logical-pathname pathname)
146 :as-file t))))
147 (go :dlopen))))
148 obj)
150 ;;; Open libraries in *SHARED-OBJECTS* and the runtime. Called during
151 ;;; initialization.
152 (defun reopen-shared-objects ()
153 ;; Ensure that the runtime is open
154 (setf *runtime-dlhandle* (dlopen-or-lose))
155 ;; Without this many symbols aren't accessible.
156 #!+android (load-shared-object "libc.so" :dont-save t)
157 ;; Reopen stuff.
158 (setf *shared-objects*
159 (remove nil (mapcar #'try-reopen-shared-object *shared-objects*))))
161 ;;; Close all dlopened libraries and clear out sap entries in
162 ;;; *SHARED-OBJECTS*, and drop the ones with DONT-SAVE set.
163 (defun close-shared-objects ()
164 (let (saved)
165 (dolist (obj (reverse *shared-objects*))
166 #!-hpux (dlclose-or-lose obj)
167 (unless (shared-object-dont-save obj)
168 (push obj saved)))
169 (setf *shared-objects* saved))
170 #!-hpux
171 (dlclose-or-lose))
173 (let ((symbols (make-hash-table :test #'equal))
174 (undefineds (make-hash-table :test #'equal)))
175 (defun ensure-dynamic-foreign-symbol-address (symbol &optional datap)
176 "Returns the address of the foreign symbol as an integer. On linkage-table
177 ports if the symbols isn't found a special guard address is returned instead,
178 accesses to which will result in an UNDEFINED-ALIEN-ERROR. On other ports an
179 error is immediately signalled if the symbol isn't found. The returned address
180 is never in the linkage-table."
181 (declare (ignorable datap))
182 (let ((addr (find-dynamic-foreign-symbol-address symbol)))
183 (cond #!-linkage-table
184 ((not addr)
185 (error 'undefined-alien-error :name symbol))
186 #!+linkage-table
187 ((not addr)
188 (style-warn 'sb!kernel:undefined-alien-style-warning
189 :symbol symbol)
190 (setf (gethash symbol undefineds) t)
191 (remhash symbol symbols)
192 (if datap
193 undefined-alien-address
195 (gethash 'sb!vm::undefined-alien-tramp sb!fasl:*assembler-routines*)
196 (find-foreign-symbol-address "undefined_alien_function"))))
197 (addr
198 (setf (gethash symbol symbols) t)
199 (remhash symbol undefineds)
200 addr))))
201 (defun undefined-foreign-symbols-p ()
202 (plusp (hash-table-count undefineds)))
203 (defun dynamic-foreign-symbols-p ()
204 (plusp (hash-table-count symbols)))
205 (defun list-dynamic-foreign-symbols ()
206 (loop for symbol being each hash-key in symbols
207 collect symbol))
208 (defun list-undefined-foreign-symbols ()
209 (loop for symbol being each hash-key in undefineds
210 collect symbol)))